Array constructor
When using array constructors with variables in it like arr(:) = (/1.0, a, b/) in an OpenMP loop, the private variable arr sometimes contains random values. Intel's thread checker also reports an "write->write data race" error at this line.
Is the array constructor not thread safe?????
| |
Re: Array constructor
Can you provide a code sample?
Is the arr(:) = (/1.0, a, b/) occuring inside your parallel region (i.e. to each private arr(:))?
Jim Dempsey
Blog: The Parallel Void
www.quickthreadprogramming.com | |
Re: Array constructor
The following test program usually produces errors when running with multiple OpenMP threads. Sometimes it is very hard to get the test failed. Using static arrays, it seems to be more likely that the test passes. However, in any case Intel's thread checker reports "Write->Write data-races" at the line with the array constructor.
program arraytest
! compiled with ifort -openmp arraytest.F90
integer(kind=4), parameter :: n=1000000
integer(kind=4) :: i
real(kind=8), dimension(:,:),allocatable :: data
real(kind=8), dimension(:),allocatable :: arr
allocate(data(3,n))
!$omp parallel private(arr,i) shared(data)
allocate(arr(3))
!$omp do
do i=1,n
arr(:) = (/ real(i,kind=8)**2, real(i,kind=8)**3, 1.0_8 /)
! uncommenting the following lines never produces an error
!arr(1) = real(i,kind=8)**2
!arr(2) = real(i,kind=8)**3
!arr(3) = 1.0_8
data(:,i) = arr(:)
end do
!$omp end do
deallocate(arr)
!$omp end parallel
do i=1,n
if ( data(1,i) /= real(i,kind=8)**2 ) then
print*,'test failed'
print*,real(i,kind=8)**2
print*,data(1,i)
stop
end if
end do
print*,'test passed'
deallocate(data)
end program arraytest
| |
Re: Array constructor
For me, it fails consistently when compiled with debug symbols, no optimization, as recommended for thread checker. It seems it may use a shared temporary in the array constructor. If there is a race in the non-optimized implementation of the array constructor, depending on optimization to keep the values in register and avoid a race may produce results which depend on your compiler version. With a current compiler, with optimization, instead of a race condition, Thread Checker complains about closing of a synchronization object at the final deallocate. This doesn't make much sense to me, particularly as that deallocation would be performed implicitly at the end of the subroutine in any case.
| |
Re: Array constructor
On a whim, try: real(kind=8), automatic, dimension(:), allocatable :: arr
Easy enough to try (add automatic).
Jim Dempsey
Blog: The Parallel Void
www.quickthreadprogramming.com | |
Re: Array constructor
On a whim, try: real(kind=8), automatic, dimension(:), allocatable :: arr
Easy enough to try (add automatic).
Jim Dempsey
The posted code can be changed so as to eliminate arr() entirely, and verify that the problem isn't located there. At first glance, I thought perhaps the private(arr) wasn't working, but that is easily eliminated as a cause of the reported problem. Private clearly requires that each thread gets its own copy of the array, and that can't be influenced by adding the non-standard keyword to the declaration outside the parallel region. If that were so, it would be another bug exposed by this example. My thread checker did complain about both deallocate() violating synchronization objects, but I could move deallocate out of the parallel region without satisfying it.
| |
Re: Array constructor
The point of the automatic on arr being:
Your intentions for arr were to have each thread have a separate copy.
For this to happen, each thread needs a seperate copy of not only the data but also the array descriptor.
Normally, enabling OpenMP, sets subroutines to default to RECURSIVE which makes "stack" declared array descriptors go on stack (as opposed to one static copy of the array descriptor as it does for non-recursive/non-OpenMP subroutines/functions).
Your (intended to be) "stack" array descriptor is declared inside PROGRAM not SUBROUTINE nor FUNCTION.
RECURSIVE is a prefix that can be placed on SUBROUTINE or FUNCTION (not PROGRAM). Therefore, should the compiler write(s) "fixed" OpenMP array descriptor on stack by flipping on RECURSIVE .AND. should RECURSIVE be ignored in PROGRAM, then the array descriptor may get place in static area.
Therefor, on a whim, add AUTOMATIC to the declaration of the arr as an alternate means to force the compiler to place the array descriptor for arr on the stack (as opposed to one static copy).
This is a trivial test for an assumption. Should this not fix the problem, then there is a deeper problem with multi-threaded array constructors. Should this fix the problem then you can raise the issue with Intel.
", automatic" 11 characters to make the test.
Jim Dempsey
Blog: The Parallel Void
www.quickthreadprogramming.com | |
Re: Array constructor
Second alternative to avoid AUTOMATIC
take body of PROGRAM and place in SUBROUTINE FOO, then CALL FOO as only statement in PROGRAM.
If this fixes the problem then this reinforces my assumption about OpenMP using RECURSIVE to force descriptors to stack (.and. recursive not applicable to program). This also provides you with a standard work around while you hash out the issue with Intel as to how OpenMP is to handle array descriptors in PROGRAM.
Jim Dempsey
Blog: The Parallel Void
www.quickthreadprogramming.com | |
Re: Array constructor
And RECURSIVE applies to SUBROUTINE and FUNCTION not (necessarily) PROGRAM. The array descriptor was declared in PROGRAM (not SUBROUTINE and FUNCTION).
It would be interesting if the poster with the problem would ecapsulate the contents of their PROGRAM/END PROGRAM into a subrouting and call it. Thus establishing if the reported constructor problem is in actuality a faux pas w/rt PROGRAM/SUBROUTINE/FUNCTION.
The OpenMP option should force all non-SAVE'd array descriptors on stack by way of a seperate flag (as opposed to riding along implicitly with RECURSIVE).
Jim
Blog: The Parallel Void
www.quickthreadprogramming.com | | |