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

OpenMP: initialize Threadprivate

Allamarein
Beginner
1,095 Views

Dear folks,
let's suppose to have this FORTRAN module:

MODULE MyUtility

IMPLICIT NONE

REAL*8, ALLOACATABLE(:,:) :: r

INTEGER :: i1, i2, i3, i3

REAL*8 :: r1,r2,r3



CONTAINS



SUBROUTINE work(x,y)

REAL*8 :: x,y

REAL*8, SAVE :: a

a = x*y

y = a*x

RETURN

END SUBROUTINE

END MODULE

And let's suppose that, before parallelizing the code:
 

  • Each global variable is initialized before the parallel job

    They are independent inside the job

    ALLOCATABLE variables are allocated and it is not requried to deallocate them or changing their dimensions during the parallel job

    Thea variables with SAVE inside the subroutine is independent inside the parallel job

 

Now, I should use THREADPRIVATE for may module and COPYIN when I launch DO PARALLEL.

My questions are:
 

  • It is possible avoiding to lits one per one the global variables inside the module, but whith a single work invoking the whole module (I am lazy and I don not want copy the global variables one by one) ?

    For the same reason, it is possibile do that in COPYIN clause?

Thanks

0 Kudos
5 Replies
TimP
Honored Contributor III
1,095 Views

When you talk about global variables, some of your words seem to indicate you would be satisfied with SAVE variables local to the module procedures which are shared by all threads, and could be set prior to entering the parallel region.   This should work, provided that they aren't modified inside a parallel region, where it would create a race condition.

Whether the module subroutines could inherit automatically a value from an outside scope (still under the restriction of not modifying within a parallel region) seems more questionable.

Without a clearer example from you, it's hard to speculate.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,095 Views

When using THREADPRIVATE (thread exclusive) global variables, as opposed to passed/stack local variables, these variables have the same "define" requirements as they do for the main thread. Note, upon OpenMP thread creation, there is an implicit COPYIN, or more correctly, "copy to" of the main thread's threadprivate copy of the THREADPRIVATE variables to the thread private variables of the newly created thread. This means that initialization of these (threadprivate) must be performed prior to first parallel region. *** and should you have nested parallel regions, the copyin (copy to) occurs at the time of the first creation of the team for the creating thread's ancestry. This can be problematic if you wish to have an allocatable thread private array, and use nested levels.

Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,095 Views

I am not certain of the nuances of declaring a routine local variable/array both as SAVE and THREADPRIVATE. This should work. However, if after testing you find issues, then create a MODULE for your routine, and declare the threadprivate and persistent data in there.

! foobar.f90
module foobar_mod
real :: YourPersistentArray(12,34)
end module foobar_mod

subroutine foobar(arg)
use foobar_mod
implicit none
real :: arg
...

The module and the routine can reside in the same source file.

You might want to consider adding a foobar_init subroutine.

Alternatively, (more aligned with language) is to place the routines (foobar, foobar_init, etc) into the CONTAINS section of the module.

Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,095 Views

While you are declaring c and b as threadprivate, you are also allocating outside the (a) parallel region. Thus when you later enter the parallel region, the array descriptor is propagated into the thread's copy (of the array descriptor). This causes each thread to have aliased arrays (all threads using same storage for data, different storage for array descriptor). To correct for this use:

...
! Initialize variables in the module
k = 100
ALLOCATE(res(1:k))
!$OMP PARALLEL
! Each thread allocates its own arrays
ALLOCATE(c(1:k,1:k))
ALLOCATE(b(1:k))
!$OMP END PARALLEL
ALLOCATE(isgreat(1:k))
...

*** Note, making b and c threadprivate implies that they intend to hold different data per thread. If you want each thread to have different data then you will (may) also require you initializing them differently within a parallel region (random_seed and random_number).

*** However, your parallel do loop is structured for each thread to reference different slices of c, and this implies the c is common to all threads.

So..... is c really to be shared or common?

Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,095 Views

It seems questionable as to why you have array c as threadprivate. In your parallel region with COPYIN(c) all the threads will have different copies of the master thread's c, then use their private copies with the same values. There is no benefit in having the threadprivate (nor copyin).

Please note, if the threadprivate c arrays were to be different amongst the different threads, then your parallel do loop is slicing up the iteration space (1,k) amongst different threads operating on arrays with different data. This leads to the (different) non-thread's slice of data not being processed.

From my understanding of your parallel loop, b could be private or threadprivate, but c should be shared. I know that this is somewhat sketch code, but in the sketch, b can be eliminated (as well as the copy operation).

x = MAXVAL(c(j,1:k))

I suggest you reserve THREADPRIVATE for when it is a reasonable solution to a programming problem.

Jim Dempsey

0 Kudos
Reply