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

OpenMP within module

fah10
New Contributor I
1,024 Views
Hi folks!
I recently updated to Intel Fortran 12. Unfortunately my code does not compile with OpenMP anymore.
The compiler seems to have problems with OpenMP statements in module procedures where the
enclosing parallel region is not in the same module. Example:

[fortran]module modtest
   implicit none
contains

   subroutine myfun(x)
      integer, intent(inout) :: x

      !$omp single
      x = x + 1
      !$omp end single copyprivate(x)
   end subroutine myfun
   
end module modtest

program test
   use modtest
   implicit none

   integer :: a

   !$omp parallel private(a)
   a = 1
   call myfun(a)
   !$omp end parallel

end program test[/fortran]

The Compiler (Version 12.0.2 20110112) aborted with the following error message:
error #7982: Variables in the COPYPRIVATE list must be PRIVATE in the enclosing parallel region.

Putting myfun into the main program, everything works again.
However, such constructs work with Intel Fortran 11.1, gfortran, xlf, etc.

Does anyone know how to solve this problem?

0 Kudos
7 Replies
jimdempseyatthecove
Honored Contributor III
1,024 Views
Your function myfun could be called from anywhere (that includes modtest). This includes from within and without a parallel region. Therefore your use of single is ambiguous with this respect, as well as if called within a parallel region it isambiguous as to which team made the call (i.e. nested levels in effect). The !$omp single must be placed where thread team scope is visible (and unambiguous) to the compiler. Also the copyprivate is meaningless in this context

Did you mean to use !$omp critical instead? critical and atomiccan be use in function/subroutine that has no knowledge of parallel region scope.

Jim Dempsey
0 Kudos
fah10
New Contributor I
1,024 Views
No, I don't think that the use of single is ambiguous (see OpenMP standard):
- "The binding thread set for a single region is the current team. A single region
binds to the innermost enclosing parallel region."
- current team tasks: "All tasks encountered during the execution of the innermost enclosing
parallel region by the threads of the corresponding team. Note that the
implicit tasks constituting the parallel region and any descendant tasks
encountered during the execution of these implicit tasks are included in this
binding task set."
- if the above routine _is not_ called within an explicit parallel region, the innermost enclosing parallel region is the implicit (inactive) parallel region with only one thread, which is automatically generated
- if the above routine _is_ called within an explicit parallel region, this region is the innermost enclosing parallel region

Sure, in the above example, the use of copyprivate is meaningless (as the whole example). In practice, copyprivate is heavily used to share pointers, allocated in a single construct. See appendix A.37 in the current OpenMP standard for examples.

From the OpenMP standard I don't see, why an explicit parallel region must be visible to the compiler in order to use copyprivate. I think the check for the variable used in copyprivate is just too severe. In general, a compiler cannot determine (at compile time) if the variable is really private, it just has to assume that.

Besides, everything worked fine with all available Fortran compilers until now.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,024 Views
In checking the OpenMP 3.0 spec, you are correct about SINGLE being used in the subroutine as posted.

However, it is unnecessary (andinvalid)to have copyprivate inside the subroutine because each thread will enter with a different variable for a.

insert

write(*,*) omp_get_thread_num(), a

following the call to the subroutine wiht the SINGLE.

only one of the threads should print 2, the remainder will print 1

Jim Dempsey
0 Kudos
fah10
New Contributor I
1,024 Views
No, copyprivate is necessary (and valid). The whole purpose of copyprivate that one thread can send the value of his own thread local variable to the other threads (where the variable is again thread local)

Doing your suggestion to print the thread local values of a after the call to the subroutine, every thread will give the same result. Otherwise there would be no need to have copyprivate at all:

[fortran]module modtest
   implicit none
contains
   subroutine myfun(x)
      integer, intent(inout) :: x

      !$omp single
      x = x + 1
      !$omp end single copyprivate(x)
   end subroutine myfun
end module modtest

program test
   use modtest
   use omp_lib
   implicit none

   integer :: a

   !$omp parallel private(a)
   a = 1
   call myfun(a)
   write(*,*) omp_get_thread_num(),a
   !$omp end parallel
end program test
[/fortran]


> gfortran -fopenmp test.F90 && OMP_NUM_THREADS=4 ./a.out
2 2
1 2
0 2
3 2


The only problem is that this program doesn't compile with Intel Fortran in version 12 anymore.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,024 Views
The output you provided, contradicts the (your)premise that the SINGLE in the called subroutine is cognizant of the caller's parallel region. The behavior is as if no parallel region was detected.

The calling argument (a) was private to each thread
Each thread initialized their private copy of a to 1
Each thread called myfun with there private copy of a
The SINGLE was apparently executed by all threads, since all threads report 2 for value of their private copy of a.

Place a break on the x=x+1 in myfun
I will bet you see 4 breaks

If so, this then indicates that SINGLE is not OpenMP 3.0 compliant (as use in your sample program).

The subroutine myfun cannot observe that the caller's arguments are private variables of the same name, and would have no information as to how to copy back to the other threads (of the caller's team) variables of same name. If this function were inlined, then maybe the compiler could make this determination.

Jim Dempsey
0 Kudos
fah10
New Contributor I
1,024 Views
No, the single construct (which is OpenMP compliant) is definitly not exedcuted by all threads. You can easily prove that by the example below. Sure, the compiler cannot check if the variable in the copyprivate was declared private (and the new intel fortran version 12 should not try to check that) but this check is just not necessary.

The mechanism, how the compiler copies private variables to the other threads depends on the implementation, but the compiler has all the information it needs, even without the knowledge of explicit parallel region.


[fortran]module modtest
   use omp_lib
   implicit none
contains
   subroutine myfun(x)
      integer, intent(inout) :: x

      !$omp single
      x = x + 1
      write(*,*) 'This is thread ',omp_get_thread_num()
      !$omp end single copyprivate(x)
   end subroutine myfun
end module modtest

program test
   use modtest
   use omp_lib
   implicit none

   integer :: a

   !$omp parallel private(a)
   a = 1
   call myfun(a)
   write(*,*) omp_get_thread_num(),a
   !$omp end parallel
end program test
[/fortran]

!> gfortran -fopenmp test.F90 && OMP_NUM_THREADS=4 ./a.out
This is thread 3
2 2
1 2
3 2
0 2

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,024 Views
This is a rather interesting example. What it seems to indicate is:

copyprivate(x), which occures at an !$omp end single, and which the !$omp single my be called from within or without a parallel region, must be declaring that the scalar x, which at compile timerepresents a cell inan array, rank 1, of unknown size at compile time, and unknown position within the array, other than the position represents the position within the array for the current thread of the thread team, or the scalar itself in the event the call is made from outside a parallel region.

Example, assume 4 thread team as you exampled above, and thread 3 is the winning thread for the single region.

Thecaller, with !$omp parallel private(a) is apparently creating a 0-basedinteger array of size of thread team. Each thread receives a reference to one of the elements of this array (indexed by thread number within the team) and uses that reference via the alias "a". Each thread calls with a seperate pointer(reference) into this array (at there own private a). Inside myfunc !$omp end single copyprivate(x) says: x is not a dummy variable to a scalar integer, instead it is a dummy reference to a 0-based array of same type (integer) with assumed index of thread team member number. When not called from parallel region this reduces to team member number 0 of a 0-based array with 1 element. Any thread therefore can determin where each of the other threads (or all threads) variables of x are located.

So then, yes, the !$omp single... !$omp end single copyprivate(x) in a subroutine without compile time knowledge of being called from parallel region, or not, can work.

And your error message is erronious (compiler error).

Jim Dempsey
0 Kudos
Reply