Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Array constructor

fah10
New Contributor I
1,266 Views
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?????
0 Kudos
11 Replies
jimdempseyatthecove
Honored Contributor III
1,266 Views

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
0 Kudos
fah10
New Contributor I
1,266 Views
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.

[plain]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[/plain]

0 Kudos
TimP
Honored Contributor III
1,266 Views
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.
0 Kudos
Steven_L_Intel1
Employee
1,266 Views
In some cases, array constructors are indeed not thread-safe. This is a bug in the process of being fixed.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,266 Views

On a whim, try: real(kind=8), automatic, dimension(:), allocatable :: arr

Easy enough to try (add automatic).

Jim Dempsey
0 Kudos
TimP
Honored Contributor III
1,266 Views

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.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,266 Views

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
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,266 Views

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 reinforcesmy 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 tohow OpenMP is to handle array descriptors in PROGRAM.

Jim Dempsey
0 Kudos
Steven_L_Intel1
Employee
1,266 Views
Enabling OpenMP implies -auto (which should be the same as adding RECURSIVE.) The problem is that when the compiler sees an array constructor containing at least one constant, it tends to want to make it static, even when it shouldn't. This will be fixed. The issue ID is DPD200083317.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,266 Views

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 reportedconstructor problem isin actuality a faux pas w/rt PROGRAM/SUBROUTINE/FUNCTION.

The OpenMP option should force all non-SAVE'd array descriptors on stackby way ofa seperate flag (as opposed to riding along implicitly with RECURSIVE).

Jim
0 Kudos
Steven_L_Intel1
Employee
1,266 Views
This should be fixed in 11.1 Update 2.
0 Kudos
Reply