From 68652a6fb22a388d3e7180ff11fba0d8616f7380 Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Thu, 2 Jan 2025 18:33:21 -0800 Subject: [PATCH 1/7] Add assert external --- install.sh | 3 ++- manifest/fpm.toml.template | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/install.sh b/install.sh index ff5a63739..e98d2b1e2 100755 --- a/install.sh +++ b/install.sh @@ -402,8 +402,9 @@ compiler_version=$($FPM_FC --version) if [[ $compiler_version == *llvm* ]]; then compiler_flag="-mmlir -allow-assumed-rank -g -Ofast" else - compiler_flag="-g -O3" + compiler_flag="-g -O3 -ffree-line-length-0" fi +compiler_flag+=" -DASSERT_PARALLEL_CALLBACKS" RUN_FPM_SH="build/run-fpm.sh" cat << EOF > $RUN_FPM_SH diff --git a/manifest/fpm.toml.template b/manifest/fpm.toml.template index 9ca3133aa..fc3885a10 100644 --- a/manifest/fpm.toml.template +++ b/manifest/fpm.toml.template @@ -6,6 +6,7 @@ maintainer = "rouson@lbl.gov" copyright = "2021-2025 The Regents of the University of California, through Lawrence Berkeley National Laboratory" [dev-dependencies] +assert = {git = "https://github.com/berkeleylab/assert.git", tag = "2.0.1"} veggies = {git = "https://gitlab.com/everythingfunctional/veggies", tag = "v1.1.3"} iso_varying_string = {git = "https://gitlab.com/everythingfunctional/iso_varying_string.git", tag = "v3.0.4"} From 8c4681eee3939598fe9429c3dca9cefd64fe7e34 Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Wed, 8 Jan 2025 17:15:00 -0800 Subject: [PATCH 2/7] Add ASSERT_PARALLEL_CALLBACKS This uses gasnett_fatalerror for process termination, for two reasosn: 1. prif_error_stop is impure and thus cannot be invoked by assert_error_stop 2. gasnett_fatalerror provides a variety of distributed-aware debugging services, such as automated backtracing and debugger attach points --- src/caffeine/caffeine.c | 8 ++++++++ src/caffeine/prif_private_s.f90 | 6 ++++++ src/caffeine/program_startup_s.F90 | 28 ++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/src/caffeine/caffeine.c b/src/caffeine/caffeine.c index 34d5ce9f9..be4c44d22 100644 --- a/src/caffeine/caffeine.c +++ b/src/caffeine/caffeine.c @@ -99,6 +99,14 @@ void caf_decaffeinate(int exit_code) gasnet_exit(exit_code); } +void caf_fatal_error( const CFI_cdesc_t* Fstr ) +{ + const char *msg = (char *)Fstr->base_addr; + int len = Fstr->elem_len; + //printf("%p:%i\n",msg,len); fflush(0); + gasnett_fatalerror_nopos("%.*s", len, msg); +} + void* caf_allocate(mspace heap, size_t bytes) { void* allocated_space = mspace_memalign(heap, 8, bytes); diff --git a/src/caffeine/prif_private_s.f90 b/src/caffeine/prif_private_s.f90 index 75feb66e5..2ad273065 100644 --- a/src/caffeine/prif_private_s.f90 +++ b/src/caffeine/prif_private_s.f90 @@ -40,6 +40,12 @@ subroutine caf_decaffeinate(exit_code) bind(C) integer(c_int), value :: exit_code end subroutine + pure subroutine caf_fatal_error(str) bind(C) + !! void caf_fatal_error( const CFI_cdesc_t* Fstr ) + use iso_c_binding, only : c_char + implicit none + character(kind=c_char,len=:), pointer, intent(in) :: str + end subroutine ! _________________ Image enumeration ____________________ function caf_this_image(gex_team) bind(C) diff --git a/src/caffeine/program_startup_s.F90 b/src/caffeine/program_startup_s.F90 index 230ee90bc..836371989 100644 --- a/src/caffeine/program_startup_s.F90 +++ b/src/caffeine/program_startup_s.F90 @@ -16,6 +16,7 @@ initial_team%heap_size, & non_symmetric_heap_mspace, & initial_team%gex_team) + call assert_init() current_team%info => initial_team initial_team%parent_team => initial_team initial_team%team_number = -1 @@ -26,4 +27,31 @@ end if end procedure +#if ASSERT_PARALLEL_CALLBACKS + subroutine assert_init() + use assert_m + implicit none + assert_this_image => assert_callback_this_image + assert_error_stop => assert_callback_error_stop + end subroutine + pure function assert_callback_this_image() result(this_image_id) + implicit none + integer :: this_image_id + + this_image_id = initial_team%this_image + end function + + pure subroutine assert_callback_error_stop(stop_code_char) + implicit none + character(len=*), intent(in) :: stop_code_char + character(len=:), allocatable, target :: tmp + tmp = stop_code_char + + call caf_fatal_error(tmp) + end subroutine +#else + subroutine assert_init() + end subroutine +#endif + end submodule program_startup_s From 43261dab49775276950081a2537e47ceb86f61be Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Tue, 7 Jan 2025 00:05:04 -0800 Subject: [PATCH 3/7] Force-enable assertions This is a filthy hack that should be replaced with a user-controllable option --- install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/install.sh b/install.sh index e98d2b1e2..b65116be6 100755 --- a/install.sh +++ b/install.sh @@ -405,6 +405,7 @@ else compiler_flag="-g -O3 -ffree-line-length-0" fi compiler_flag+=" -DASSERT_PARALLEL_CALLBACKS" +compiler_flag+=" -DASSERTIONS" RUN_FPM_SH="build/run-fpm.sh" cat << EOF > $RUN_FPM_SH From 942d45582190d71146ed069df1dbcb574d9827bb Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Mon, 13 Jan 2025 19:39:05 -0800 Subject: [PATCH 4/7] Unconditionally set ASSERT_MULTI_IMAGE This ensures we get multi-image assertion capabilities, even for compilers that normally default to single-image (flang-new) --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index b65116be6..f62a62804 100755 --- a/install.sh +++ b/install.sh @@ -404,7 +404,7 @@ if [[ $compiler_version == *llvm* ]]; then else compiler_flag="-g -O3 -ffree-line-length-0" fi -compiler_flag+=" -DASSERT_PARALLEL_CALLBACKS" +compiler_flag+=" -DASSERT_MULTI_IMAGE -DASSERT_PARALLEL_CALLBACKS" compiler_flag+=" -DASSERTIONS" RUN_FPM_SH="build/run-fpm.sh" From 8a9e9a7ea96ec0a87c9ec700e4e62c56433231b1 Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Tue, 7 Jan 2025 00:05:56 -0800 Subject: [PATCH 5/7] Deploy assert library in collectives --- .../{co_max_s.f90 => co_max_s.F90} | 6 ++++- .../{co_min_s.f90 => co_min_s.F90} | 6 ++++- .../{co_reduce_s.f90 => co_reduce_s.F90} | 22 +++++++++++-------- src/caffeine/prif_private_s.f90 | 1 + 4 files changed, 24 insertions(+), 11 deletions(-) rename src/caffeine/collective_subroutines/{co_max_s.f90 => co_max_s.F90} (87%) rename src/caffeine/collective_subroutines/{co_min_s.f90 => co_min_s.F90} (87%) rename src/caffeine/collective_subroutines/{co_reduce_s.f90 => co_reduce_s.F90} (90%) diff --git a/src/caffeine/collective_subroutines/co_max_s.f90 b/src/caffeine/collective_subroutines/co_max_s.F90 similarity index 87% rename from src/caffeine/collective_subroutines/co_max_s.f90 rename to src/caffeine/collective_subroutines/co_max_s.F90 index fc3e562df..540b7441a 100644 --- a/src/caffeine/collective_subroutines/co_max_s.f90 +++ b/src/caffeine/collective_subroutines/co_max_s.F90 @@ -1,7 +1,11 @@ ! Copyright (c), The Regents of the University of California ! Terms of use are as specified in LICENSE.txt + +#include "assert_macros.h" + submodule(prif:prif_private_s) co_max_s use iso_c_binding, only : c_funloc + use assert_m implicit none @@ -24,7 +28,7 @@ function reverse_alphabetize(lhs, rhs) result(last_alphabetically) character(len=*), intent(in) :: lhs, rhs character(len=len(lhs)) :: last_alphabetically - call assert(len(lhs)==len(rhs), "caf_co_max: LHS/RHS length match", lhs//" , "//rhs) + call_assert_diagnose(len(lhs)==len(rhs), "caf_co_max: LHS/RHS length match", lhs//" , "//rhs) last_alphabetically = max(lhs,rhs) end function diff --git a/src/caffeine/collective_subroutines/co_min_s.f90 b/src/caffeine/collective_subroutines/co_min_s.F90 similarity index 87% rename from src/caffeine/collective_subroutines/co_min_s.f90 rename to src/caffeine/collective_subroutines/co_min_s.F90 index c2b4361b3..005386228 100644 --- a/src/caffeine/collective_subroutines/co_min_s.f90 +++ b/src/caffeine/collective_subroutines/co_min_s.F90 @@ -1,7 +1,11 @@ ! Copyright (c), The Regents of the University of California ! Terms of use are as specified in LICENSE.txt + +#include "assert_macros.h" + submodule(prif:prif_private_s) co_min_s use iso_c_binding, only : c_funloc + use assert_m implicit none @@ -24,7 +28,7 @@ function alphabetize(lhs, rhs) result(first_alphabetically) character(len=*), intent(in) :: lhs, rhs character(len=len(lhs)) :: first_alphabetically - call assert(len(lhs)==len(rhs), "prif_co_min: LHS/RHS length match", lhs//" , "//rhs) + call_assert_diagnose(len(lhs)==len(rhs), "prif_co_min: LHS/RHS length match", lhs//" , "//rhs) first_alphabetically = min(lhs,rhs) end function diff --git a/src/caffeine/collective_subroutines/co_reduce_s.f90 b/src/caffeine/collective_subroutines/co_reduce_s.F90 similarity index 90% rename from src/caffeine/collective_subroutines/co_reduce_s.f90 rename to src/caffeine/collective_subroutines/co_reduce_s.F90 index 9f322da7f..b2e971273 100644 --- a/src/caffeine/collective_subroutines/co_reduce_s.f90 +++ b/src/caffeine/collective_subroutines/co_reduce_s.F90 @@ -1,9 +1,13 @@ ! Copyright (c), The Regents of the University of California ! Terms of use are as specified in LICENSE.txt + +#include "assert_macros.h" + submodule(prif:prif_private_s) co_reduce_s use iso_c_binding, only : & c_loc, c_funloc, c_associated, c_f_pointer, c_f_procpointer, c_char, c_double, & c_float, c_int32_t + use assert_m implicit none @@ -83,7 +87,7 @@ pure function c_double_complex_operation(lhs, rhs) result(lhs_op_rhs) procedure(c_double_complex_operation), pointer :: double_complex_op => null() if (present(stat)) stat=0 - call assert(c_associated(operation), "caf_co_reduce: c_associated(operation)") + call_assert_describe(c_associated(operation), "caf_co_reduce: c_associated(operation)") if (caf_same_cfi_type(a, 0)) then call c_f_procpointer(operation, int32_op) @@ -135,7 +139,7 @@ subroutine Coll_ReduceSub_c_int32_t(arg1, arg2_and_out, count, cdata) bind(C) integer(c_int32_t), pointer :: lhs(:)=>null(), rhs_and_result(:)=>null() integer(c_size_t) i - call assert(all([c_associated(arg1), c_associated(arg2_and_out)]), "Coll_ReduceSub_c_int32_t: operands associated") + call_assert_describe(all([c_associated(arg1), c_associated(arg2_and_out)]), "Coll_ReduceSub_c_int32_t: operands associated") call c_f_pointer(arg1, lhs, [count]) call c_f_pointer(arg2_and_out, rhs_and_result, [count]) @@ -153,7 +157,7 @@ subroutine Coll_ReduceSub_c_int64_t(arg1, arg2_and_out, count, cdata) bind(C) integer(c_int64_t), pointer :: lhs(:)=>null(), rhs_and_result(:)=>null() integer(c_size_t) i - call assert(all([c_associated(arg1), c_associated(arg2_and_out)]), "Coll_ReduceSub_c_int64_t: operands associated") + call_assert_describe(all([c_associated(arg1), c_associated(arg2_and_out)]), "Coll_ReduceSub_c_int64_t: operands associated") call c_f_pointer(arg1, lhs, [count]) call c_f_pointer(arg2_and_out, rhs_and_result, [count]) @@ -171,7 +175,7 @@ subroutine Coll_ReduceSub_c_double(arg1, arg2_and_out, count, cdata) bind(C) real(c_double), pointer :: lhs(:)=>null(), rhs_and_result(:)=>null() integer(c_size_t) i - call assert(all([c_associated(arg1), c_associated(arg2_and_out)]), "Coll_ReduceSub_c_double: operands associated") + call_assert_describe(all([c_associated(arg1), c_associated(arg2_and_out)]), "Coll_ReduceSub_c_double: operands associated") call c_f_pointer(arg1, lhs, [count]) call c_f_pointer(arg2_and_out, rhs_and_result, [count]) @@ -189,7 +193,7 @@ subroutine Coll_ReduceSub_c_float(arg1, arg2_and_out, count, cdata) bind(C) real(c_float), pointer :: lhs(:)=>null(), rhs_and_result(:)=>null() integer(c_size_t) i - call assert(all([c_associated(arg1), c_associated(arg2_and_out)]), "Coll_ReduceSub_c_float: operands associated") + call_assert_describe(all([c_associated(arg1), c_associated(arg2_and_out)]), "Coll_ReduceSub_c_float: operands associated") call c_f_pointer(arg1, lhs, [count]) call c_f_pointer(arg2_and_out, rhs_and_result, [count]) @@ -207,7 +211,7 @@ subroutine Coll_ReduceSub_c_double_complex(arg1, arg2_and_out, count, cdata) bin complex(c_double), pointer :: lhs(:)=>null(), rhs_and_result(:)=>null() integer(c_size_t) i - call assert(all([c_associated(arg1), c_associated(arg2_and_out)]), "Coll_ReduceSub_c_dobule_complex: operands associated") + call_assert_describe(all([c_associated(arg1), c_associated(arg2_and_out)]), "Coll_ReduceSub_c_dobule_complex: operands associated") call c_f_pointer(arg1, lhs, [count]) call c_f_pointer(arg2_and_out, rhs_and_result, [count]) @@ -225,7 +229,7 @@ subroutine Coll_ReduceSub_c_float_complex(arg1, arg2_and_out, count, cdata) bind complex(c_float), pointer :: lhs(:)=>null(), rhs_and_result(:)=>null() integer(c_size_t) i - call assert(all([c_associated(arg1), c_associated(arg2_and_out)]), "Coll_ReduceSub_c_float_complex: operands associated") + call_assert_describe(all([c_associated(arg1), c_associated(arg2_and_out)]), "Coll_ReduceSub_c_float_complex: operands associated") call c_f_pointer(arg1, lhs, [count]) call c_f_pointer(arg2_and_out, rhs_and_result, [count]) @@ -243,7 +247,7 @@ subroutine Coll_ReduceSub_c_bool(arg1, arg2_and_out, count, cdata) bind(C) logical(c_bool), pointer :: lhs(:)=>null(), rhs_and_result(:)=>null() integer(c_size_t) i - call assert(all([c_associated(arg1), c_associated(arg2_and_out)]), "Coll_ReduceSub_c_bool: operands associated") + call_assert_describe(all([c_associated(arg1), c_associated(arg2_and_out)]), "Coll_ReduceSub_c_bool: operands associated") call c_f_pointer(arg1, lhs, [count]) call c_f_pointer(arg2_and_out, rhs_and_result, [count]) @@ -262,7 +266,7 @@ subroutine Coll_ReduceSub_c_char(arg1, arg2_and_out, count, cdata) bind(C) integer(c_int), pointer :: arglen=>null() associate(c_associated_args => [c_associated(arg1), c_associated(arg2_and_out), c_associated(cdata)]) - call assert(all(c_associated_args), "Coll_ReduceSub_c_char: all(c_associated_args)") + call_assert_describe(all(c_associated_args), "Coll_ReduceSub_c_char: all(c_associated_args)") end associate call c_f_pointer(cdata, arglen) diff --git a/src/caffeine/prif_private_s.f90 b/src/caffeine/prif_private_s.f90 index 2ad273065..c87f64cec 100644 --- a/src/caffeine/prif_private_s.f90 +++ b/src/caffeine/prif_private_s.f90 @@ -1,6 +1,7 @@ ! Copyright (c), The Regents of the University of California ! Terms of use are as specified in LICENSE.txt submodule(prif) prif_private_s + !use assert_m implicit none type(team_data), target :: initial_team From 80e817d2d16424d1d5da9583b6dff6bef9538ba2 Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Wed, 8 Jan 2025 18:43:44 -0800 Subject: [PATCH 6/7] Remove obsolete caffeine assert stub --- src/caffeine/caffeine_assert_s.F90 | 38 ------------------- .../collective_subroutines/co_max_s.F90 | 1 - .../collective_subroutines/co_min_s.F90 | 1 - .../collective_subroutines/co_reduce_s.F90 | 1 - src/caffeine/prif_private_s.f90 | 9 +---- src/caffeine/program_startup_s.F90 | 1 - 6 files changed, 1 insertion(+), 50 deletions(-) delete mode 100644 src/caffeine/caffeine_assert_s.F90 diff --git a/src/caffeine/caffeine_assert_s.F90 b/src/caffeine/caffeine_assert_s.F90 deleted file mode 100644 index a03839778..000000000 --- a/src/caffeine/caffeine_assert_s.F90 +++ /dev/null @@ -1,38 +0,0 @@ -! Copyright (c), The Regents of the University of California -! Terms of use are as specified in LICENSE.txt -submodule(prif:prif_private_s) caffeine_assert_s - implicit none - -#if CAF_ASSERTIONS || !defined(CAF_ASSERTIONS) - logical, parameter :: assertions_=.true. -#else - logical, parameter :: assertions_=.false. -#endif - - !! Disable assertions by compiling with preprocessor setting: -DCAF_ASSERTIONS=0 - -contains - - module procedure assert - character(len=:), allocatable :: tail - - if (assertions_) then - if (.not. assertion) then - if (.not. present(diagnostics)) then - tail = "." - else - tail = " with diagnostics " - select type(diagnostics) - type is(character(len=*)) - tail = tail // diagnostics - class default - tail = tail // "of unsupported type." - end select - end if - - call prif_error_stop(.false._c_bool, stop_code_char='Assertion "'// description // '" failed' // tail) - end if - end if - end procedure - -end submodule caffeine_assert_s diff --git a/src/caffeine/collective_subroutines/co_max_s.F90 b/src/caffeine/collective_subroutines/co_max_s.F90 index 540b7441a..a99d8d582 100644 --- a/src/caffeine/collective_subroutines/co_max_s.F90 +++ b/src/caffeine/collective_subroutines/co_max_s.F90 @@ -5,7 +5,6 @@ submodule(prif:prif_private_s) co_max_s use iso_c_binding, only : c_funloc - use assert_m implicit none diff --git a/src/caffeine/collective_subroutines/co_min_s.F90 b/src/caffeine/collective_subroutines/co_min_s.F90 index 005386228..b5eea6a22 100644 --- a/src/caffeine/collective_subroutines/co_min_s.F90 +++ b/src/caffeine/collective_subroutines/co_min_s.F90 @@ -5,7 +5,6 @@ submodule(prif:prif_private_s) co_min_s use iso_c_binding, only : c_funloc - use assert_m implicit none diff --git a/src/caffeine/collective_subroutines/co_reduce_s.F90 b/src/caffeine/collective_subroutines/co_reduce_s.F90 index b2e971273..b2d942022 100644 --- a/src/caffeine/collective_subroutines/co_reduce_s.F90 +++ b/src/caffeine/collective_subroutines/co_reduce_s.F90 @@ -7,7 +7,6 @@ use iso_c_binding, only : & c_loc, c_funloc, c_associated, c_f_pointer, c_f_procpointer, c_char, c_double, & c_float, c_int32_t - use assert_m implicit none diff --git a/src/caffeine/prif_private_s.f90 b/src/caffeine/prif_private_s.f90 index c87f64cec..7862c3db6 100644 --- a/src/caffeine/prif_private_s.f90 +++ b/src/caffeine/prif_private_s.f90 @@ -1,7 +1,7 @@ ! Copyright (c), The Regents of the University of California ! Terms of use are as specified in LICENSE.txt submodule(prif) prif_private_s - !use assert_m + use assert_m implicit none type(team_data), target :: initial_team @@ -10,13 +10,6 @@ interface - module subroutine assert(assertion, description, diagnostics) - implicit none - logical, intent(in) :: assertion - character(len=*), intent(in) :: description - class(*), intent(in), optional :: diagnostics - end subroutine - ! ________ Program initiation and finalization ___________ subroutine caf_caffeinate( & diff --git a/src/caffeine/program_startup_s.F90 b/src/caffeine/program_startup_s.F90 index 836371989..a8c932eb2 100644 --- a/src/caffeine/program_startup_s.F90 +++ b/src/caffeine/program_startup_s.F90 @@ -29,7 +29,6 @@ #if ASSERT_PARALLEL_CALLBACKS subroutine assert_init() - use assert_m implicit none assert_this_image => assert_callback_this_image assert_error_stop => assert_callback_error_stop From ab60440031e41791e9c095571fdf2ac6da3a5066 Mon Sep 17 00:00:00 2001 From: Dan Bonachea Date: Tue, 14 Jan 2025 10:22:59 -0800 Subject: [PATCH 7/7] install.sh: Accept Fortran flags from FFLAGS and CPPFLAGS This enables command-line control of assertions, eg: ``` env CPPFLAGS=-DASSERTIONS=0 install.sh ... ``` --- install.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/install.sh b/install.sh index f62a62804..04feec8a3 100755 --- a/install.sh +++ b/install.sh @@ -19,6 +19,7 @@ All unrecognized arguments will be passed to GASNet's configure. Some influential environment variables: FC Fortran compiler command + FFLAGS Fortran compiler flags CC C compiler command CFLAGS C compiler flags CPP C preprocessor @@ -398,6 +399,8 @@ EOF exit_if_pkg_config_pc_file_missing "caffeine" +user_compiler_flags="${CPPFLAGS:-} ${FFLAGS:-}" + compiler_version=$($FPM_FC --version) if [[ $compiler_version == *llvm* ]]; then compiler_flag="-mmlir -allow-assumed-rank -g -Ofast" @@ -405,7 +408,14 @@ else compiler_flag="-g -O3 -ffree-line-length-0" fi compiler_flag+=" -DASSERT_MULTI_IMAGE -DASSERT_PARALLEL_CALLBACKS" -compiler_flag+=" -DASSERTIONS" + +if ! [[ "$user_compiler_flags " =~ -[DU]ASSERTIONS[=\ ] ]] ; then + # default to enabling assertions, unless the command line sets a relevant flag + compiler_flag+=" -DASSERTIONS" +fi + +# Should come last to allow command-line overrides +compiler_flag+=" $user_compiler_flags" RUN_FPM_SH="build/run-fpm.sh" cat << EOF > $RUN_FPM_SH