public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug fortran/108336] New: Repeatable random_numbers with openmp
@ 2023-01-08  8:45 gareth.davies.ga.code at gmail dot com
  2023-01-08  8:56 ` [Bug fortran/108336] " pinskia at gcc dot gnu.org
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: gareth.davies.ga.code at gmail dot com @ 2023-01-08  8:45 UTC (permalink / raw)
  To: gcc-bugs

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

            Bug ID: 108336
           Summary: Repeatable random_numbers with openmp
           Product: gcc
           Version: 11.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: fortran
          Assignee: unassigned at gcc dot gnu.org
          Reporter: gareth.davies.ga.code at gmail dot com
  Target Milestone: ---

The aim is to get repeatable random numbers with openmp. This report was
derived from a discussion including input from gfortran developer Steve Kargl:
https://fortran-lang.discourse.group/t/replicable-monte-carlo-simulation-with-openmp/4972/19

AFAIK the following program should give repeatable random numbers using openmp.
But it doesn't - there are occasional changes in results, suggestive of a race
condition. 


$ gfortran --version
GNU Fortran (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ cat random_number7.f90 
program main
   use omp_lib
   implicit none
   integer :: n1, i, n, nt
   real :: x1, x2
   real, allocatable :: threadval(:)

   n1 = 2

   ! Initialize the master state to a repeatable sequence.
   call random_init(.true., .false.)

   ! Store final random number on each thread
!$omp parallel
   nt = omp_get_num_threads()
!$omp end parallel
   allocate(threadval(nt))
   threadval = -1.0

!$omp parallel private(x1, x2, i), shared(n1, threadval)

   ! Trigger non-master threads to get their unique seed
   if(omp_get_thread_num() /= 0) call random_number(x1)
!$omp barrier
   ! Get some random numbers -- almost repeatable (but not)
!$omp do
   do i = 1, n1
      call random_number(x1)
      call random_number(x2)
   end do
!$omp end do
   ! Store final RN on each thread
   threadval(omp_get_thread_num()+1) = x2 

!$omp end parallel

   print*, minval(threadval), maxval(threadval)
end program

$ gfortran -fopenmp random_number7.f90 -o random_number7
$ for i in {1..10}; do OMP_NUM_THREADS=6 ./random_number7; done
  0.191325366      0.876643896    
  0.191325366      0.480524838    
  0.191325366      0.876643896    
  0.191325366      0.804360509    
  0.191325366      0.804360509    
  0.191325366      0.480524838    
  0.191325366      0.670394361    
  0.191325366      0.804360509    
  0.157898605      0.191325366    
  0.191325366      0.670394361

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

* [Bug fortran/108336] Repeatable random_numbers with openmp
  2023-01-08  8:45 [Bug fortran/108336] New: Repeatable random_numbers with openmp gareth.davies.ga.code at gmail dot com
@ 2023-01-08  8:56 ` pinskia at gcc dot gnu.org
  2023-01-08  9:48 ` gareth.davies.ga.code at gmail dot com
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: pinskia at gcc dot gnu.org @ 2023-01-08  8:56 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #1 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
Most likely there is only one seed per program so the random # generator is
using locks. So the order is dependent on which thread calls the function.

Now having a seed per thread might be a good idea but it does have other kind
of issues. Even initializing it and even Making sure it does not reinitialized
each time a new openmp thread is launched.

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

* [Bug fortran/108336] Repeatable random_numbers with openmp
  2023-01-08  8:45 [Bug fortran/108336] New: Repeatable random_numbers with openmp gareth.davies.ga.code at gmail dot com
  2023-01-08  8:56 ` [Bug fortran/108336] " pinskia at gcc dot gnu.org
