public inbox for fortran@gcc.gnu.org
 help / color / mirror / Atom feed
* Possible problems with OpenMP task parallelism
@ 2023-06-29  0:01 Andrew Benson
  2023-07-04 15:23 ` Andrew Benson
  0 siblings, 1 reply; 2+ messages in thread
From: Andrew Benson @ 2023-06-29  0:01 UTC (permalink / raw)
  To: gfortran

I've been starting to try using OpenMP task parallelism, but I'm running into 
some issues. I'm not sufficiently experienced with task parallelism in OpenMP 
to know if I'm misunderstanding how it should work, or if there's a compiler 
bug. 

Here's an example code (highly simplified from the actual code I'm working 
on):

module taskerMod

   type :: tasker
      integer :: depth=-1
    contains
      final     ::            taskerDestruct
      procedure :: compute => taskerCompute
   end type tasker

 contains

   subroutine taskerDestruct(self)
     !$ use :: OMP_Lib                                                                                                                                                                                                             
     implicit none
     type(tasker), intent(inout) :: self

     write (0,*) "DESTRUCT FROM DEPTH ",self%depth !$ ," : 
",omp_get_thread_num()                                                                                                                                                  
     return
   end subroutine taskerDestruct

   recursive subroutine taskerCompute(self)
     !$ use :: OMP_Lib                                                                                                                                                                                                             
     implicit none
     class(tasker), intent(inout) :: self

     !$omp atomic
     self%depth=self%depth+1
     write (0,*) "DEPTH ",self%depth !$ ," : ",omp_get_thread_num()                                                                                                                                                                
     if (self%depth < 3) then
        !$omp task untied                                                                                                                                                                                                          
        call self%compute()
        !$omp end task                                                                                                                                                                                                             
     end if
     return
   end subroutine taskerCompute

 end module taskerMod

 program testTasks
   use :: taskerMod
   implicit none
   type(tasker) :: tasker_

   tasker_=tasker(0)
   !$omp parallel                                                                                                                                                                                                                  
   !$omp single                                                                                                                                                                                                                    
   !$omp taskgroup                                                                                                                                                                                                                 
   !$omp task untied                                                                                                                                                                                                               
   call tasker_%compute()
   !$omp end task                                                                                                                                                                                                                  
   !$omp end taskgroup                                                                                                                                                                                                             
   !$omp end single                                                                                                                                                                                                                
   !$omp end parallel                                                                                                                                                                                                              
 end program testTasks

Compiling without OpenMP results in the expected behavior:
$ gfortran test.F90
$ ./a.out
 DESTRUCT FROM DEPTH           -1
 DEPTH            1
 DEPTH            2
 DEPTH            3

There's a call to the finalizer for the tasker class (on assignment), and then 
it simply reports the 3 levels of recursion that I've set it to go through.

But, if I compile with OpenMP and run just a single thread (the same problem 
occurs with multiple threads also):
$ gfortran test.F90 -fopenmp
$ ./a.out
 DESTRUCT FROM DEPTH           -1
 DEPTH            1
 DEPTH            2
 DESTRUCT FROM DEPTH            2
 DEPTH            3
 DESTRUCT FROM DEPTH            3

I now see calls to the finalizer from the 2nd and 3rd recursive calls to the 
taskerCompute function. Since self is intent(inout) to this function I 
wouldn't expect it to be finalized. But, this is where I doubt my 
understanding of how tasks should behave.

This happens with versions 12.0.0, 13.0.1, and the current HEAD of the GCC git 
repo. But, ifort, does not produce the extra finalizer calls when used to 
compile the above with OpenMP.

Does anyone have any insights into whether or not the finalizer should be 
called in this situation?

Another issue I find with a modified version of the above:

module taskerMod

   type :: helper
   end type helper

   type :: tasker
      integer :: depth=-1
    contains
      final     ::            taskerDestruct
      procedure :: compute => taskerCompute
   end type tasker

 contains

   subroutine taskerDestruct(self)
     !$ use :: OMP_Lib                                                                                                                                                                                                             
     implicit none
     type(tasker), intent(inout) :: self

     write (0,*) "DESTRUCT FROM DEPTH ",self%depth !$ ," : 
",omp_get_thread_num()                                                                                                                                                  
     return
   end subroutine taskerDestruct

   recursive subroutine taskerCompute(self,helper_)
     !$ use :: OMP_Lib                                                                                                                                                                                                             
     implicit none
     class(tasker), intent(inout)           :: self
     class(helper), intent(inout), optional :: helper_

     !$omp atomic                                                                                                                                                                                                                  
     self%depth=self%depth+1
     write (0,*) "DEPTH ",self%depth !$ ," : ",omp_get_thread_num()                                                                                                                                                                
     if (self%depth < 3) then
        !$omp task untied                                                                                                                                                                                                          
        call self%compute(helper_)
        !$omp end task                                                                                                                                                                                                             
     end if
     return
   end subroutine taskerCompute

 end module taskerMod

 program testTasks
   use :: taskerMod
   implicit none
   type(tasker) :: tasker_
   type(helper) :: helper_

   tasker_=tasker(0)
   !$omp parallel                                                                                                                                                                                                                  
   !$omp single                                                                                                                                                                                                                    
   !$omp taskgroup                                                                                                                                                                                                                 
   !$omp task untied                                                                                                                                                                                                               
   call tasker_%compute()
   !$omp end task                                                                                                                                                                                                                  
   !$omp end taskgroup                                                                                                                                                                                                             
   !$omp end single                                                                                                                                                                                                                
   !$omp end parallel                                                                                                                                                                                                              
 end program testTasks

This one causes a segfault:
$ gfortran test1.F90  -fopenmp
$ ./a.out
 DESTRUCT FROM DEPTH           -1
 DEPTH            1

Program received signal SIGSEGV: Segmentation fault - invalid memory 
reference.

Backtrace for this error:
#0  0x2ac99289a1ef in ???
#1  0x401840 in ???
#2  0x2ac9925a9606 in GOMP_task
        at ../../../gcc-git/libgomp/task.c:644
#3  0x401588 in ???
#4  0x40197b in ???
#5  0x2ac9925a77a4 in gomp_barrier_handle_tasks
        at ../../../gcc-git/libgomp/task.c:1650
#6  0x2ac9925b058f in gomp_team_barrier_wait_end
        at ../../../gcc-git/libgomp/config/linux/bar.c:116
#7  0x2ac9925aeffc in gomp_team_end
        at ../../../gcc-git/libgomp/team.c:956
#8  0x401692 in ???
#9  0x4016cd in ???
#10  0x2ac992886d0c in ???
#11  0x401128 in ???
Segmentation fault

This appears to be due to the optional argument, helper_. If it is present in 
the initial call, i.e.:
   call tasker_%compute(helper_)

then this runs without a segfault.

-Andrew

-- 

* Andrew Benson: https://abensonca.github.io

* Galacticus: https://github.com/galacticusorg/galacticus




^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Possible problems with OpenMP task parallelism
  2023-06-29  0:01 Possible problems with OpenMP task parallelism Andrew Benson
@ 2023-07-04 15:23 ` Andrew Benson
  0 siblings, 0 replies; 2+ messages in thread
