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...
連結已複製
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
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
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?
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 :-().
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
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
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
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.
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