@ 2023-01-08  9:48 ` gareth.davies.ga.code at gmail dot com
  2023-01-08 10:28 ` [Bug libfortran/108336] " pinskia at gcc dot gnu.org
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: gareth.davies.ga.code at gmail dot com @ 2023-01-08  9:48 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #2 from Gareth Davies <gareth.davies.ga.code at gmail dot com> ---
(In reply to Andrew Pinski from comment #1)
> Most likely there is only one seed per program so the random # generator is
> using locks. So the order is dependent on which thread calls the function.
> 
> Now having a seed per thread might be a good idea but it does have other
> kind of issues. Even initializing it and even Making sure it does not
> reinitialized each time a new openmp thread is launched.

There is some documentation as to how it's supposed to work here:
https://gcc.gnu.org/onlinedocs/gfortran/RANDOM_005fSEED.html

It sounds like we should be able to get repeated random numbers - even if their
mapping to the threads does vary. Indeed, the results are pretty close to that.

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

* [Bug libfortran/108336] Repeatable random_numbers with openmp
  2023-01-08  8:45 [Bug fortran/108336] New: Repeatable random_numbers with openmp gareth.davies.ga.code at gmail dot com
  2023-01-08  8:56 ` [Bug fortran/108336] " pinskia at gcc dot gnu.org
  2023-01-08  9:48 ` gareth.davies.ga.code at gmail dot com
@ 2023-01-08 10:28 ` pinskia at gcc dot gnu.org
  2023-01-08 20:58 ` anlauf at gcc dot gnu.org
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: pinskia at gcc dot gnu.org @ 2023-01-08 10:28 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #3 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
Yes the race condition is the following:
the order of calling random_number on which thread first.

init_rand_state definitely takes a lock when reading/writing from/to
master_state.

I see no other race condition in the code.
The code is in intrinsics/random.c 

https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libgfortran/intrinsics/random.c;h=b5732e6c25a14359745c5f698c2dd4cab6f3c81f;hb=HEAD

https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libgfortran/intrinsics/random_init.f90;h=c2a6a0db9ee34c968494d1d2692ac4a48097251f;hb=HEAD

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

* [Bug libfortran/108336] Repeatable random_numbers with openmp
  2023-01-08  8:45 [Bug fortran/108336] New: Repeatable random_numbers with openmp gareth.davies.ga.code at gmail dot com
                   ` (2 preceding siblings ...)
  2023-01-08 10:28 ` [Bug libfortran/108336] " pinskia at gcc dot gnu.org
@ 2023-01-08 20:58 ` anlauf at gcc dot gnu.org
  2023-01-08 22:34 ` pinskia at gcc dot gnu.org
  2023-01-08 23:19 ` gareth.davies.ga.code at gmail dot com
  5 siblings, 0 replies; 7+ messages in thread
From: anlauf at gcc dot gnu.org @ 2023-01-08 20:58 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #4 from anlauf at gcc dot gnu.org ---
There is one flaw with the testcase: when OMP_NUM_THREADS > n1,
array elements threadval(n1+1:OMP_NUM_THREADS) are filled with
undefined values.

When I replace the line

   if(omp_get_thread_num() /= 0) call random_number(x1)

by the following loop:

   do i = 1, nt
      if (i > 1 .and. omp_get_thread_num() == i-1) call random_number(x1)
!$omp barrier
   end do

and furthermore do

   print*, minval(threadval(1:n1)), maxval(threadval(1:n1))

I get repeatable results.

Am I missing something?

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

* [Bug libfortran/108336] Repeatable random_numbers with openmp
  2023-01-08  8:45 [Bug fortran/108336] New: Repeatable random_numbers with openmp gareth.davies.ga.code at gmail dot com
                   ` (3 preceding siblings ...)
  2023-01-08 20:58 ` anlauf at gcc dot gnu.org
@ 2023-01-08 22:34 ` pinskia at gcc dot gnu.org
  2023-01-08 23:19 ` gareth.davies.ga.code at gmail dot com
  5 siblings, 0 replies; 7+ messages in thread
From: pinskia at gcc dot gnu.org @ 2023-01-08 22:34 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #5 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
Maybe instead of:

!$omp parallel
   nt = omp_get_num_threads()
!$omp end parallel

Do:
  nt = omp_get_max_threads()

that should improve the situtation of not allocating enough for the array.

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

* [Bug libfortran/108336] Repeatable random_numbers with openmp
  2023-01-08  8:45 [Bug fortran/108336] New: Repeatable random_numbers with openmp gareth.davies.ga.code at gmail dot com
                   ` (4 preceding siblings ...)
  2023-01-08 22:34 ` pinskia at gcc dot gnu.org
@ 2023-01-08 23:19 ` gareth.davies.ga.code at gmail dot com
  5 siblings, 0 replies; 7+ messages in thread
From: gareth.davies.ga.code at gmail dot com @ 2023-01-08 23:19 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #6 from Gareth Davies <gareth.davies.ga.code at gmail dot com> ---
(In reply to anlauf from comment #4)
> There is one flaw with the testcase: when OMP_NUM_THREADS > n1,
> array elements threadval(n1+1:OMP_NUM_THREADS) are filled with
> undefined values.

Yes, my bad in trying to simplify the test case...

We should have n1 >= nt.

> 
> When I replace the line
> 
>    if(omp_get_thread_num() /= 0) call random_number(x1)
> 
> by the following loop:
> 
>    do i = 1, nt
>       if (i > 1 .and. omp_get_thread_num() == i-1) call random_number(x1)
> !$omp barrier
>    end do
> 
> and furthermore do
> 
>    print*, minval(threadval(1:n1)), maxval(threadval(1:n1))
> 
> I get repeatable results.
> 
> Am I missing something?

Thanks, I also get repeatable results with those changes. 

A "weaker" approach to getting deterministic results without forcing a 1:1
mapping of random numbers to threads is to replace:

>    do i = 1, nt
>       if (i > 1 .and. omp_get_thread_num() == i-1) call random_number(x1)
> !$omp barrier
>    end do

with:

!$omp critical
   if(omp_get_thread_num() /= 0 ) call random_number(x1)
!$omp end critical 
!$omp barrier

This is what I was looking for.

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

end of thread, other threads:[~2023-01-08 23:19 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-08  8:45 [Bug fortran/108336] New: Repeatable random_numbers with openmp gareth.davies.ga.code at gmail dot com
2023-01-08  8:56 ` [Bug fortran/108336] " pinskia at gcc dot gnu.org
2023-01-08  9:48 ` gareth.davies.ga.code at gmail dot com
2023-01-08 10:28 ` [Bug libfortran/108336] " pinskia at gcc dot gnu.org
2023-01-08 20:58 ` anlauf at gcc dot gnu.org
2023-01-08 22:34 ` pinskia at gcc dot gnu.org
2023-01-08 23:19 ` gareth.davies.ga.code at gmail dot com

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).