Message ID | 20180108025140.GA14526@troutmask.apl.washington.edu |
---|---|
State | New |
Headers | show |
Series | Implementation of RANDOM_INIT from F2018 | expand |
On Sun, Jan 07, 2018 at 06:52:22PM -0800, Steve Kargl wrote: > > I have zero knowledge about co-arrays and especially zero > knowledge about gfortran internals for co-arrays. I'm > disinclined to waste another 12 hours trying to get gfortran > to emit essentially a call to this_image(). See iresolve.c > for details. > An epiphany came to me last night, which has led to the attach patch. This patch should be a complete implementation of RANDOM_INIT. RANDOM_INIT takes two LOGICAL, INTENT(IN) arguments. To avoid library bloat, these arguments are converted/casted to LOGICAL(4) in trans-intrinsic.c (conv_intrinsic_random_init). It is also in this function, that I set up the hidden argument that is needed to hopefully give standard conforming behavior when co-arrays are involved. I, however, cannot test -fcoarray=lib situation. I would appreciate feedback from a co-array user. Boostrapped and regression tested on x86_64-*-freebsd. OK to commit? 2018-01-08 Steven G. Kargl <kargl@gcc.gnu.org> * check.c (gfc_check_random_init): New function. Check arguments of random_init(). * gfortran.h (gfc_isym_id): Add GFC_ISYM_RANDOM_INIT. * intrinsic.c (add_subroutines): Make random_init() an intrinsic subroutine. (gfc_check_intrinsic_standard): Check for Fortran 2018. * intrinsic.h: Add prototypes for gfc_check_random_init and gfc_resolve_random_init. * iresolve.c (gfc_resolve_random_init): New function. Add _gfortran_random_init to list of subroutines. * trans-decl.c: Describe gfor_fndecl_random_init. * trans-intrinsic.c (conv_intrinsic_random_init): New function. Translate random_init and added hidden argument. (gfc_conv_intrinsic_subroutine): Call conv_intrinsic_random_init. * trans.h: Declare gfor_fndecl_random_init. 2018-01-08 Steven G. Kargl <kargl@gcc.gnu.org> * gfortran.dg/random_init_1.f90: New test. * gfortran.dg/random_init_2.f90: New test. 2018-01-08 Steven G. Kargl <kargl@gcc.gnu.org> * gfortran.map: Add _gfortran_random_init to library map. * intrinsics/random.c (random_init): Implemenation of random_init.
I’ll be glad to test with -fcoarray=lib -lcaf_mpi with two caveats: 1. My turnaround time will probably usually be 48-72 hours for such tests. 2. I don’t monitor this mailing list very closely so I might miss similar requests unless they are also submitted as issues on the OpenCoarrays GitHub repository. For clarification, are you asking for simple execution of the existing tests or do you suspect that the tests might need modification (or new tests) to exercise the -fcoarray=lib option? Damian On January 8, 2018 at 4:58:09 PM, Steve Kargl (sgk@troutmask.apl.washington.edu) wrote: On Sun, Jan 07, 2018 at 06:52:22PM -0800, Steve Kargl wrote: > > I have zero knowledge about co-arrays and especially zero > knowledge about gfortran internals for co-arrays. I'm > disinclined to waste another 12 hours trying to get gfortran > to emit essentially a call to this_image(). See iresolve.c > for details. > An epiphany came to me last night, which has led to the attach patch. This patch should be a complete implementation of RANDOM_INIT. RANDOM_INIT takes two LOGICAL, INTENT(IN) arguments. To avoid library bloat, these arguments are converted/casted to LOGICAL(4) in trans-intrinsic.c (conv_intrinsic_random_init). It is also in this function, that I set up the hidden argument that is needed to hopefully give standard conforming behavior when co-arrays are involved. I, however, cannot test -fcoarray=lib situation. I would appreciate feedback from a co-array user. Boostrapped and regression tested on x86_64-*-freebsd. OK to commit? 2018-01-08 Steven G. Kargl <kargl@gcc.gnu.org> * check.c (gfc_check_random_init): New function. Check arguments of random_init(). * gfortran.h (gfc_isym_id): Add GFC_ISYM_RANDOM_INIT. * intrinsic.c (add_subroutines): Make random_init() an intrinsic subroutine. (gfc_check_intrinsic_standard): Check for Fortran 2018. * intrinsic.h: Add prototypes for gfc_check_random_init and gfc_resolve_random_init. * iresolve.c (gfc_resolve_random_init): New function. Add _gfortran_random_init to list of subroutines. * trans-decl.c: Describe gfor_fndecl_random_init. * trans-intrinsic.c (conv_intrinsic_random_init): New function. Translate random_init and added hidden argument. (gfc_conv_intrinsic_subroutine): Call conv_intrinsic_random_init. * trans.h: Declare gfor_fndecl_random_init. 2018-01-08 Steven G. Kargl <kargl@gcc.gnu.org> * gfortran.dg/random_init_1.f90: New test. * gfortran.dg/random_init_2.f90: New test. 2018-01-08 Steven G. Kargl <kargl@gcc.gnu.org> * gfortran.map: Add _gfortran_random_init to library map. * intrinsics/random.c (random_init): Implemenation of random_init. -- steve
On Mon, Jan 08, 2018 at 05:33:01PM -0800, Damian Rouson wrote: > I’ll be glad to test with -fcoarray=lib -lcaf_mpi with two caveats: > > 1. My turnaround time will probably usually be 48-72 hours for > such tests. Turn around time is unimportant to me. I'm simply interested if what I have done work or if I need to fix a bug. > 2. I don’t monitor this mailing list very closely so I might miss > similar requests unless they are also submitted as issues on the > OpenCoarrays GitHub repository. That's understandable. There is only so much time in a day. > For clarification, are you asking for simple execution of the > existing tests or do you suspect that the tests might need > modification (or new tests) to exercise the -fcoarray=lib option? Hopefully, this clarifies the situation. Suppose, you have a co-array program that causes execution of 2 images, say, image0 and image1. If the program contains call random_init(repeatable=.true., image_distinct=.true.) then image0 and image1 will have distinct PRNG sequences. Now, if you re-run the program, then image0 and image1 will have the same distinct sequences. If you have call random_init(.true., .false.) image0 and image1 do not need to have distinct PRNG sequences, but I set up gfortran to have distinct sequences. If you re-run the program image0 and image1 should have the same sequences. Finally, if you have call random_init(.false.,.true.) image0 and image1 will have distinct sequence, and if you re-run the program image and image1 will should have different sequence than what was seen in the previous and these are distinct. There is one final detail, the standard says that calling random_init in one image cannot affect the PRNG sequence in another image if image_distinct=.false.
On 01/08/2018 04:58 PM, Steve Kargl wrote: > On Sun, Jan 07, 2018 at 06:52:22PM -0800, Steve Kargl wrote: >> >> I have zero knowledge about co-arrays and especially zero >> knowledge about gfortran internals for co-arrays. I'm >> disinclined to waste another 12 hours trying to get gfortran >> to emit essentially a call to this_image(). See iresolve.c >> for details. >> > > An epiphany came to me last night, which has led to the attach > patch. This patch should be a complete implementation of > RANDOM_INIT. > > RANDOM_INIT takes two LOGICAL, INTENT(IN) arguments. To > avoid library bloat, these arguments are converted/casted to > LOGICAL(4) in trans-intrinsic.c (conv_intrinsic_random_init). > It is also in this function, that I set up the hidden argument > that is needed to hopefully give standard conforming behavior > when co-arrays are involved. I, however, cannot test -fcoarray=lib > situation. I would appreciate feedback from a co-array user. > > Boostrapped and regression tested on x86_64-*-freebsd. > OK to commit? > Yes, Looks good Steve. So all we need is a run test with actual =lib case. Jerry
On Mon, Jan 08, 2018 at 06:51:06PM -0800, Jerry DeLisle wrote: > On 01/08/2018 04:58 PM, Steve Kargl wrote: > > On Sun, Jan 07, 2018 at 06:52:22PM -0800, Steve Kargl wrote: > >> > >> I have zero knowledge about co-arrays and especially zero > >> knowledge about gfortran internals for co-arrays. I'm > >> disinclined to waste another 12 hours trying to get gfortran > >> to emit essentially a call to this_image(). See iresolve.c > >> for details. > >> > > > > An epiphany came to me last night, which has led to the attach > > patch. This patch should be a complete implementation of > > RANDOM_INIT. > > > > RANDOM_INIT takes two LOGICAL, INTENT(IN) arguments. To > > avoid library bloat, these arguments are converted/casted to > > LOGICAL(4) in trans-intrinsic.c (conv_intrinsic_random_init). > > It is also in this function, that I set up the hidden argument > > that is needed to hopefully give standard conforming behavior > > when co-arrays are involved. I, however, cannot test -fcoarray=lib > > situation. I would appreciate feedback from a co-array user. > > > > Boostrapped and regression tested on x86_64-*-freebsd. > > OK to commit? > > > > Yes, Looks good Steve. So all we need is a run test with actual =lib case. > Yes. If someone adds this to a program that creates two images, and each image executes foo subroutine foo character(len=10) name real x(2) integer fd write(name,'(A,I0)') 'dat', this_image() call random_init(repeatable=.true., image_distinct=.true.) call random_number(x) open(newunit=fd,file=name) write(fd,*) x close(fd) end program then dat0 and dat1 will contain distinct numbers, and everytime the program executes the new dat0 and new dat1 should match the old dat0 and dat1. If repeatable=.false., then dat0 and dat1 will still be distinct sequences. Repeated execution of the program will cause the new dat0 and new dat1 to not match the old dat0 and old dat1.
On Mon, Jan 08, 2018 at 06:51:06PM -0800, Jerry DeLisle wrote: > On 01/08/2018 04:58 PM, Steve Kargl wrote: > > > > Boostrapped and regression tested on x86_64-*-freebsd. > > OK to commit? > > > > Yes, Looks good Steve. So all we need is a run test with actual =lib case. > Just realized that I forgot to update the documentation. I'll add a RANDOM_INIT section before committing.
Hi Steve, Here are the results of compiling with the OpenCoarrays “caf” compiler wrapper, which uses -fcoarray=lib -lcaf_mpi: 1. random_init(repeatable=.true., image_distinct=.true.) gives repeatable sequences that are distinct on each image. 2. random_init(.true., .false.) gives repeatable sequences that are identical on all images. 3. random_init(.false.,.true.) gives non-repeatable sequences that are distinct on each image. 4. random_init(.false.,.false.) gives non-repeatable sequences that are distinct on each image. The behavior with test 2 differs from the description in the email below. I hope this is helpful. I can provide the raw output if so desired. In case it’s of interest, there’s a script in OpenCoarrays that checks out the trunk, applies a provided patch to it, and then does a non-bootstrap build of the patched trunk, MPICH, and OpenCoarrays. These were my steps: git clone https://github.com/sourceryinstitute/opencoarrays cd opencoarrays ./developer-scripts/patched-trunk-instal.sh random_init.diff source prerequisites/installations/setup.sh caf repeatable-distinct.f90 cafrun -n 4 ./a.out If you decide to try this, please let me know. I can edit the above script to give an option for multithreaded builds to speed things up quite a bit. Damian On January 8, 2018 at 6:03:26 PM, Steve Kargl (sgk@troutmask.apl.washington.edu) wrote: On Mon, Jan 08, 2018 at 05:33:01PM -0800, Damian Rouson wrote: > I’ll be glad to test with -fcoarray=lib -lcaf_mpi with two caveats: > > 1. My turnaround time will probably usually be 48-72 hours for > such tests. Turn around time is unimportant to me. I'm simply interested if what I have done work or if I need to fix a bug. > 2. I don’t monitor this mailing list very closely so I might miss > similar requests unless they are also submitted as issues on the > OpenCoarrays GitHub repository. That's understandable. There is only so much time in a day. > For clarification, are you asking for simple execution of the > existing tests or do you suspect that the tests might need > modification (or new tests) to exercise the -fcoarray=lib option? Hopefully, this clarifies the situation. Suppose, you have a co-array program that causes execution of 2 images, say, image0 and image1. If the program contains call random_init(repeatable=.true., image_distinct=.true.) then image0 and image1 will have distinct PRNG sequences. Now, if you re-run the program, then image0 and image1 will have the same distinct sequences. If you have call random_init(.true., .false.) image0 and image1 do not need to have distinct PRNG sequences, but I set up gfortran to have distinct sequences. If you re-run the program image0 and image1 should have the same sequences. Finally, if you have call random_init(.false.,.true.) image0 and image1 will have distinct sequence, and if you re-run the program image and image1 will should have different sequence than what was seen in the previous and these are distinct. There is one final detail, the standard says that calling random_init in one image cannot affect the PRNG sequence in another image if image_distinct=.false. -- Steve
Index: gcc/fortran/check.c =================================================================== --- gcc/fortran/check.c (revision 256045) +++ gcc/fortran/check.c (working copy) @@ -5671,6 +5671,19 @@ gfc_check_mvbits (gfc_expr *from, gfc_expr *frompos, g bool +gfc_check_random_init (gfc_expr *repeatable, gfc_expr *image_distinct) +{ + if (!type_check (repeatable, 0, BT_LOGICAL)) + return false; + + if (!type_check (image_distinct, 1, BT_LOGICAL)) + return false; + + return true; +} + + +bool gfc_check_random_number (gfc_expr *harvest) { if (!type_check (harvest, 0, BT_REAL)) Index: gcc/fortran/expr.c =================================================================== --- gcc/fortran/expr.c (revision 256045) +++ gcc/fortran/expr.c (working copy) @@ -3853,7 +3853,7 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr * /* Error for assignments of contiguous pointers to targets which is not contiguous. Be lenient in the definition of what counts as - congiguous. */ + contiguous. */ if (lhs_attr.contiguous && !gfc_is_simply_contiguous (rvalue, false, true)) gfc_error ("Assignment to contiguous pointer from non-contiguous " Index: gcc/fortran/gfortran.h =================================================================== --- gcc/fortran/gfortran.h (revision 256045) +++ gcc/fortran/gfortran.h (working copy) @@ -551,6 +551,7 @@ enum gfc_isym_id GFC_ISYM_PRODUCT, GFC_ISYM_RADIX, GFC_ISYM_RAND, + GFC_ISYM_RANDOM_INIT, GFC_ISYM_RANDOM_NUMBER, GFC_ISYM_RANDOM_SEED, GFC_ISYM_RANGE, Index: gcc/fortran/intrinsic.c =================================================================== --- gcc/fortran/intrinsic.c (revision 256045) +++ gcc/fortran/intrinsic.c (working copy) @@ -3549,6 +3549,12 @@ add_subroutines (void) make_alias ("kmvbits", GFC_STD_GNU); } + add_sym_2s ("random_init", GFC_ISYM_RANDOM_INIT, CLASS_IMPURE, + BT_UNKNOWN, 0, GFC_STD_F2018, + gfc_check_random_init, NULL, gfc_resolve_random_init, + "repeatable", BT_LOGICAL, dl, REQUIRED, INTENT_IN, + "image_distinct", BT_LOGICAL, dl, REQUIRED, INTENT_IN); + add_sym_1s ("random_number", GFC_ISYM_RANDOM_NUMBER, CLASS_IMPURE, BT_UNKNOWN, 0, GFC_STD_F95, gfc_check_random_number, NULL, gfc_resolve_random_number, @@ -4601,6 +4607,10 @@ gfc_check_intrinsic_standard (const gfc_intrinsic_sym* case GFC_STD_F2008_TS: symstd_msg = "new in TS 29113/TS 18508"; + break; + + case GFC_STD_F2018: + symstd_msg = "new in Fortran 2018"; break; case GFC_STD_GNU: Index: gcc/fortran/intrinsic.h =================================================================== --- gcc/fortran/intrinsic.h (revision 256045) +++ gcc/fortran/intrinsic.h (working copy) @@ -203,6 +203,7 @@ bool gfc_check_getlog (gfc_expr *); bool gfc_check_move_alloc (gfc_expr *, gfc_expr *); bool gfc_check_mvbits (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +bool gfc_check_random_init (gfc_expr *, gfc_expr *); bool gfc_check_random_number (gfc_expr *); bool gfc_check_random_seed (gfc_expr *, gfc_expr *, gfc_expr *); bool gfc_check_dtime_etime_sub (gfc_expr *, gfc_expr *); @@ -643,6 +644,7 @@ void gfc_resolve_lstat_sub (gfc_code *); void gfc_resolve_ltime (gfc_code *); void gfc_resolve_mvbits (gfc_code *); void gfc_resolve_perror (gfc_code *); +void gfc_resolve_random_init (gfc_code *); void gfc_resolve_random_number (gfc_code *); void gfc_resolve_random_seed (gfc_code *); void gfc_resolve_rename_sub (gfc_code *); Index: gcc/fortran/iresolve.c =================================================================== --- gcc/fortran/iresolve.c (revision 256045) +++ gcc/fortran/iresolve.c (working copy) @@ -35,7 +35,9 @@ along with GCC; see the file COPYING3. If not see #include "intrinsic.h" #include "constructor.h" #include "arith.h" +#include "tm.h" /* For flag_coarray. */ + /* Given printf-like arguments, return a stable version of the result string. We already have a working, optimized string hashing table in the form of @@ -3118,6 +3120,8 @@ gfc_resolve_trim (gfc_expr *f, gfc_expr *string) { f->ts.type = BT_CHARACTER; f->ts.kind = string->ts.kind; + f->ts.u.cl = NULL; + f->ts.u.pad = 0; f->value.function.name = gfc_get_string ("__trim_%d", string->ts.kind); } @@ -3368,6 +3372,61 @@ gfc_resolve_mvbits (gfc_code *c) /* Create a dummy formal arglist so the INTENTs are known later for purpose of creating temporaries. */ c->resolved_sym->formal = create_formal_for_intents (c->ext.actual, INTENTS); +} + + +/* Set up the call to RANDOM_INIT. To deal with image_distinct, we need to + send a hidden argument into the library function. For program that don't + use co-arrays or uses -fcoarray=single, the hidden argument is set to 0. + For -fcoarray=lib, the hidden argument should be set to the value + returned by this_image(). Using R for REPEATABLE and I for + IMAGE_DISTINCT. So, RANDOM_INIT(R, I) is mapped to the library routine + _gfortran_random_init(R, I, 0) for a single image, and it should be + mapped to _gfortran_random_init(R, I, this_image()). */ + +void +gfc_resolve_random_init (gfc_code *c) +{ + gfc_actual_arglist *a; + const char *name; + + name = gfc_get_string (PREFIX ("random_init")); + c->resolved_sym = gfc_get_intrinsic_sub_symbol (name); + + /* Pass a hidden integer to deal with seeding images for coarrays. */ + a = gfc_get_actual_arglist (); + if (flag_coarray != GFC_FCOARRAY_LIB) + { + a->expr = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind, + &c->ext.actual->next->expr->where); + mpz_set_si (a->expr->value.integer, 0); + } + else + { + gfc_fatal_error ("RANDOM_INIT with co-arrays is broken!"); +#if 0 +/* Well, this didn't work. :( */ + static const char name[] = "this_image"; + a->expr = gfc_get_expr (); + a->expr->expr_type = EXPR_FUNCTION; + a->expr->ts.type = BT_INTEGER; + a->expr->ts.kind = gfc_default_integer_kind; + a->expr->where = gfc_current_locus; + a->expr->value.function.isym = gfc_find_function (name); + a->expr->value.function.name = a->expr->value.function.isym->name; + + a->expr->value.function.actual = gfc_get_actual_arglist (); + a->expr->value.function.actual->next = gfc_get_actual_arglist (); + a->expr->value.function.actual->next->next = gfc_get_actual_arglist (); + a->expr->value.function.isym->formal->actual = gfc_get_actual_arglist (); + a->expr->value.function.isym->formal->actual->next = gfc_get_actual_arglist (); + a->expr->value.function.isym->formal->actual->next->next = gfc_get_actual_arglist (); + + gfc_simplify_expr (a->expr, 0); + c->resolved_isym->formal->actual->next->next = a; +#endif + } + c->ext.actual->next->next = a; } Index: libgfortran/gfortran.map =================================================================== --- libgfortran/gfortran.map (revision 256045) +++ libgfortran/gfortran.map (working copy) @@ -801,6 +801,7 @@ GFORTRAN_8 { _gfortran_product_r4; _gfortran_product_r8; _gfortran_rand; + _gfortran_random_init; _gfortran_random_r10; _gfortran_random_r16; _gfortran_random_r4; Index: libgfortran/intrinsics/random.c =================================================================== --- libgfortran/intrinsics/random.c (revision 256045) +++ libgfortran/intrinsics/random.c (working copy) @@ -44,6 +44,9 @@ see the files COPYING3 and COPYING.RUNTIME respectivel #include <_mingw.h> /* For __MINGW64_VERSION_MAJOR */ #endif +extern void random_init (GFC_LOGICAL_4 *, GFC_LOGICAL_4 *, GFC_INTEGER_4 *); +iexport_proto(random_init); + extern void random_r4 (GFC_REAL_4 *); iexport_proto(random_r4); @@ -205,7 +208,6 @@ static uint64_t master_state[] = { 0x625288bc262faf33ULL }; - static __gthread_key_t rand_state_key; static xorshift1024star_state* @@ -927,6 +929,46 @@ random_seed_i8 (GFC_INTEGER_8 *size, gfc_array_i8 *put } iexport(random_seed_i8); + +/* random_init is used to seed the PRNG with either a default + set of seeds or a random set of seeds. */ + +void +random_init (GFC_LOGICAL_4 *repeatable, GFC_LOGICAL_4 *image_distinct, + GFC_INTEGER_4 *hidden) +{ + static const uint64_t repeat_state[] = { + 0x25b946ebc0b36173ULL, 0x31fffb768dfde2d1ULL, 0xb08dbf28a70a6b08ULL, + 0x60b1fc7fbcc04151ULL, 0xb4018862d654635dULL, 0x5c2fc35553bb5470ULL, + 0xd588f951b8984a2bULL, 0x060c05384e97789dULL, 0x2b992ddfa23249d6ULL, + 0x4034650f1c98bd69ULL, 0x79267e9c00e018afULL, 0x449eb881a2869d0eULL, + 0xe2fee08d1e670313ULL, 0x17afc3eef0f0c640ULL, 0x2002db4f8acb8a0eULL, + 0x50cd06b1b61a6804ULL + }; + + xorshift1024star_state* rs = get_rand_state(); + + __gthread_mutex_lock (&random_lock); + + if (*repeatable) + { + /* Copy the repeat seeds. */ + memcpy (&rs->s, repeat_state, sizeof (repeat_state)); + njumps = 0; + if (*image_distinct) njumps = *hidden; + master_init = true; + init_rand_state (rs, true); + rs->p = 0; + } + else + { + master_init = false; + init_rand_state (rs, true); + } + + __gthread_mutex_unlock (&random_lock); +} +iexport(random_init); #if !defined __GTHREAD_MUTEX_INIT || defined __GTHREADS static void __attribute__((constructor))