Intel® Moderncode for Parallel Architectures
Support for developing parallel programming applications on Intel® Architecture.
1696 Discussions

Allocation of shared abstract data types with OpenMP

Massimiliano_Culpo
672 Views
Hi,

I am trying to allocate a field that is part of an abstract data type within an OpenMP parallel region. To do the job I am calling an initialization subroutine defined in the same module. I encounter the following behavior:

  • if the variable is declared private then the field appears to be allocated both inside the module and after the call to the initialization subroutine in the main program
  • if the variable is declared shared the field is allocated within the module, but IS NOT allocated after the call to the initialization subroutine in the main program
Notice that I cannot reproduce the same behavior if the allocatable array is not part of a structure. A minimal example showing this behavior is given by the two files below:

dummy.f90
03-allocatable.f90

I am quite a newbie of OpenMP so I was wondering if this is the behavior I should expect. In this case how I can initialize a shared variable of this kind?

M.

0 Kudos
7 Replies
jimdempseyatthecove
Honored Contributor III
672 Views

Try inserting flush between barrier and single

!$omp barrier

!$omp flush(struct, pstruct)
!$omp single

Jim Dempsey
0 Kudos
Massimiliano_Culpo
672 Views
Many thanks for the kind answer.

Anyhow: I did try to use the "flush" directive already, and that does not seem to work in my case. Furthermore I found in:

https://computing.llnl.gov/tutorials/openMP/#FLUSH

that the flush directive should be implied after an "end single" directive, and this also does not seem to be the case for me.


Just to be clear I attach a modified version of the simple example provided above with "flush" inserted:

[bash]program main
  
  use dummy
  use omp_lib
  
  type(pippo)          :: struct,pstruct
  integer              :: tid,nthreads
  real(8), allocatable :: vect(:)

  !$omp parallel default(shared) private(tid,ntrheads,pstruct)
  tid      = omp_get_thread_num()
  nthreads = omp_get_num_threads()
  
  !$omp critical
  print *,tid,nthreads
  call initstruct(pstruct)
  !$omp end critical
  
  !$omp barrier

  !$omp flush(struct,pstruct)

  !$omp single  
  print *
  call initstruct(struct )
  call initvec(vect)
  !$omp flush(struct,pstruct)
  print *
  print *,allocated(struct%vec),tid,nthreads
  print *,allocated(vect),tid,nthreads
  print *
  if (allocated(struct%vec)) then 
     call freestruct(struct)
  end if
  if (allocated(vect)) then 
     deallocate(vect)
  end if
  !$omp end single

  !$omp flush(struct)
  print *,allocated(struct%vec),tid,nthreads  
  print *,allocated(pstruct%vec),tid,nthreads
  if (allocated(pstruct%vec)) then  
     call freestruct(pstruct)
  end if  
  !$omp end parallel

end program main[/bash]


these are the instructions I use to compile the code:

  • ifort -c dummy.f90 -module ./
  • ifort -o 03-allocatable.bin -openmp 03-allocatable.f90 *.o -module ./
and finally, this is the output I have on screen (3 threads):

2 3
T initstruct
0 3
T initstruct
1 3
T initstruct

T initstruct
T initvec

F 0 3
T 0 3

F 2 3
T 2 3
F 0 3
T 0 3
F 1 3
T 1 3


It seems to me that despite the flush directives, the array struct%vec is not allocated on exit to the module procedure.

Furthermore this is the output of valgrind at the end of the procedure:

==4682== LEAK SUMMARY:
==4682== definitely lost: 80 bytes in 1 blocks
==4682== indirectly lost: 0 bytes in 0 blocks
==4682== possibly lost: 416 bytes in 2 blocks
==4682== still reachable: 20 bytes in 1 blocks
==4682== suppressed: 0 bytes in 0 blocks
==4682== Reachable blocks (those to which a pointer was found) are not shown.
==4682== To see them, rerun with: --leak-check=full --show-reachable=yes

Some part of memory appears to be lost, and I my impression is that it is possibly the shared abstract data-type.

Any clue to shed some light on this behavior?

0 Kudos
jimdempseyatthecove
Honored Contributor III
672 Views
Remove the (all) flush,

Add barrier following end of single.

The threads not taking single path are performing print prior to allocation by thread in single.

Jim Dempsey
0 Kudos
Massimiliano_Culpo
672 Views
I tried that, but I got the same output as before. Notice that even the thread executing the single statement sees the abstract data-type as not allocated.

Just a quick question: isn't a barrier already implied by an "end single" directive?
0 Kudos
jimdempseyatthecove
Honored Contributor III
672 Views
Strange,

Try

!$omp single default(shared)
...

If for some reason !$omp single is using (creating)private copies, then you would see this behavior.

I do not know about your second question (IOW consult the documentation). I suppose if it did, you could add nowait to permit non-barrier usage.

Jim Dempsey
0 Kudos
Massimiliano_Culpo
672 Views
I tried that, and it produced (as expected) a failure during compile-time, as the "default(shared)" attribute was already declared at the beginning of the parallel section.

M.
0 Kudos
jimdempseyatthecove
Honored Contributor III
672 Views
I tried that, and it produced (as expected) a failure during compile-time, as the "default(shared)" attribute was already declared at the beginning of the parallel section.

M.

M,

The point of trying !$omp single default(shared) was to investigate why the allocation appeared to be private within the scope of the single. Your next step is to determine if indeed the array descriptor is private or shared. For this you may need to insert a subroutine call to a C++ routine that passes an assumed shape array (descriptor), then simply print out the address of the array descriptor.

If the array discriptor is shared, then the problem lies in deallocation of what is thought to be an autoallocated array or subroutine local allocated array, which in newer fortran is autodeallocated. Note, allocation to (dummy arg) pointershould not be auto-deallocated

Jim Dempsey

0 Kudos
Reply