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

OpenMP with associate - define private?

Johannes_Rieke
新貢獻者 III
2,018 檢視

Hi, I like to parallize a loop with OpenMP. For better readability I further like to use associate within this loop. In a minimum working example this looks like:

program OMP_associate
  use iso_fortran_env, only : compiler_version
  implicit none
  
  integer :: i, i_dummy(73), i_array(42,73)
  
  
  write(*,'("OMP with associate test")')
  write(*,'("Compiler version: ",a)') compiler_version()
  
  i_array = 73
  
  !$OMP parallel do private(i, i_dummy)  
  ! !$OMP parallel do private(i, i_dummy, i_ass) ! this is not accepted, because i_ass is not defined, has no type
  do i = 1, size(i_array,dim=2)
    associate (i_ass => i_array(:,i)) ! this causes a race condition, because i_ass is not declared as private
      
    ! do something
    i_dummy(i) = sum(i_ass)
    end associate
  end do
  !$OMP end parallel do
  
  write(*,'(*(i8))') i_dummy  

end program OMP_associate

The code compiles with this option fine (PSXE 2020 initial, aka 19.1.0, Windows OS):

/nologo /debug:full /Od /Qopenmp-offload /Qopenmp /warn:all /debug-parameters:used /module:"x64\Debug\\" /object:"x64\Debug\\" /Fd"x64\Debug\vc150.pdb" /traceback /check:all /libs:static /threads /dbglibs /c

At run time it fails in line 25 with multiple threads because i_ass is not private and i_dummy contains garbadge. Single threaded works fine.

OMP with associate test
Compiler version: Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 19.1.0.166 Build 20191121
********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
forrtl: error (63): output conversion error, unit -1, file CONOUT$
Image              PC                Routine            Line        Source
OMP_associate.exe  00007FF601019564  Unknown               Unknown  Unknown
OMP_associate.exe  00007FF601016683  Unknown               Unknown  Unknown
OMP_associate.exe  00007FF601013771  Unknown               Unknown  Unknown
OMP_associate.exe  00007FF60101133E  MAIN__                     25  OMP_associate.f90
OMP_associate.exe  00007FF6010AA47E  Unknown               Unknown  Unknown
OMP_associate.exe  00007FF6010AB194  Unknown               Unknown  Unknown
OMP_associate.exe  00007FF6010AB0BE  Unknown               Unknown  Unknown
OMP_associate.exe  00007FF6010AAF7E  Unknown               Unknown  Unknown
OMP_associate.exe  00007FF6010AB209  Unknown               Unknown  Unknown
KERNEL32.DLL       00007FFAD5A637E4  Unknown               Unknown  Unknown
ntdll.dll          00007FFAD85BCB81  Unknown               Unknown  Unknown

Is there a way to get the pointer associated to a variable private without using an explicitly defined pointer/target construct? Otherwise I would use a local copy...

0 積分
10 回應
jimdempseyatthecove
榮譽貢獻者 III
2,018 檢視

Try:

!$omp ...
do I=...
  block
    associate(i_ass=>...
  end block
end do
!$omp end...

or

program OMP_associate
  use iso_fortran_env, only : compiler_version
  implicit none
  
  integer :: i, i_dummy(73)         ! *** remove i_array
  integer, target :: i_array(42,73) ! *** add i_array with TARGET attribute
  integer, pointer :: i_ass (:,:)      ! *** add pointer to rank 2 array         
  
  write(*,'("OMP with associate test")')
  write(*,'("Compiler version: ",a)') compiler_version()
  
  i_array = 73
  
!$OMP parallel do private(i, i_dummy, i_ass) ! *** now declare pointer as private
  do i = 1, size(i_array,dim=2)
    associate (i_ass => i_array(:,i))      
    ! do something
    i_dummy(i) = sum(i_ass)
    end associate
  end do
  !$OMP end parallel do
  
  write(*,'(*(i8))') i_dummy  

end program OMP_associate

Jim Dempsey

 

Johannes_Rieke
新貢獻者 III
2,018 檢視

Hi Jim, thanks for your reply.

The second solution I've tried to avoid, because in my application I would have to assign many class components as targets. In your above second suggestion in line 7 it must say integer,pointer::i_ass(:), because of rank 1. Then it works fine.

However, I found a coding error of mine in the original code: In line 13 i_dummy must not be listed in the OMP private definition. Removing it, the original code runs fine although i_ass is not defined as private explicitly.

!$OMP parallel do private(i,i_dummy) !change to private(i)

The first solution of Jim would require to nest the associate within a block. Wasn't there recently a thread, where this causes problems (compiler implementation not standard)?

Are locally defined variables in blocks always treated as private in an OMP section?

Finally is this - automatically OMP private - valid for assoiated variables, too?

BR, Johannes

Johannes_Rieke
新貢獻者 III
2,018 檢視

UPDATE: What works fine in this simple example, fails in my complex application. I'll try to nail it down, but I'm highly suspicious for using associate within an OMP section for now. Using a block around it, fails in a different way.

While I'm working on a reproducer, has anyone knowledge, whether associate can be savely used within an OMP section? Does the standard mention something?

Mark_Lewy
傑出貢獻者 I
1,925 檢視

I've only just noticed this thread, but have encountered this problem too.

The OpenMP and Fortran standards are not explicit on what happens to an associate name inside an OpenMP parallel do loop and, as you note, you can't specify an associate name in a private clause.

I noticed data races in some OpenMP loops with associate blocks in 18.0.3 and 19.0.5; my work-around was to either use a local pointer or variable instead.  Another way to avoid this would be to refactor your loop body into a separate subroutine.

I thought I had reported this to Intel Support, but it doesn't look as if I have (probably couldn't find time to create a small reproducer near release time :-().

jimdempseyatthecove
榮譽貢獻者 III
1,917 檢視

IMHO

The associate-name should be defined in the context of the associate context of the thread encountering the associate. IOW, the associate name need not, and in fact shall not be referenced in an OMP directive. However, the current OpenMP implementation appears to require specification on DEFAULT(NONE)?

Note, as to if the selector of the associate-name is private or shared, this would depend on if the =>selector were the same or different amongst threads in the parallel region.

Jim Dempsey

Mark_Lewy
傑出貢獻者 I
1,913 檢視

Thanks Jim,

I think I agree with what you have said.  My interpretation of OpenMP 5.1 is that it requires the selector to be specified for default(none), but still makes no mention of associate-name.  I'm tempted to post a question on the OpenMP forum to see if there is a definitive answer.

My view is also that the associate-name should be treated as private to the thread, but my experience of current versions of Intel Fortran suggest this is not the case.

I also wonder whether it's worth me creating a small reproduce for Intel Support?

Mark

 

 

jimdempseyatthecove
榮譽貢獻者 III
1,909 檢視

I think the OpenMP forum is the better place. If you get an authoritative answer to this, that conflicts with the implementation, it will carry more weight to affect a change.

Jim Dempsey

jimdempseyatthecove
榮譽貢獻者 III
2,018 檢視

You may also consider passing the array slice to a contained procedure (or external procedure) that is called by each thread.

Jim Dempsey

Johannes_Rieke
新貢獻者 III
2,018 檢視

Hi Jim, yes that would be an idea.

I now figured out, what went wrong. In my application I made a similar mistake as in the original example. I put an array defined and allocated outside the OMP section into the private list. This caused some wierd errors and was misleading me to associated pointer. Once I got an array bounds error of a variable with the associated pointer, then an access violation in libiomp5md.dll and thirdly an error while deallocating a complete other variable - all with only slightly changing the order of some lines. I suggest that by the OMP private statement local copies have been made and that these could not be correctly finalized in OMP lib/during compilation. For sure a mistake of my own.

I wonder, if it would be possible to make the compiler identifying this error and give the user a warning?

Nevertheless, the question, whether an ASSOCIATE statement can be savely used within an OMP section, is still open. It seems to work with the Intel compiler, but might not with other compilers.

jimdempseyatthecove
榮譽貢獻者 III
2,018 檢視

For allocatable arrays that are not allocated outside the parallel region, that are to be allocated (and deallocated) within the parallel region, use FIRSTPRIVATE as opposed to PRIVATE. I know for a fact that at least older versions of the compiler used to result in the (supposed) unallocated array descriptor initially containing junk inside the parallel region. I am not sure if this was corrected. The use of FIRSTPRIVATE copies in the unallocated state of the array descriptor.

Jim Dempsey

回覆