From: Andrew Benson @ 2023-07-04 15:23 UTC (permalink / raw)
  To: gfortran; +Cc: Andrew Benson

[-- Attachment #1: Type: text/plain, Size: 6070 bytes --]

I've opened PRs for both of these issues:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110547

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110548

-Andrew


--

* Andrew Benson: http://users.obs.carnegiescience.edu/abenson

* Galacticus: https://github.com/galacticusorg/galacticus

On Wed, Jun 28, 2023, 5:01 PM Andrew Benson <abenson@carnegiescience.edu>
wrote:

> I've been starting to try using OpenMP task parallelism, but I'm running
> into
> some issues. I'm not sufficiently experienced with task parallelism in
> OpenMP
> to know if I'm misunderstanding how it should work, or if there's a
> compiler
> bug.
>
> Here's an example code (highly simplified from the actual code I'm working
> on):
>
> module taskerMod
>
>    type :: tasker
>       integer :: depth=-1
>     contains
>       final     ::            taskerDestruct
>       procedure :: compute => taskerCompute
>    end type tasker
>
>  contains
>
>    subroutine taskerDestruct(self)
>      !$ use :: OMP_Lib
>
>
>
>      implicit none
>      type(tasker), intent(inout) :: self
>
>      write (0,*) "DESTRUCT FROM DEPTH ",self%depth !$ ," :
> ",omp_get_thread_num()
>
>
>      return
>    end subroutine taskerDestruct
>
>    recursive subroutine taskerCompute(self)
>      !$ use :: OMP_Lib
>
>
>
>      implicit none
>      class(tasker), intent(inout) :: self
>
>      !$omp atomic
>      self%depth=self%depth+1
>      write (0,*) "DEPTH ",self%depth !$ ," : ",omp_get_thread_num()
>
>
>      if (self%depth < 3) then
>         !$omp task untied
>
>
>         call self%compute()
>         !$omp end task
>
>
>
>      end if
>      return
>    end subroutine taskerCompute
>
>  end module taskerMod
>
>  program testTasks
>    use :: taskerMod
>    implicit none
>    type(tasker) :: tasker_
>
>    tasker_=tasker(0)
>    !$omp parallel
>
>
>    !$omp single
>
>
>    !$omp taskgroup
>
>
>
>    !$omp task untied
>
>
>
>    call tasker_%compute()
>    !$omp end task
>
>
>    !$omp end taskgroup
>
>
>
>    !$omp end single
>
>
>    !$omp end parallel
>
>
>  end program testTasks
>
> Compiling without OpenMP results in the expected behavior:
> $ gfortran test.F90
> $ ./a.out
>  DESTRUCT FROM DEPTH           -1
>  DEPTH            1
>  DEPTH            2
>  DEPTH            3
>
> There's a call to the finalizer for the tasker class (on assignment), and
> then
> it simply reports the 3 levels of recursion that I've set it to go through.
>
> But, if I compile with OpenMP and run just a single thread (the same
> problem
> occurs with multiple threads also):
> $ gfortran test.F90 -fopenmp
> $ ./a.out
>  DESTRUCT FROM DEPTH           -1
>  DEPTH            1
>  DEPTH            2
>  DESTRUCT FROM DEPTH            2
>  DEPTH            3
>  DESTRUCT FROM DEPTH            3
>
> I now see calls to the finalizer from the 2nd and 3rd recursive calls to
> the
> taskerCompute function. Since self is intent(inout) to this function I
> wouldn't expect it to be finalized. But, this is where I doubt my
> understanding of how tasks should behave.
>
> This happens with versions 12.0.0, 13.0.1, and the current HEAD of the GCC
> git
> repo. But, ifort, does not produce the extra finalizer calls when used to
> compile the above with OpenMP.
>
> Does anyone have any insights into whether or not the finalizer should be
> called in this situation?
>
> Another issue I find with a modified version of the above:
>
> module taskerMod
>
>    type :: helper
>    end type helper
>
>    type :: tasker
>       integer :: depth=-1
>     contains
>       final     ::            taskerDestruct
>       procedure :: compute => taskerCompute
>    end type tasker
>
>  contains
>
>    subroutine taskerDestruct(self)
>      !$ use :: OMP_Lib
>
>
>
>      implicit none
>      type(tasker), intent(inout) :: self
>
>      write (0,*) "DESTRUCT FROM DEPTH ",self%depth !$ ," :
> ",omp_get_thread_num()
>
>
>      return
>    end subroutine taskerDestruct
>
>    recursive subroutine taskerCompute(self,helper_)
>      !$ use :: OMP_Lib
>
>
>
>      implicit none
>      class(tasker), intent(inout)           :: self
>      class(helper), intent(inout), optional :: helper_
>
>      !$omp atomic
>
>
>      self%depth=self%depth+1
>      write (0,*) "DEPTH ",self%depth !$ ," : ",omp_get_thread_num()
>
>
>      if (self%depth < 3) then
>         !$omp task untied
>
>
>         call self%compute(helper_)
>         !$omp end task
>
>
>
>      end if
>      return
>    end subroutine taskerCompute
>
>  end module taskerMod
>
>  program testTasks
>    use :: taskerMod
>    implicit none
>    type(tasker) :: tasker_
>    type(helper) :: helper_
>
>    tasker_=tasker(0)
>    !$omp parallel
>
>
>    !$omp single
>
>
>    !$omp taskgroup
>
>
>
>    !$omp task untied
>
>
>
>    call tasker_%compute()
>    !$omp end task
>
>
>    !$omp end taskgroup
>
>
>
>    !$omp end single
>
>
>    !$omp end parallel
>
>
>  end program testTasks
>
> This one causes a segfault:
> $ gfortran test1.F90  -fopenmp
> $ ./a.out
>  DESTRUCT FROM DEPTH           -1
>  DEPTH            1
>
> Program received signal SIGSEGV: Segmentation fault - invalid memory
> reference.
>
> Backtrace for this error:
> #0  0x2ac99289a1ef in ???
> #1  0x401840 in ???
> #2  0x2ac9925a9606 in GOMP_task
>         at ../../../gcc-git/libgomp/task.c:644
> #3  0x401588 in ???
> #4  0x40197b in ???
> #5  0x2ac9925a77a4 in gomp_barrier_handle_tasks
>         at ../../../gcc-git/libgomp/task.c:1650
> #6  0x2ac9925b058f in gomp_team_barrier_wait_end
>         at ../../../gcc-git/libgomp/config/linux/bar.c:116
> #7  0x2ac9925aeffc in gomp_team_end
>         at ../../../gcc-git/libgomp/team.c:956
> #8  0x401692 in ???
> #9  0x4016cd in ???
> #10  0x2ac992886d0c in ???
> #11  0x401128 in ???
> Segmentation fault
>
> This appears to be due to the optional argument, helper_. If it is present
> in
> the initial call, i.e.:
>    call tasker_%compute(helper_)
>
> then this runs without a segfault.
>
> -Andrew
>
> --
>
> * Andrew Benson: https://abensonca.github.io
>
> * Galacticus: https://github.com/galacticusorg/galacticus
>
>
>
>

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2023-07-04 15:23 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-29  0:01 Possible problems with OpenMP task parallelism Andrew Benson
2023-07-04 15:23 ` Andrew Benson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).