From b05562296d3486cbd3afb8332e048e956339780e Mon Sep 17 00:00:00 2001 From: Brian Homerding Date: Tue, 6 Jun 2023 19:17:22 +0000 Subject: [PATCH 001/193] Add new reduction api SYCL support, incorrect results for MIN --- include/RAJA/pattern/launch/launch_core.hpp | 2 +- include/RAJA/pattern/params/forall.hpp | 1 + include/RAJA/pattern/params/reducer.hpp | 6 +- include/RAJA/policy/sycl/MemUtils_SYCL.hpp | 70 ++++++++++++ include/RAJA/policy/sycl/forall.hpp | 106 ++++++++++++++++-- include/RAJA/policy/sycl/params/reduce.hpp | 45 ++++++++ include/RAJA/policy/sycl/policy.hpp | 2 +- scripts/alcf-builds/sycl.sh | 2 +- .../forall/reduce-basic/CMakeLists.txt | 12 +- 9 files changed, 229 insertions(+), 17 deletions(-) create mode 100644 include/RAJA/policy/sycl/params/reduce.hpp diff --git a/include/RAJA/pattern/launch/launch_core.hpp b/include/RAJA/pattern/launch/launch_core.hpp index 67c3c50e21..d65f2c071c 100644 --- a/include/RAJA/pattern/launch/launch_core.hpp +++ b/include/RAJA/pattern/launch/launch_core.hpp @@ -202,7 +202,7 @@ class LaunchContext void teamSync() { #if defined(RAJA_GPU_DEVICE_COMPILE_PASS_ACTIVE) && defined(RAJA_ENABLE_SYCL) - itm->barrier(sycl::access::fence_space::local_space); + itm->barrier(::sycl::access::fence_space::local_space); #endif #if defined(RAJA_GPU_DEVICE_COMPILE_PASS_ACTIVE) && !defined(RAJA_ENABLE_SYCL) diff --git a/include/RAJA/pattern/params/forall.hpp b/include/RAJA/pattern/params/forall.hpp index 499b442cc5..4236794a29 100644 --- a/include/RAJA/pattern/params/forall.hpp +++ b/include/RAJA/pattern/params/forall.hpp @@ -8,6 +8,7 @@ #include "RAJA/policy/cuda/params/reduce.hpp" #include "RAJA/policy/cuda/params/kernel_name.hpp" #include "RAJA/policy/hip/params/reduce.hpp" +#include "RAJA/policy/sycl/params/reduce.hpp" #include "RAJA/util/CombiningAdapter.hpp" diff --git a/include/RAJA/pattern/params/reducer.hpp b/include/RAJA/pattern/params/reducer.hpp index d094a729c1..7499268bf3 100644 --- a/include/RAJA/pattern/params/reducer.hpp +++ b/include/RAJA/pattern/params/reducer.hpp @@ -8,6 +8,8 @@ #include "RAJA/policy/cuda/MemUtils_CUDA.hpp" #elif defined(RAJA_HIP_ACTIVE) #include "RAJA/policy/hip/MemUtils_HIP.hpp" +#elif defined(RAJA_SYCL_ACTIVE) +#include "RAJA/policy/sycl/MemUtils_SYCL.hpp" #endif namespace RAJA @@ -74,6 +76,8 @@ namespace detail using device_mem_pool_t = RAJA::cuda::device_mempool_type; #elif defined(RAJA_HIP_ACTIVE) using device_mem_pool_t = RAJA::hip::device_mempool_type; +#elif defined(RAJA_SYCL_ACTIVE) + using device_mem_pool_t = RAJA::sycl::device_mempool_type; #endif // @@ -92,7 +96,7 @@ namespace detail value_type *target = nullptr; value_type val = op::identity(); -#if defined(RAJA_CUDA_ACTIVE) || defined(RAJA_HIP_ACTIVE) +#if defined(RAJA_CUDA_ACTIVE) || defined(RAJA_HIP_ACTIVE) || defined(RAJA_SYCL_ACTIVE) // Device related attributes. value_type * devicetarget = nullptr; RAJA::detail::SoAPtr device_mem; diff --git a/include/RAJA/policy/sycl/MemUtils_SYCL.hpp b/include/RAJA/policy/sycl/MemUtils_SYCL.hpp index 484a3c85ec..f7b4aa01f4 100644 --- a/include/RAJA/policy/sycl/MemUtils_SYCL.hpp +++ b/include/RAJA/policy/sycl/MemUtils_SYCL.hpp @@ -70,6 +70,76 @@ cl::sycl::queue* getQueue(); } // namespace detail +//! Allocator for pinned memory for use in basic_mempool +struct PinnedAllocator { + + // returns a valid pointer on success, nullptr on failure + void* malloc(size_t nbytes) + { + void* ptr; + ::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); + ptr = ::sycl::malloc_host(nbytes, *q); + return ptr; + } + + // returns true on success, false on failure + bool free(void* ptr) + { + ::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); + ::sycl::free(ptr, *q); + return true; + } +}; + +//! Allocator for device memory for use in basic_mempool +struct DeviceAllocator { + + // returns a valid pointer on success, nullptr on failure + void* malloc(size_t nbytes) + { + void* ptr; + ::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); + ptr = ::sycl::malloc_device(nbytes, *q); + return ptr; + } + + // returns true on success, false on failure + bool free(void* ptr) + { + ::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); + ::sycl::free(ptr, *q); + return true; + } +}; + +//! Allocator for pre-zeroed device memory for use in basic_mempool +// Note: Memory must be zero when returned to mempool +struct DeviceZeroedAllocator { + + // returns a valid pointer on success, nullptr on failure + void* malloc(size_t nbytes) + { + void* ptr; + ::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); + ptr = ::sycl::malloc_device(nbytes, *q); + q->memset(ptr, 0, nbytes); + return ptr; + } + + // returns true on success, false on failure + bool free(void* ptr) + { + ::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); + ::sycl::free(ptr, *q); + return true; + } +}; + +using device_mempool_type = basic_mempool::MemPool; +using device_zeroed_mempool_type = + basic_mempool::MemPool; +using pinned_mempool_type = basic_mempool::MemPool; + } // namespace sycl } // namespace RAJA diff --git a/include/RAJA/policy/sycl/forall.hpp b/include/RAJA/policy/sycl/forall.hpp index 2d708b7b83..6c3646dabd 100644 --- a/include/RAJA/policy/sycl/forall.hpp +++ b/include/RAJA/policy/sycl/forall.hpp @@ -32,6 +32,8 @@ #include "RAJA/pattern/forall.hpp" +#include "RAJA/pattern/params/forall.hpp" + #include "RAJA/util/macros.hpp" #include "RAJA/util/types.hpp" @@ -84,11 +86,16 @@ cl::sycl::range<1> getGridDim(size_t len, size_t block_size) template {},bool>::type = true> -RAJA_INLINE resources::EventProxy forall_impl(resources::Sycl &sycl_res, - sycl_exec, - Iterable&& iter, - LoopBody&& loop_body, - ForallParam) +RAJA_INLINE +concepts::enable_if_t< + resources::EventProxy, + RAJA::expt::type_traits::is_ForallParamPack, + RAJA::expt::type_traits::is_ForallParamPack_empty> +forall_impl(resources::Sycl &sycl_res, + sycl_exec, + Iterable&& iter, + LoopBody&& loop_body, + ForallParam) { using Iterator = camp::decay; @@ -141,11 +148,12 @@ RAJA_INLINE resources::EventProxy forall_impl(resources::Sycl template {},bool>::type = true> -RAJA_INLINE resources::EventProxy forall_impl(resources::Sycl &sycl_res, - sycl_exec, - Iterable&& iter, - LoopBody&& loop_body, - ForallParam) +RAJA_INLINE +resources::EventProxy forall_impl(resources::Sycl &sycl_res, + sycl_exec, + Iterable&& iter, + LoopBody&& loop_body, + ForallParam) { using Iterator = camp::decay; using LOOP_BODY = camp::decay; @@ -210,11 +218,85 @@ RAJA_INLINE resources::EventProxy forall_impl(resources::Sycl & RAJA_FT_END; } - - return resources::EventProxy(sycl_res); } +template {},bool>::type = true> +RAJA_INLINE +concepts::enable_if_t< + resources::EventProxy, + RAJA::expt::type_traits::is_ForallParamPack, + concepts::negate> > +forall_impl(resources::Sycl &sycl_res, + sycl_exec, + Iterable&& iter, + LoopBody&& loop_body, + ForallParam f_params) + +{ + using Iterator = camp::decay; + using LOOP_BODY = camp::decay; + using IndexType = camp::decay; + using EXEC_POL = RAJA::sycl_exec; + // + // Compute the requested iteration space size + // + Iterator begin = std::begin(iter); + Iterator end = std::end(iter); + IndexType len = std::distance(begin, end); + + RAJA::expt::ParamMultiplexer::init(f_params); + + // Only launch kernel if we have something to iterate over + if (len > 0 && BlockSize > 0) { + // + // Compute the number of blocks + // + sycl_dim_t blockSize{BlockSize}; + sycl_dim_t gridSize = impl::getGridDim(static_cast(len), BlockSize); + + cl::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); + // Global resource was not set, use the resource that was passed to forall + // Determine if the default SYCL res is being used + if (!q) { + q = sycl_res.get_queue(); + } + + auto combiner = []( ForallParam x, ForallParam y ) { + RAJA::expt::ParamMultiplexer::combine( x, y ); + return x; + }; + + ForallParam* res = ::sycl::malloc_shared(1,*q); + auto reduction = ::sycl::reduction(res, f_params, combiner); + auto prop = ::sycl::property::reduction::initialize_to_identity(); + + q->submit([&](cl::sycl::handler& h) { + h.parallel_for( cl::sycl::range<1>(len), + reduction, + [=] (cl::sycl::item<1> it, auto & red) { + + ForallParam fp; + RAJA::expt::ParamMultiplexer::init(fp); + IndexType ii = it.get_id(0); + if (ii < len) { + RAJA::expt::invoke_body(fp, loop_body, begin[ii]); + } + red.combine(fp); + }); + }); + + if (!Async) { q->wait(); } + q->wait(); + RAJA::expt::ParamMultiplexer::combine( f_params, *res ); + ::sycl::free(res, *q); + } + RAJA::expt::ParamMultiplexer::resolve(f_params); + + return resources::EventProxy(sycl_res); + +} // ////////////////////////////////////////////////////////////////////// diff --git a/include/RAJA/policy/sycl/params/reduce.hpp b/include/RAJA/policy/sycl/params/reduce.hpp new file mode 100644 index 0000000000..33f544f770 --- /dev/null +++ b/include/RAJA/policy/sycl/params/reduce.hpp @@ -0,0 +1,45 @@ +#ifndef NEW_REDUCE_SYCL_REDUCE_HPP +#define NEW_REDUCE_SYCL_REDUCE_HPP + +#include "RAJA/pattern/params/reducer.hpp" + +namespace RAJA { +namespace expt { +namespace detail { + +#if defined(RAJA_ENABLE_SYCL) + + // Init + template + camp::concepts::enable_if< type_traits::is_sycl_policy > + init(Reducer& red) { +// std::cout << "BRIAN: setting to " << OP::identity() << '\n'; + red.val = OP::identity(); + } + + // Combine + template + camp::concepts::enable_if< type_traits::is_sycl_policy > + SYCL_EXTERNAL + combine(Reducer& out, const Reducer& in) { +// std::cout << "BRIAN: combining " << out.val << " with " << in.val << '\n'; + out.val = OP{}(out.val, in.val); +// out.val = OP{}(in.val); + } + + // Resolve + template + camp::concepts::enable_if< type_traits::is_sycl_policy > + resolve(Reducer& red) { + + std::cout << "BRIAN: resolving " << red.val << " with " << *red.target << '\n'; + *red.target = OP{}(red.val, *red.target); + } + +#endif + +} // namespace detail +} // namespace expt +} // namespace RAJA + +#endif // NEW_REDUCE_SYCL_REDUCE_HPP diff --git a/include/RAJA/policy/sycl/policy.hpp b/include/RAJA/policy/sycl/policy.hpp index 98631ad8a6..41f3d2343c 100644 --- a/include/RAJA/policy/sycl/policy.hpp +++ b/include/RAJA/policy/sycl/policy.hpp @@ -68,7 +68,7 @@ namespace sycl // ////////////////////////////////////////////////////////////////////// -template +template struct sycl_exec : public RAJA::make_policy_pattern_launch_platform_t< RAJA::Policy::sycl, RAJA::Pattern::forall, diff --git a/scripts/alcf-builds/sycl.sh b/scripts/alcf-builds/sycl.sh index ed5c6fa4bd..e6020f44b1 100755 --- a/scripts/alcf-builds/sycl.sh +++ b/scripts/alcf-builds/sycl.sh @@ -36,7 +36,7 @@ cmake \ -DCMAKE_LINKER=clang++ \ -DCMAKE_CXX_STANDARD=17 \ -DBLT_CXX_STD=c++17 \ - -DENABLE_TESTS=Off \ + -DENABLE_TESTS=On \ -DENABLE_EXAMPLES=On \ "$@" \ .. diff --git a/test/functional/forall/reduce-basic/CMakeLists.txt b/test/functional/forall/reduce-basic/CMakeLists.txt index 316c710b11..34ee40a25f 100644 --- a/test/functional/forall/reduce-basic/CMakeLists.txt +++ b/test/functional/forall/reduce-basic/CMakeLists.txt @@ -28,7 +28,8 @@ endif() # expt-reduce tests. # if(RAJA_ENABLE_SYCL) - list(REMOVE_ITEM FORALL_BACKENDS Sycl) + list(REMOVE_ITEM REDUCETYPES ReduceMaxLoc) + list(REMOVE_ITEM REDUCETYPES ReduceMinLoc) endif() @@ -59,6 +60,15 @@ set(REDUCETYPES ReduceBitAnd ReduceBitOr) set(DATATYPES BitwiseReductionDataTypeList) +# +# If building SYCL tests, remove the back-end from +# from the list of tests to generate here for the +# expt-reduce tests. + +if(RAJA_ENABLE_SYCL) + list(REMOVE_ITEM FORALL_BACKENDS Sycl) +endif() + # # Generate bitwise reduction tests for each enabled RAJA back-end # From af30b0508ea69de79765f4e97ac8afc956711553 Mon Sep 17 00:00:00 2001 From: Brian Homerding Date: Mon, 19 Jun 2023 14:22:13 +0000 Subject: [PATCH 002/193] Fix reduction object initialization for Sycl --- include/RAJA/policy/sycl/forall.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/RAJA/policy/sycl/forall.hpp b/include/RAJA/policy/sycl/forall.hpp index 6c3646dabd..75ea8b42af 100644 --- a/include/RAJA/policy/sycl/forall.hpp +++ b/include/RAJA/policy/sycl/forall.hpp @@ -269,8 +269,8 @@ forall_impl(resources::Sycl &sycl_res, }; ForallParam* res = ::sycl::malloc_shared(1,*q); + RAJA::expt::ParamMultiplexer::init(*res); auto reduction = ::sycl::reduction(res, f_params, combiner); - auto prop = ::sycl::property::reduction::initialize_to_identity(); q->submit([&](cl::sycl::handler& h) { h.parallel_for( cl::sycl::range<1>(len), From abc45e0d38d0e7533d222a0ba15ff777b94a66a9 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Thu, 22 Jun 2023 17:21:33 +0200 Subject: [PATCH 003/193] Update rocmcc --- .gitlab-ci.yml | 4 ++-- .gitlab/corona-build-and-test-extra.yml | 4 ++-- .gitlab/tioga-build-and-test-extra.yml | 8 ++++---- scripts/radiuss-spack-configs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8ba8c96d8e..ed02a9b5a1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -59,7 +59,7 @@ stages: include: - local: '.gitlab/custom-jobs-and-variables.yml' - project: 'radiuss/radiuss-shared-ci' - ref: v2023.03.1 + ref: woptim/rocmcc-5-5-1 file: '${CI_MACHINE}-build-and-test.yml' - local: '.gitlab/${CI_MACHINE}-build-and-test-extra.yml' strategy: depend @@ -85,7 +85,7 @@ trigger-rajaperf: include: # checks preliminary to running the actual CI test (optional) - project: 'radiuss/radiuss-shared-ci' - ref: v2023.03.1 + ref: woptim/rocmcc-5-5-1 file: 'preliminary-ignore-draft-pr.yml' # pipelines subscribed by the project - local: '.gitlab/subscribed-pipelines.yml' diff --git a/.gitlab/corona-build-and-test-extra.yml b/.gitlab/corona-build-and-test-extra.yml index e65bba3947..a4ad4ff693 100644 --- a/.gitlab/corona-build-and-test-extra.yml +++ b/.gitlab/corona-build-and-test-extra.yml @@ -21,8 +21,8 @@ # ${PROJECT__DEPS} in the extra jobs. There is no reason not to fully # describe the spec here. -rocmcc_5_4_1_hip_desul_atomics: +rocmcc_5_5_0_hip_desul_atomics: variables: - SPEC: " ~shared +rocm ~openmp +tests +desul amdgpu_target=gfx906 %rocmcc@5.4.1 ^hip@5.4.1 ^blt@develop" + SPEC: " ~shared +rocm ~openmp +tests +desul amdgpu_target=gfx906 %rocmcc@5.5.0 ^hip@5.5.0 ^blt@develop" extends: .build_and_test_on_corona diff --git a/.gitlab/tioga-build-and-test-extra.yml b/.gitlab/tioga-build-and-test-extra.yml index 25b9880982..3751c2cc99 100644 --- a/.gitlab/tioga-build-and-test-extra.yml +++ b/.gitlab/tioga-build-and-test-extra.yml @@ -21,12 +21,12 @@ # ${PROJECT__DEPS} in the extra jobs. There is no reason not to fully # describe the spec here. -rocmcc_5_4_3_hip_desul_atomics: +rocmcc_5_5_1_hip_desul_atomics: variables: - SPEC: "~shared +rocm ~openmp +desul +tests amdgpu_target=gfx90a %rocmcc@5.4.3 ^hip@5.4.3 ^blt@develop" + SPEC: "~shared +rocm ~openmp +desul +tests amdgpu_target=gfx90a %rocmcc@5.5.1 ^hip@5.5.1 ^blt@develop" extends: .build_and_test_on_tioga -rocmcc_5_4_3_hip_openmp: +rocmcc_5_5_1_hip_openmp: variables: - SPEC: "~shared +rocm +openmp +tests amdgpu_target=gfx90a %rocmcc@5.4.3 ^hip@5.4.3 ^blt@develop" + SPEC: "~shared +rocm +openmp +tests amdgpu_target=gfx90a %rocmcc@5.5.1 ^hip@5.5.1 ^blt@develop" extends: .build_and_test_on_tioga diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index ffde592300..55005af670 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit ffde592300392a7bbebbfe0a8d752187c1b93132 +Subproject commit 55005af670edc0f3798519a0ebae12f541555778 From 244c05ae60147ad48492ae52fff3edb3ea6e4402 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Fri, 23 Jun 2023 10:49:04 +0200 Subject: [PATCH 004/193] Add missing rocmcc compilers --- scripts/radiuss-spack-configs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index 55005af670..5335191a5f 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit 55005af670edc0f3798519a0ebae12f541555778 +Subproject commit 5335191a5f2cd251be0fae2ebe22320cca0044d4 From a8467eb8e57a11d0d6c65e7073565dff947f139f Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Fri, 23 Jun 2023 16:01:10 +0200 Subject: [PATCH 005/193] point to stable ref in radiuss-shared-ci --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ed02a9b5a1..42fe01ae07 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -59,7 +59,7 @@ stages: include: - local: '.gitlab/custom-jobs-and-variables.yml' - project: 'radiuss/radiuss-shared-ci' - ref: woptim/rocmcc-5-5-1 + ref: v2023.06.0 file: '${CI_MACHINE}-build-and-test.yml' - local: '.gitlab/${CI_MACHINE}-build-and-test-extra.yml' strategy: depend @@ -85,7 +85,7 @@ trigger-rajaperf: include: # checks preliminary to running the actual CI test (optional) - project: 'radiuss/radiuss-shared-ci' - ref: woptim/rocmcc-5-5-1 + ref: v2023.06.0 file: 'preliminary-ignore-draft-pr.yml' # pipelines subscribed by the project - local: '.gitlab/subscribed-pipelines.yml' From af49922971eaa1643cf836707a2c85f7c6025374 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Fri, 23 Jun 2023 16:03:35 +0200 Subject: [PATCH 006/193] point to radiuss-spack-config main ref --- scripts/radiuss-spack-configs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index 5335191a5f..c9d8938279 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit 5335191a5f2cd251be0fae2ebe22320cca0044d4 +Subproject commit c9d8938279824ba1d10465dd2d9b8faf59edbfa9 From 4382eb1f085a7b905c5c9bd8fa33e4f11da1245a Mon Sep 17 00:00:00 2001 From: Adrien Bernede <51493078+adrienbernede@users.noreply.github.com> Date: Fri, 4 Aug 2023 11:48:10 +0200 Subject: [PATCH 007/193] Update radiuss spack configs and shared ci --- .gitlab-ci.yml | 4 ++-- .gitlab/corona-build-and-test-extra.yml | 4 ++-- .gitlab/lassen-build-and-test-extra.yml | 8 -------- .gitlab/ruby-build-and-test-extra.yml | 4 ++-- .gitlab/tioga-build-and-test-extra.yml | 8 ++++---- scripts/radiuss-spack-configs | 2 +- 6 files changed, 11 insertions(+), 19 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 42fe01ae07..5ff1f9703e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -59,7 +59,7 @@ stages: include: - local: '.gitlab/custom-jobs-and-variables.yml' - project: 'radiuss/radiuss-shared-ci' - ref: v2023.06.0 + ref: v2023.08.0 file: '${CI_MACHINE}-build-and-test.yml' - local: '.gitlab/${CI_MACHINE}-build-and-test-extra.yml' strategy: depend @@ -85,7 +85,7 @@ trigger-rajaperf: include: # checks preliminary to running the actual CI test (optional) - project: 'radiuss/radiuss-shared-ci' - ref: v2023.06.0 + ref: v2023.08.0 file: 'preliminary-ignore-draft-pr.yml' # pipelines subscribed by the project - local: '.gitlab/subscribed-pipelines.yml' diff --git a/.gitlab/corona-build-and-test-extra.yml b/.gitlab/corona-build-and-test-extra.yml index a4ad4ff693..87474144be 100644 --- a/.gitlab/corona-build-and-test-extra.yml +++ b/.gitlab/corona-build-and-test-extra.yml @@ -21,8 +21,8 @@ # ${PROJECT__DEPS} in the extra jobs. There is no reason not to fully # describe the spec here. -rocmcc_5_5_0_hip_desul_atomics: +rocmcc_5_6_0_hip_desul_atomics: variables: - SPEC: " ~shared +rocm ~openmp +tests +desul amdgpu_target=gfx906 %rocmcc@5.5.0 ^hip@5.5.0 ^blt@develop" + SPEC: " ~shared +rocm ~openmp +tests +desul amdgpu_target=gfx906 %rocmcc@5.6.0 ^hip@5.6.0 ^blt@develop" extends: .build_and_test_on_corona diff --git a/.gitlab/lassen-build-and-test-extra.yml b/.gitlab/lassen-build-and-test-extra.yml index 2e4118df90..fc0b65c450 100644 --- a/.gitlab/lassen-build-and-test-extra.yml +++ b/.gitlab/lassen-build-and-test-extra.yml @@ -20,14 +20,6 @@ xl_2022_08_19_gcc_8_3_1_cuda_11_2_0: LASSEN_BUILD_AND_TEST_JOB_ALLOC: "1 -W 120" extends: .build_and_test_on_lassen -# Overriding shared spec: Longer allocation + extra flags -xl_2022_08_19_gcc_8_3_1_cuda_11_7_0: - variables: - SPEC: "${PROJECT_LASSEN_VARIANTS} +cuda cxxflags==\"-qthreaded -std=c++14 -O3 -qstrict -qxlcompatmacros -qlanglvl=extended0x -qalias=noansi -qhot -qpic -qsmp=omp -qsuppress=1500-029 -qsuppress=1500-036\" %xl@16.1.1.12.gcc.8.3.1 ^cuda@11.7.0+allow-unsupported-compilers ${PROJECT_LASSEN_DEPS}" - MODULE_LIST: "cuda/11.7.0" - LASSEN_BUILD_AND_TEST_JOB_ALLOC: "1 -W 120" - extends: .build_and_test_on_lassen - ############ # Extra jobs diff --git a/.gitlab/ruby-build-and-test-extra.yml b/.gitlab/ruby-build-and-test-extra.yml index a8cd89a49b..23d8690f9c 100644 --- a/.gitlab/ruby-build-and-test-extra.yml +++ b/.gitlab/ruby-build-and-test-extra.yml @@ -23,9 +23,9 @@ gcc_10_3_1: RUBY_BUILD_AND_TEST_JOB_ALLOC: "--time=60 --nodes=1" extends: .build_and_test_on_ruby -intel_19_1_2_gcc_8_5_0: +intel_19_1_2_gcc_10_3_1: variables: - SPEC: " ~shared +openmp +omptask +tests %intel@19.1.2.gcc.8.5.0" + SPEC: " ~shared +openmp +omptask +tests %intel@19.1.2.gcc.10.3.1" RUBY_BUILD_AND_TEST_JOB_ALLOC: "--time=90 --nodes=1" extends: .build_and_test_on_ruby diff --git a/.gitlab/tioga-build-and-test-extra.yml b/.gitlab/tioga-build-and-test-extra.yml index ec8e5dd1d4..bbf60ad430 100644 --- a/.gitlab/tioga-build-and-test-extra.yml +++ b/.gitlab/tioga-build-and-test-extra.yml @@ -21,12 +21,12 @@ # ${PROJECT__DEPS} in the extra jobs. There is no reason not to fully # describe the spec here. -rocmcc_5_5_1_hip_desul_atomics: +rocmcc_5_6_0_hip_desul_atomics: variables: - SPEC: "~shared +rocm ~openmp +desul +tests amdgpu_target=gfx90a %rocmcc@5.5.1 ^hip@5.5.1 ^blt@develop" + SPEC: "~shared +rocm ~openmp +desul +tests amdgpu_target=gfx90a %rocmcc@5.6.0 ^hip@5.6.0 ^blt@develop" extends: .build_and_test_on_tioga -rocmcc_5_5_1_hip_openmp: +rocmcc_5_6_0_hip_openmp: variables: - SPEC: "~shared +rocm +openmp +omptask +tests amdgpu_target=gfx90a %rocmcc@5.5.1 ^hip@5.5.1 ^blt@develop" + SPEC: "~shared +rocm +openmp +omptask +tests amdgpu_target=gfx90a %rocmcc@5.6.0 ^hip@5.6.0 ^blt@develop" extends: .build_and_test_on_tioga diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index 955f0c3a67..53902d811c 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit 955f0c3a67e28fac4648ac41787e93511207b22e +Subproject commit 53902d811c52ebd3f3ea4a7f558b65dc3d1f699d From 085b7f493a557abfa5bceceb9c31535532e7576e Mon Sep 17 00:00:00 2001 From: Adrien Bernede <51493078+adrienbernede@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:28:50 +0200 Subject: [PATCH 008/193] reactivate intel 2022 (oneapi) --- .gitlab/ruby-build-and-test-extra.yml | 10 +++++----- scripts/radiuss-spack-configs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitlab/ruby-build-and-test-extra.yml b/.gitlab/ruby-build-and-test-extra.yml index 23d8690f9c..d9dd7b2d58 100644 --- a/.gitlab/ruby-build-and-test-extra.yml +++ b/.gitlab/ruby-build-and-test-extra.yml @@ -54,8 +54,8 @@ clang_14_0_6_gcc_10_3_1_desul_atomics: extends: .build_and_test_on_ruby # Ideally, we want to use this spec, but the build takes too much time... -#intel_oneapi_2022_2_gcc_8_3_1: -# variables: -# SPEC: "~shared +openmp +tests %oneapi@2022.2.gcc.8.3.1" -# RUBY_BUILD_AND_TEST_JOB_ALLOC: "--time=90 --nodes=1" -# extends: .build_and_test_on_ruby +intel_2022_1_gcc_8_3_1: + variables: + SPEC: "~shared +openmp +tests %intel@2022.1.gcc.8.3.1" + RUBY_BUILD_AND_TEST_JOB_ALLOC: "--time=90 --nodes=1" + extends: .build_and_test_on_ruby diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index 53902d811c..d67bb50a59 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit 53902d811c52ebd3f3ea4a7f558b65dc3d1f699d +Subproject commit d67bb50a590302bf77077c6f55a93e1e1ca37287 From 650d279ead829f934fa688f6a40bded8b9050dcb Mon Sep 17 00:00:00 2001 From: Adrien Bernede <51493078+adrienbernede@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:32:18 +0200 Subject: [PATCH 009/193] Fix gcc version with intel 2022.1 --- .gitlab/ruby-build-and-test-extra.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab/ruby-build-and-test-extra.yml b/.gitlab/ruby-build-and-test-extra.yml index d9dd7b2d58..e75930a5bf 100644 --- a/.gitlab/ruby-build-and-test-extra.yml +++ b/.gitlab/ruby-build-and-test-extra.yml @@ -54,8 +54,8 @@ clang_14_0_6_gcc_10_3_1_desul_atomics: extends: .build_and_test_on_ruby # Ideally, we want to use this spec, but the build takes too much time... -intel_2022_1_gcc_8_3_1: +intel_2022_1_gcc_10_3_1: variables: - SPEC: "~shared +openmp +tests %intel@2022.1.gcc.8.3.1" + SPEC: "~shared +openmp +tests %intel@2022.1.gcc.10.3.1" RUBY_BUILD_AND_TEST_JOB_ALLOC: "--time=90 --nodes=1" extends: .build_and_test_on_ruby From b8d9a0d49d750f6e044e25b5524156fb0d8e9155 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Mon, 7 Aug 2023 15:42:05 +0200 Subject: [PATCH 010/193] Fix intel version --- .gitlab/ruby-build-and-test-extra.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab/ruby-build-and-test-extra.yml b/.gitlab/ruby-build-and-test-extra.yml index e75930a5bf..34a72d4f02 100644 --- a/.gitlab/ruby-build-and-test-extra.yml +++ b/.gitlab/ruby-build-and-test-extra.yml @@ -54,8 +54,8 @@ clang_14_0_6_gcc_10_3_1_desul_atomics: extends: .build_and_test_on_ruby # Ideally, we want to use this spec, but the build takes too much time... -intel_2022_1_gcc_10_3_1: +intel_2022_1_0_gcc_10_3_1: variables: - SPEC: "~shared +openmp +tests %intel@2022.1.gcc.10.3.1" + SPEC: "~shared +openmp +tests %intel@2022.1.0.gcc.10.3.1" RUBY_BUILD_AND_TEST_JOB_ALLOC: "--time=90 --nodes=1" extends: .build_and_test_on_ruby From 83a7d060c3fdbedab186779d1137e79501875026 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Mon, 7 Aug 2023 16:33:08 +0200 Subject: [PATCH 011/193] Fix intel fc fortran compiler path --- scripts/radiuss-spack-configs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index d67bb50a59..a8a56d06eb 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit d67bb50a590302bf77077c6f55a93e1e1ca37287 +Subproject commit a8a56d06eb44b6b5fc59c6288b92b2a9bc5fe7f2 From ca06c12725bb35541ec0bb56c88dff27f1a6df99 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Fri, 11 Aug 2023 19:03:21 +0200 Subject: [PATCH 012/193] Uniformize build_and_test script: add ability to not use /dev/shm --- .gitlab-ci.yml | 5 +-- scripts/gitlab/build_and_test.sh | 55 +++++++++++++------------------- 2 files changed, 25 insertions(+), 35 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5ff1f9703e..e25dda6730 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,8 +12,9 @@ # This entire pipeline is LLNL-specific # # Important note: This file is a template provided by -# llnl/radiuss-shared-ci. It should not require any change from the project to -# get started but could feature project-specific stages. +# llnl/radiuss-shared-ci. Changes needed consists in setting variable values, +# change the reference to the radiuss-shared-ci repo, opt-in and out optional +# features. The project can then extend it with additional stages. # # However, each project should provide: # - .gitlab/custom-jobs-and-variables.yml diff --git a/scripts/gitlab/build_and_test.sh b/scripts/gitlab/build_and_test.sh index 065490a916..08ca015ddb 100755 --- a/scripts/gitlab/build_and_test.sh +++ b/scripts/gitlab/build_and_test.sh @@ -21,11 +21,11 @@ hostname="$(hostname)" truehostname=${hostname//[0-9]/} project_dir="$(pwd)" -build_root=${BUILD_ROOT:-""} hostconfig=${HOST_CONFIG:-""} spec=${SPEC:-""} module_list=${MODULE_LIST:-""} job_unique_id=${CI_JOB_ID:-""} +use_dev_shm=${USE_DEV_SHM:-true} if [[ -n ${module_list} ]] then @@ -37,7 +37,7 @@ fi prefix="" -if [[ -d /dev/shm ]] +if [[ -d /dev/shm && ${use_dev_shm} == true ]] then prefix="/dev/shm/${hostname}" if [[ -z ${job_unique_id} ]]; then @@ -50,6 +50,10 @@ then prefix="${prefix}-${job_unique_id}" mkdir -p ${prefix} +else + # We set the prefix in the parent directory so that spack dependencies are not installed inside the source tree. + prefix="$(pwd)/../spack-and-build-root" + mkdir -p ${prefix} fi # Dependencies @@ -69,20 +73,15 @@ then exit 1 fi - prefix_opt="" + prefix_opt="--prefix=${prefix}" - if [[ -d /dev/shm ]] - then - prefix_opt="--prefix=${prefix}" - - # We force Spack to put all generated files (cache and configuration of - # all sorts) in a unique location so that there can be no collision - # with existing or concurrent Spack. - spack_user_cache="${prefix}/spack-user-cache" - export SPACK_DISABLE_LOCAL_CONFIG="" - export SPACK_USER_CACHE_PATH="${spack_user_cache}" - mkdir -p ${spack_user_cache} - fi + # We force Spack to put all generated files (cache and configuration of + # all sorts) in a unique location so that there can be no collision + # with existing or concurrent Spack. + spack_user_cache="${prefix}/spack-user-cache" + export SPACK_DISABLE_LOCAL_CONFIG="" + export SPACK_USER_CACHE_PATH="${spack_user_cache}" + mkdir -p ${spack_user_cache} ./scripts/uberenv/uberenv.py --spec="${spec}" ${prefix_opt} @@ -121,17 +120,8 @@ fi hostconfig=$(basename ${hostconfig_path}) # Build Directory -if [[ -z ${build_root} ]] -then - if [[ -d /dev/shm ]] - then - build_root="${prefix}" - else - build_root="$(pwd)" - fi -else - build_root="${build_root}" -fi +# When using /dev/shm, we use prefix for both spack builds and source build, unless BUILD_ROOT was defined +build_root=${BUILD_ROOT:-"${prefix}"} build_dir="${build_root}/build_${hostconfig//.cmake/}" install_dir="${build_root}/install_${hostconfig//.cmake/}" @@ -164,7 +154,6 @@ then mkdir -p ${build_dir} && cd ${build_dir} date - if [[ "${truehostname}" == "corona" || "${truehostname}" == "tioga" ]] then module unload rocm @@ -180,11 +169,11 @@ then else make install fi + date echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" echo "~~~~~ RAJA built" echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - date fi # Test @@ -246,13 +235,13 @@ then echo "~~~~~ RAJA tests complete" echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" date - - # echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - # echo "~~~~~ CLEAN UP" - # echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - # make clean fi +echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" +echo "~~~~~ CLEAN UP" +echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" +make clean + echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" echo "~~~~~ Build and test completed" echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" From 7f2011edac38a1d2c8abc0b94a84e85d23e07068 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Sat, 12 Aug 2023 15:00:40 +0200 Subject: [PATCH 013/193] Change pattern for draft PR filter --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e25dda6730..96c67831d6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -41,8 +41,8 @@ variables: # Set the build-and-test command. BUILD_AND_TEST_CMD: "./scripts/gitlab/build_and_test.sh" # Override the list of branch that will skip the "draft PR test". -# Add protected branches here. Defaults to "develop main master". - ALWAYS_RUN_LIST: "develop main" +# Add protected branches here. + ALWAYS_RUN_LIST: "^develop$|^main$|^v[0-9.]*-RC$" # We organize the build-and-test stage in sub-pipelines. Each sub-pipeline # corresponds to a test batch on a given machine. From 9afc85d49ea0daf4f660a26ee3500851ed65de0a Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Tue, 15 Aug 2023 14:40:18 +0200 Subject: [PATCH 014/193] Update RSC with changes for Umpire --- scripts/radiuss-spack-configs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index a8a56d06eb..4660a0ba2d 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit a8a56d06eb44b6b5fc59c6288b92b2a9bc5fe7f2 +Subproject commit 4660a0ba2d6a91e5f353b506739ad420baee8a58 From f3992e317ecb85ea75e78211ff526f76c99a30f5 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Tue, 15 Aug 2023 16:18:39 +0200 Subject: [PATCH 015/193] RAJA package: Set BLT_CXX_STD to C++14 globally --- scripts/radiuss-spack-configs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index 4660a0ba2d..03ed465dd6 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit 4660a0ba2d6a91e5f353b506739ad420baee8a58 +Subproject commit 03ed465dd6236d324574b20efe43b6731eb36ce0 From aac5e8d04c1cac2fe948490a95eb159e936b156b Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Wed, 16 Aug 2023 15:14:52 +0200 Subject: [PATCH 016/193] Mark intel oneapi on ruby as allowed to fail (openmp test failing) --- .gitlab/ruby-build-and-test-extra.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.gitlab/ruby-build-and-test-extra.yml b/.gitlab/ruby-build-and-test-extra.yml index 34a72d4f02..ae3cdcf2d4 100644 --- a/.gitlab/ruby-build-and-test-extra.yml +++ b/.gitlab/ruby-build-and-test-extra.yml @@ -29,6 +29,12 @@ intel_19_1_2_gcc_10_3_1: RUBY_BUILD_AND_TEST_JOB_ALLOC: "--time=90 --nodes=1" extends: .build_and_test_on_ruby +intel_2022_1_0: + variables: + SPEC: "${PROJECT_RUBY_VARIANTS} %intel@2022.1.0 ${PROJECT_RUBY_DEPS}" + allow_failure: true + extends: .build_and_test_on_ruby + ############ # Extra jobs ############ @@ -52,10 +58,3 @@ clang_14_0_6_gcc_10_3_1_desul_atomics: variables: SPEC: " ~shared +openmp +tests +desul %clang@14.0.6.gcc.10.3.1" extends: .build_and_test_on_ruby - -# Ideally, we want to use this spec, but the build takes too much time... -intel_2022_1_0_gcc_10_3_1: - variables: - SPEC: "~shared +openmp +tests %intel@2022.1.0.gcc.10.3.1" - RUBY_BUILD_AND_TEST_JOB_ALLOC: "--time=90 --nodes=1" - extends: .build_and_test_on_ruby From b950ee740182f93c46ce97aefc28e1b93b6589c2 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Thu, 17 Aug 2023 17:37:59 +0200 Subject: [PATCH 017/193] Update RSC packages --- scripts/radiuss-spack-configs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index 03ed465dd6..9099a2b8fd 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit 03ed465dd6236d324574b20efe43b6731eb36ce0 +Subproject commit 9099a2b8fd8121594df0c036825787e31c2e5085 From df9a038c15046b0d7044b0f575e06fc4dac2018c Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Thu, 17 Aug 2023 17:39:25 +0200 Subject: [PATCH 018/193] Bump Spack version --- .uberenv_config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.uberenv_config.json b/.uberenv_config.json index f160101d50..abbff592c6 100644 --- a/.uberenv_config.json +++ b/.uberenv_config.json @@ -4,7 +4,7 @@ "package_final_phase" : "initconfig", "package_source_dir" : "../..", "spack_url": "https://github.com/spack/spack.git", -"spack_branch": "e4s-23.02", +"spack_branch": "v0.20.1", "spack_activate" : {}, "spack_configs_path": "scripts/radiuss-spack-configs", "spack_packages_path": "scripts/radiuss-spack-configs/packages", From f301cab9c9c1f79730f74dfdd446eff92b28e703 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Thu, 17 Aug 2023 17:52:24 +0200 Subject: [PATCH 019/193] From RSC: syntax fix --- scripts/radiuss-spack-configs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index 9099a2b8fd..b2e1167927 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit 9099a2b8fd8121594df0c036825787e31c2e5085 +Subproject commit b2e11679273dbda51d6db94144a587b16aa6d833 From 7da265d04018174692360e6fefafdc49b10dfb5c Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Thu, 17 Aug 2023 19:02:59 +0200 Subject: [PATCH 020/193] Update RSC --- .gitlab-ci.yml | 7 ++++--- scripts/radiuss-spack-configs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 96c67831d6..be4161bc21 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -40,9 +40,10 @@ variables: BUILD_ROOT: ${CI_PROJECT_DIR} # Set the build-and-test command. BUILD_AND_TEST_CMD: "./scripts/gitlab/build_and_test.sh" -# Override the list of branch that will skip the "draft PR test". -# Add protected branches here. - ALWAYS_RUN_LIST: "^develop$|^main$|^v[0-9.]*-RC$" +# Override the pattern describing branches that will skip the "draft PR test". +# Add protected branches here. See default value in +# preliminary-ignore-draft-pr.yml. + ALWAYS_RUN_PATTERN: "^develop$|^main$|^v[0-9.]*-RC$" # We organize the build-and-test stage in sub-pipelines. Each sub-pipeline # corresponds to a test batch on a given machine. diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index b2e1167927..a7b3ea9c76 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit b2e11679273dbda51d6db94144a587b16aa6d833 +Subproject commit a7b3ea9c765a622a4f24b43942aabf6f8d6dbfed From 4a09e319263a974a7b961e4cadb6ef97253d93ec Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Fri, 18 Aug 2023 21:59:17 +0200 Subject: [PATCH 021/193] Update RSC to main --- scripts/radiuss-spack-configs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index a7b3ea9c76..9eded97504 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit a7b3ea9c765a622a4f24b43942aabf6f8d6dbfed +Subproject commit 9eded97504a0a293b8d0020c062365b8e79c797b From 5e1f5062fd2391e75f97b0fd2d0becf95cd12a92 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Tue, 22 Aug 2023 10:38:20 +0200 Subject: [PATCH 022/193] =?UTF-8?q?From=20RSC:=20add=20latest=20RAJA?= =?UTF-8?q?=E2=80=AFand=20RAJAPerf=20releases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/radiuss-spack-configs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index 9eded97504..bdf3d423b9 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit 9eded97504a0a293b8d0020c062365b8e79c797b +Subproject commit bdf3d423b92324668db91a151b6d400507562282 From 7b5f9925aa9a4ee9b9bf817be8466aeeedd20999 Mon Sep 17 00:00:00 2001 From: Rich Hornung Date: Fri, 25 Aug 2023 15:18:24 -0700 Subject: [PATCH 023/193] Clean up test in CI overview sections. --- docs/sphinx/dev_guide/ci.rst | 79 ++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/docs/sphinx/dev_guide/ci.rst b/docs/sphinx/dev_guide/ci.rst index 719fbd1b0b..d3341878b2 100644 --- a/docs/sphinx/dev_guide/ci.rst +++ b/docs/sphinx/dev_guide/ci.rst @@ -17,28 +17,27 @@ Continuous Integration (CI) Testing viewed by clicking the appropriate link in the **checks** section of a GitHub pull request. -The CI tools used by the RAJA project are: +The RAJA project uses to CI tools to run its tests: * **Azure Pipelines** runs builds and tests for Linux, Windows, and MacOS - environments using recent versions of various compilers. While we do GPU - builds for CUDA, HIP, and SYCL on Azure, RAJA tests are only run for - CPU-only pipelines. Docker container images we use for the Linux testing - are maintained in the + environments using recent versions of various compilers. While we do some + GPU builds on Azure, RAJA tests are only run for CPU-only builds. Docker + container images we use for the Linux testing are maintained in the `RSE Ops Project `_. Please see the `RAJA Azure DevOps `_ project to learn more about our testing there. - * **GitLab** instances in the Collaboration Zone (CZ) of the Livermore - Computing (LC) Center run builds and tests on LC HPC platforms using + * **GitLab** instance in the Collaboration Zone (CZ) of the Livermore + Computing (LC) Center run builds and tests on LC platforms using software stacks (compilers, etc.) important to many RAJA user applications. Execution of LC GitLab CI on LC resources has restrictions, which are described below. If you have access to LC platforms, you can access information about `LC GitLab CI `_ -The tools integrate with the RAJA GitHub project and automatically run RAJA +These tools integrate with the RAJA GitHub project and automatically run RAJA builds and tests when a PR is created and when changes are pushed to a PR -branch. +branch or one of our protected branches `main` and `develop`. The following sections describe basic elements of the operation of the CI tools. @@ -55,20 +54,24 @@ machine and compiler environments important to RAJA user applications at LLNL. Constraints ----------- -Running GitLab CI on Livermore Computing (LC) platforms is constrained by LC +How projects can run GitLab CI on LC platforms is constrained by LC security policies. The policies require that all members of a GitHub project be members of the LLNL GitHub organization and have two-factor authentication enabled on their GitHub accounts. When these requirements are satisfied, -mirroring of a GitHub repo and triggering GitLab CI functionality from GitHub -can be done. Otherwise, LC GitLab CI checks will not be run for a project. -For a compliant LLNL GitHub project, such as RAJA, auto-mirroring of the +GitLab on the LC CZ can mirror a GitHub project and trigger GitLab CI when +changes are made to the GitHub repo. If the requirements are not met, LC +GitLab CI checks will not be run for a project. This implies, for example, +that GitLab CI will not run for a PR made on an LLNL organization project +from a fork of the project repo by someone not in the LLNL organization. + +For a compliant LLNL GitHub project like RAJA, auto-mirroring of the GitHub repo on LC GitLab is done every 30 minutes or so, triggering builds and tests on new changes pushed to the RAJA GitHub project. If you have access to LC platforms, you can learn more about `LC GitLab mirroring `_. -**GitLab CI will not run for a PR branch on a fork of the RAJA repo.** We -manually manage contributions made on a fork of the RAJA repo using the -procedure described in :ref:`contributing-label`. +.. note:: **GitLab CI will not run for a PR branch on a fork of the RAJA repo.** + We manually manage contributions made on a fork of the RAJA repo + using the procedure described in :ref:`contributing-label`. .. _gitlab_ci_workflow-label: @@ -78,22 +81,29 @@ GitLab CI (LC) Testing Workflow The figure below shows the high-level steps in the RAJA GitLab CI testing process. The main steps, which we will discuss in more detail later, are: - #. A *mirror* of the RAJA GitHub repo in the RAJA LC CZ GitLab project is - updated automatically after the RAJA ``develop`` or ``main`` branches - are changed as well as when any PR branch in the RAJA GitHub project is - changed. There may be a delay in the mirroring, since it is not - synhronous with changes to the RAJA GitHub project. - #. GitLab launches CI test pipelines. While running, the execution and - pass/fail status may be viewed and monitored in the GitLab CI GUI - or in the RAJA GitHub project checks section for a PR. + #. A *mirror* of the RAJA GitHub repo is updated in the RAJA LC CZ GitLab + project automatically every 30 minutes approximately. + + .. note:: There may be a delay in the mirroring, since it is not + synhronous with changes to the RAJA GitHub project. + + #. GitLab launches CI test pipelines for any new changes made to the + ``develop`` or ``main`` branches or any non-fork PR branch. While + running, the execution and pass/fail status may be viewed and monitored + in the GitLab CI GUI or in the RAJA GitHub project checks section of a PR. + #. For each platform and compiler combination, `Spack `_ builds RAJA dependencies and generates a configuration in the form of a CMake cache file, or *host-config* file. + #. A host-config file is passed to CMake, which configures a RAJA build space. Then, RAJA and its tests are compiled. + #. Next, the RAJA tests are run. - #. When test pipelines complete, results are reported in GitLab. + + #. When test pipelines complete, results are reported to GitLab. + #. Lastly, GitLab reports to GitHub to show the status of checks there. .. figure:: ./figures/RAJA-Gitlab-Workflow2.png @@ -110,24 +120,23 @@ play in the RAJA GitLab CI workflow. GitLab CI Testing Dependencies (specific to LC CZ) --------------------------------------------------- -RAJA GitLab CI testing depends on several other projects that we share with -other projects. These include +RAJA GitLab CI testing depends on several other projects that we develop +collaboratively with other projects. These include * `RADIUSS Shared CI `_, a centralized framework for software testing with GitLab CI on LC machines. The project is developed on GitHub and is mirrored to the LC - CZ GitLab instance, where it is used by multiple projects. - * `Spack `_, a widely used - multi-platform package manager that builds and installs software stacks. + CZ GitLab instance. + * `Spack `_, a multi-platform package + manager that builds and installs HPC software stacks. * `Uberenv `_, a Python script that helps to automate the use of Spack and other tools for building third-party dependencies. Uberenv is a submodule in RAJA that lives in ``RAJA/scripts/uberenv/``. * `RADIUSS Spack Configs `_, - a collection of build configurations used by Spack to generate host-config - files for CMake. The build configurations are specific to LLNL LC - platforms and are used by multiple projects. It also contains Spack - packages for various projects, including RAJA. The RAJA Spack package is + a collection of Spack compiler and package configurations used by Spack + to generate host-config files for CMake. The build configurations are + specific to LLNL LC platforms. Spack packages for multiple projects are maintained in this project. RADIUSS Spack Configs is a submodule in RAJA that lives in ``RAJA/scripts/radiuss-spack-configs/``. @@ -135,6 +144,8 @@ The relationships among these dependencies in a project that uses them is illustrated in the `RADIUSS Shared CI User Guide `_. The guide also describes how the framework works and how to set up a project to use it. +.. important:: The RAJA Spack package is maintained in the `RADIUSS Spack Configs `_ project. When it is updated, it is pushed to the Spack repo on GitHub. + In the rest of the this section, we describe files in the RAJA repo that are used to configure and customize the shared CI framework specifically for the RAJA project. From b40c739acf35297e8b1cf0e36651778795d1b733 Mon Sep 17 00:00:00 2001 From: Brian Homerding Date: Mon, 28 Aug 2023 22:06:27 +0000 Subject: [PATCH 024/193] Remove maxloc and minloc tests for SYCL --- test/functional/forall/reduce-basic/CMakeLists.txt | 9 +++++++++ .../forall/reduce-multiple-indexset/CMakeLists.txt | 13 +++++++------ .../forall/reduce-multiple-segment/CMakeLists.txt | 13 +++++++------ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/test/functional/forall/reduce-basic/CMakeLists.txt b/test/functional/forall/reduce-basic/CMakeLists.txt index 34ee40a25f..e2592a858b 100644 --- a/test/functional/forall/reduce-basic/CMakeLists.txt +++ b/test/functional/forall/reduce-basic/CMakeLists.txt @@ -114,6 +114,15 @@ if(RAJA_ENABLE_SYCL) list(APPEND FORALL_BACKENDS Sycl) endif() +# +# If building SYCL tests, remove the back-end from +# from the list of tests to generate here for the +# core reduction tests. +# +if(RAJA_ENABLE_SYCL) + list(REMOVE_ITEM REDUCETYPES ReduceMaxLoc) + list(REMOVE_ITEM REDUCETYPES ReduceMinLoc) +endif() # # Generate core reduction tests for each enabled RAJA back-end diff --git a/test/functional/forall/reduce-multiple-indexset/CMakeLists.txt b/test/functional/forall/reduce-multiple-indexset/CMakeLists.txt index f7c481172b..5e728701e7 100644 --- a/test/functional/forall/reduce-multiple-indexset/CMakeLists.txt +++ b/test/functional/forall/reduce-multiple-indexset/CMakeLists.txt @@ -17,13 +17,14 @@ if(RAJA_ENABLE_TARGET_OPENMP) endif() # -# While we're adding SYCL tests, enable it for each test set like this. +# If building SYCL tests, remove the back-end from +# from the list of tests to generate here for the +# reduce tests. # -# Eventually, remove this and enable in the top-level CMakeLists.txt file. -# -#if(RAJA_ENABLE_SYCL) -# list(APPEND FORALL_BACKENDS Sycl) -#endif() +if(RAJA_ENABLE_SYCL) + list(REMOVE_ITEM REDUCETYPES ReduceMaxLoc) + list(REMOVE_ITEM REDUCETYPES ReduceMinLoc) +endif() # # Generate tests for each enabled RAJA back-end diff --git a/test/functional/forall/reduce-multiple-segment/CMakeLists.txt b/test/functional/forall/reduce-multiple-segment/CMakeLists.txt index 12c1e19d93..0eee794eb3 100644 --- a/test/functional/forall/reduce-multiple-segment/CMakeLists.txt +++ b/test/functional/forall/reduce-multiple-segment/CMakeLists.txt @@ -17,13 +17,14 @@ if(RAJA_ENABLE_TARGET_OPENMP) endif() # -# While we're adding SYCL tests, enable it for each test set like this. +# If building SYCL tests, remove the back-end from +# from the list of tests to generate here for the +# reduce tests. # -# Eventually, remove this and enable in the top-level CMakeLists.txt file. -# -#if(RAJA_ENABLE_SYCL) -# list(APPEND FORALL_BACKENDS Sycl) -#endif() +if(RAJA_ENABLE_SYCL) + list(REMOVE_ITEM REDUCETYPES ReduceMaxLoc) + list(REMOVE_ITEM REDUCETYPES ReduceMinLoc) +endif() # # Generate tests for each enabled RAJA back-end From c3147a68af23a450f90d834f2ab332137c5caa36 Mon Sep 17 00:00:00 2001 From: Brian Homerding Date: Tue, 29 Aug 2023 13:15:39 +0000 Subject: [PATCH 025/193] Remove MaxLoc and MinLoc from SYCL reduction --- include/RAJA/policy/sycl/reduce.hpp | 140 ---------------------------- 1 file changed, 140 deletions(-) diff --git a/include/RAJA/policy/sycl/reduce.hpp b/include/RAJA/policy/sycl/reduce.hpp index c88c05f2c1..522edd8004 100644 --- a/include/RAJA/policy/sycl/reduce.hpp +++ b/include/RAJA/policy/sycl/reduce.hpp @@ -595,146 +595,6 @@ class ReduceMax } }; -//! specialization of ReduceMinLoc for omp_target_reduce -template -class ReduceMinLoc - : public TargetReduceLoc, T, IndexType> -{ -public: - - using self = ReduceMinLoc; - using parent = - TargetReduceLoc, T, IndexType>; - using parent::parent; - - //! enable minloc() for ReduceMinLoc -- alias for reduce() - self &minloc(T rhsVal, IndexType rhsLoc) - { -#ifdef __SYCL_DEVICE_ONLY__ - // TODO: Race condition currently - auto i = 0;//__spirv::initLocalInvocationId<1, cl::sycl::id<1>>()[0]; - auto atm = cl::sycl::ext::oneapi::atomic_ref(parent::val.device[i]); - auto oldMin = atm.fetch_min(rhsVal); - if(oldMin >= rhsVal) { // New min or Same min - if(oldMin == rhsVal) { // Same as old min - if(rhsLoc < parent::loc.device[i]) { // if same, only overwrite if earlier - if(rhsVal == atm.load()) { - parent::loc.device[i] = rhsLoc; - } - } - } else { - if(rhsVal == atm.load()) { - parent::loc.device[i] = rhsLoc; - } - } - } - return *this; -#else - parent::reduce(rhsVal, rhsLoc); - return *this; -#endif - } - - //! enable minloc() for ReduceMinLoc -- alias for reduce() - const self &minloc(T rhsVal, IndexType rhsLoc) const - { -#ifdef __SYCL_DEVICE_ONLY__ - // TODO: Race condition currently - auto i = 0;//__spirv::initLocalInvocationId<1, cl::sycl::id<1>>()[0]; - auto atm = cl::sycl::ext::oneapi::atomic_ref(parent::val.device[i]); - auto oldMin = atm.fetch_min(rhsVal); - if(oldMin >= rhsVal) { // New min or Same min - if(oldMin == rhsVal) { // Same as old min - if(rhsLoc < parent::loc.device[i]) { // if same, only overwrite if earlier - if(rhsVal == atm.load()) { - parent::loc.device[i] = rhsLoc; - } - } - } else { - if(rhsVal == atm.load()) { - parent::loc.device[i] = rhsLoc; - } - } - } - return *this; -#else - parent::reduce(rhsVal, rhsLoc); - return *this; -#endif - } -}; - - -//! specialization of ReduceMaxLoc for omp_target_reduce -template -class ReduceMaxLoc - : public TargetReduceLoc, T, IndexType> -{ -public: - - using self = ReduceMaxLoc; - using parent = - TargetReduceLoc, T, IndexType>; - using parent::parent; - - //! enable maxloc() for ReduceMaxLoc -- alias for reduce() - self &maxloc(T rhsVal, IndexType rhsLoc) - { -#ifdef __SYCL_DEVICE_ONLY__ - // TODO: Race condition currently - auto i = 0;//__spirv::initLocalInvocationId<1, cl::sycl::id<1>>()[0]; - auto atm = cl::sycl::ext::oneapi::atomic_ref(parent::val.device[i]); - auto oldMin = atm.fetch_max(rhsVal); - if(oldMin <= rhsVal) { // New min or Same min - if(oldMin == rhsVal) { // Same as old min - if(rhsLoc < parent::loc.device[i]) { // if same, only overwrite if earlier - if(rhsVal == atm.load()) { - parent::loc.device[i] = rhsLoc; - } - } - } else { - if(rhsVal == atm.load()) { - parent::loc.device[i] = rhsLoc; - } - } - } - return *this; -#else - parent::reduce(rhsVal, rhsLoc); - return *this; -#endif - } - - //! enable maxloc() for ReduceMaxLoc -- alias for reduce() - const self &maxloc(T rhsVal, IndexType rhsLoc) const - { -#ifdef __SYCL_DEVICE_ONLY__ - // TODO: Race condition currently - auto i = 0;//__spirv::initLocalInvocationId<1, cl::sycl::id<1>>()[0]; - auto atm = cl::sycl::ext::oneapi::atomic_ref(parent::val.device[i]); - auto oldMin = atm.fetch_max(rhsVal); - if(oldMin <= rhsVal) { // New min or Same min - if(oldMin == rhsVal) { // Same as old min - if(rhsLoc < parent::loc.device[i]) { // if same, only overwrite if earlier - if(rhsVal == atm.load()) { - parent::loc.device[i] = rhsLoc; - } - } - } else { - if(rhsVal == atm.load()) { - parent::loc.device[i] = rhsLoc; - } - } - } - return *this; -#else - parent::reduce(rhsVal, rhsLoc); - return *this; -#endif - } -}; - - } // namespace RAJA #endif // closing endif for RAJA_ENABLE_SYCL guard From d83c79fffc02bfa832b0b3647a4979f310aafb75 Mon Sep 17 00:00:00 2001 From: Brian Homerding Date: Tue, 29 Aug 2023 13:28:51 +0000 Subject: [PATCH 026/193] Remove debugging prints --- include/RAJA/policy/sycl/params/reduce.hpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/RAJA/policy/sycl/params/reduce.hpp b/include/RAJA/policy/sycl/params/reduce.hpp index 33f544f770..1b90965da6 100644 --- a/include/RAJA/policy/sycl/params/reduce.hpp +++ b/include/RAJA/policy/sycl/params/reduce.hpp @@ -13,7 +13,6 @@ namespace detail { template camp::concepts::enable_if< type_traits::is_sycl_policy > init(Reducer& red) { -// std::cout << "BRIAN: setting to " << OP::identity() << '\n'; red.val = OP::identity(); } @@ -22,17 +21,13 @@ namespace detail { camp::concepts::enable_if< type_traits::is_sycl_policy > SYCL_EXTERNAL combine(Reducer& out, const Reducer& in) { -// std::cout << "BRIAN: combining " << out.val << " with " << in.val << '\n'; out.val = OP{}(out.val, in.val); -// out.val = OP{}(in.val); } // Resolve template camp::concepts::enable_if< type_traits::is_sycl_policy > resolve(Reducer& red) { - - std::cout << "BRIAN: resolving " << red.val << " with " << *red.target << '\n'; *red.target = OP{}(red.val, *red.target); } From 59317ddaf2313d13996ece735b483add70814d15 Mon Sep 17 00:00:00 2001 From: Brian Homerding Date: Wed, 30 Aug 2023 16:20:55 +0000 Subject: [PATCH 027/193] Update Intel SYCL Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 64939607b9..1c3ef7096b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -108,7 +108,7 @@ RUN . /opt/spack/share/spack/setup-env.sh && export LD_LIBRARY_PATH=/opt/view/li ## make -j 6 && \ ## cd .. && rm -rf build -FROM ghcr.io/rse-ops/intel-ubuntu-22.04:intel-2022.1.0 AS sycl +FROM ghcr.io/rse-ops/intel-ubuntu-22.04:intel-2023.2.1 AS sycl ENV GTEST_COLOR=1 COPY . /home/raja/workspace WORKDIR /home/raja/workspace/build From d82c9a1f2807bde2f7dcde5018811ecffb174e0d Mon Sep 17 00:00:00 2001 From: gberg617 Date: Wed, 28 Jun 2023 14:28:54 -0700 Subject: [PATCH 028/193] Added IndexLayout --- include/RAJA/RAJA.hpp | 1 + include/RAJA/util/IndexLayout.hpp | 132 ++++++++++++++++ include/RAJA/util/View.hpp | 8 + test/unit/view-layout/CMakeLists.txt | 4 + test/unit/view-layout/test-indexlayout.cpp | 172 +++++++++++++++++++++ 5 files changed, 317 insertions(+) create mode 100644 include/RAJA/util/IndexLayout.hpp create mode 100644 test/unit/view-layout/test-indexlayout.cpp diff --git a/include/RAJA/RAJA.hpp b/include/RAJA/RAJA.hpp index 7c5484c922..87279fae50 100644 --- a/include/RAJA/RAJA.hpp +++ b/include/RAJA/RAJA.hpp @@ -123,6 +123,7 @@ #include "RAJA/util/OffsetLayout.hpp" #include "RAJA/util/PermutedLayout.hpp" #include "RAJA/util/StaticLayout.hpp" +#include "RAJA/util/IndexLayout.hpp" #include "RAJA/util/View.hpp" diff --git a/include/RAJA/util/IndexLayout.hpp b/include/RAJA/util/IndexLayout.hpp new file mode 100644 index 0000000000..af957aa85b --- /dev/null +++ b/include/RAJA/util/IndexLayout.hpp @@ -0,0 +1,132 @@ +/*! + ****************************************************************************** + * + * \file + * + * \brief RAJA header file defining the IndexLayout class and IndexList classes. + * + ****************************************************************************** + */ + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) 2016-23, Lawrence Livermore National Security, LLC +// and RAJA project contributors. See the RAJA/LICENSE file for details. +// +// SPDX-License-Identifier: (BSD-3-Clause) +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + +#ifndef RAJA_INDEXLAYOUT_HPP +#define RAJA_INDEXLAYOUT_HPP + +#include "RAJA/util/Layout.hpp" + +namespace RAJA +{ + +template +struct ConditionalIndexList { + + RAJA_INLINE constexpr ConditionalIndexList(IdxLin* index_list_in) : + index_list(index_list_in){} + + IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr get(const IdxLin idx) const { + if (index_list) return index_list[idx]; + else return idx; + } + + IdxLin* index_list; +}; + +template +struct IndexList { + + RAJA_INLINE constexpr IndexList(IdxLin* index_list_in) : + index_list(index_list_in){} + + IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr get(const IdxLin idx) const {return index_list[idx];} + + IdxLin* index_list; +}; + +template +struct DirectIndex { + + RAJA_INLINE constexpr DirectIndex() {} + + IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr get(const IdxLin idx) const {return idx;} + +}; + +namespace internal +{ + +template +struct IndexLayout_impl; + +template +struct IndexLayout_impl, IdxLin, IndexTypes...> { + using IndexRange = camp::idx_seq; + using IndexLinear = IdxLin; + using Base = RAJA::detail::LayoutBase_impl; + Base base_; + + static constexpr size_t n_dims = sizeof...(RangeInts); + + template + constexpr RAJA_INLINE IndexLayout_impl( + camp::tuple index_tuple_in, + Types... ns) + : base_{(ns)...}, + tuple(index_tuple_in) + { + } + + template + RAJA_INLINE RAJA_HOST_DEVICE constexpr IdxLin operator()( + Indices... indices) const + { + return sum( + (base_.strides[RangeInts] * camp::get(tuple).get(indices))...); + } + + camp::tuple tuple; + +}; + +} // namespace internal + + +template +struct IndexLayout + : public internal::IndexLayout_impl, IdxLin, IndexTypes...> { + using Base = + internal::IndexLayout_impl, IdxLin, IndexTypes...>; + + using internal::IndexLayout_impl, + IdxLin, IndexTypes...>::IndexLayout_impl; + + constexpr RAJA_INLINE RAJA_HOST_DEVICE IndexLayout( + const internal::IndexLayout_impl, IdxLin, IndexTypes...>& + rhs) + : Base{rhs} + { + } + +}; + +template +auto make_index_tuple(IndexTypes... it) -> camp::tuple { + return camp::tuple(it...); +} + +template +auto make_index_layout( + camp::tuple index_tuple_in, + Types... ns) -> IndexLayout { + static_assert(sizeof...(Types) == sizeof...(IndexTypes), ""); + return IndexLayout(index_tuple_in, ns...); +} + +} + +#endif \ No newline at end of file diff --git a/include/RAJA/util/View.hpp b/include/RAJA/util/View.hpp index e0a505e689..04147be6d0 100644 --- a/include/RAJA/util/View.hpp +++ b/include/RAJA/util/View.hpp @@ -24,6 +24,7 @@ #include "RAJA/pattern/atomic.hpp" +#include "RAJA/util/IndexLayout.hpp" #include "RAJA/util/Layout.hpp" #include "RAJA/util/OffsetLayout.hpp" #include "RAJA/util/TypedViewBase.hpp" @@ -69,6 +70,13 @@ RAJA_INLINE View > make_view( return View >(ptr, 1); } +template +RAJA_INLINE View > make_index_view( + ValueType *ptr, IndexLayout index_layout) +{ + return View >(ptr, index_layout); +} + // select certain indices from a tuple, given a curated index sequence // returns linear index of layout(ar...) diff --git a/test/unit/view-layout/CMakeLists.txt b/test/unit/view-layout/CMakeLists.txt index a1823f2e5e..7764974547 100644 --- a/test/unit/view-layout/CMakeLists.txt +++ b/test/unit/view-layout/CMakeLists.txt @@ -24,3 +24,7 @@ raja_add_test( raja_add_test( NAME test-multiview SOURCES test-multiview.cpp) + +raja_add_test( + NAME test-indexlayout + SOURCES test-indexlayout.cpp) diff --git a/test/unit/view-layout/test-indexlayout.cpp b/test/unit/view-layout/test-indexlayout.cpp new file mode 100644 index 0000000000..33fad7b1fd --- /dev/null +++ b/test/unit/view-layout/test-indexlayout.cpp @@ -0,0 +1,172 @@ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) 2016-23, Lawrence Livermore National Security, LLC +// and RAJA project contributors. See the RAJA/LICENSE file for details. +// +// SPDX-License-Identifier: (BSD-3-Clause) +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + +#include +#include "RAJA/util/types.hpp" +#include "RAJA_test-base.hpp" + +using namespace RAJA; + +TEST(IndexLayout, IndexList1D) { + + Index_type arr[3] = {1,2,3}; + + auto index_tuple = make_index_tuple(IndexList<>(&arr[0])); + auto index_layout = make_index_layout(index_tuple, 3); + + EXPECT_EQ(index_layout(0), 1); + EXPECT_EQ(index_layout(1), 2); + EXPECT_EQ(index_layout(2), 3); + +} + +TEST(IndexLayout, IndexList1DSubsetOfLayout) { + + Index_type arr[3] = {2,3,4}; + + auto index_tuple = make_index_tuple(IndexList<>(&arr[0])); + auto index_layout = make_index_layout(index_tuple, 5); + + EXPECT_EQ(index_layout(0), 2); + EXPECT_EQ(index_layout(1), 3); + EXPECT_EQ(index_layout(2), 4); + +} + + +TEST(IndexLayout, ExtractTwoIndices2DLayoutAxis0) { + + Index_type arr[2] = {1,2}; + + auto index_tuple = make_index_tuple(IndexList<>(&arr[0]), DirectIndex<>()); + auto index_layout = make_index_layout(index_tuple, 3, 10); + + for (int i = 0; i < 10; i++ ) { + EXPECT_EQ(index_layout(0,i), i+10); + EXPECT_EQ(index_layout(1,i), i+20); + } + +} + +TEST(IndexLayout, ExtractTwoIndices2DLayoutAxis1) { + + Index_type arr[2] = {9,5}; + + auto index_tuple = make_index_tuple(DirectIndex<>(), IndexList<>(&arr[0])); + auto index_layout = make_index_layout(index_tuple, 3, 10); + + EXPECT_EQ(index_layout(0,0), 9); + EXPECT_EQ(index_layout(0,1), 5); + EXPECT_EQ(index_layout(1,0), 19); + EXPECT_EQ(index_layout(1,1), 15); + EXPECT_EQ(index_layout(2,0), 29); + EXPECT_EQ(index_layout(2,1), 25); + +} + +TEST(IndexLayout, ExtractOneIndex2DLayoutAxis0) { + + Index_type arr[1] = {2}; + + auto index_tuple = make_index_tuple(IndexList<>(&arr[0]), DirectIndex<>()); + auto index_layout = make_index_layout(index_tuple, 3, 3); + + EXPECT_EQ(index_layout(0,0), 6); + EXPECT_EQ(index_layout(0,1), 7); + EXPECT_EQ(index_layout(0,2), 8); + +} + +TEST(IndexLayout, IndexList2DLayoutExtractOneIndex) { + + Index_type arr[1] = {2}; + + auto index_tuple = make_index_tuple(DirectIndex<>(), IndexList<>(&arr[0])); + auto index_layout = make_index_layout(index_tuple, 3, 3); + + EXPECT_EQ(index_layout(0,0), 2); + EXPECT_EQ(index_layout(1,0), 5); + EXPECT_EQ(index_layout(2,0), 8); + +} + +TEST(IndexLayout, ConditionalIndexListNullPtr) { + + Index_type* arr_ptr = nullptr; + + auto index_tuple = make_index_tuple(ConditionalIndexList<>(arr_ptr)); + auto index_layout = make_index_layout(index_tuple, 3); + + EXPECT_EQ(index_layout(0), 0); + EXPECT_EQ(index_layout(1), 1); + EXPECT_EQ(index_layout(2), 2); +} + +TEST(IndexLayout, View1DLayout) +{ + Index_type data[5] = {5,10,15,20,25}; + Index_type index_list[3] = {4,2,3}; + + auto index_tuple = make_index_tuple(IndexList<>(&index_list[0])); + auto index_layout = make_index_layout(index_tuple, 5); + + auto view = make_index_view(&data[0], index_layout); + + EXPECT_EQ(view(0), 25); + EXPECT_EQ(view(1), 15); + EXPECT_EQ(view(2), 20); + +} + +TEST(IndexLayout, View2DLayout) +{ + Index_type data[2][3]; + + for (int i = 0; i < 2; i ++ ) + for (int j = 0; j < 3; j ++ ) + data[i][j] = i*j; + + Index_type index_list[2] = {1,2}; + + auto index_tuple = make_index_tuple(DirectIndex<>(), IndexList<>(&index_list[0])); + auto index_layout = make_index_layout(index_tuple, 2, 3); + + auto view = make_index_view(&data[0][0], index_layout); + + for (int i = 0; i < 2; i ++ ) + for (int j = 0; j < 2; j ++ ) + EXPECT_EQ(view(i,j), i*(j+1)); + +} + +TEST(IndexLayout, View3DLayout) +{ + Index_type data[2][3][4]; + + for (int i = 0; i < 2; i ++ ) + for (int j = 0; j < 3; j ++ ) + for (int k = 0; k < 4; k ++ ) + data[i][j][k] = i*j*k; + + Index_type index_list_j[2] = {1,2}; + Index_type index_list_k[2] = {2,3}; + + auto index_tuple = make_index_tuple(DirectIndex<>(), + IndexList<>(&index_list_j[0]), + IndexList<>(&index_list_k[0])); + + auto index_layout = make_index_layout(index_tuple, 2, 3, 4); + + auto view = make_index_view(&data[0][0][0], index_layout); + + for (int i = 0; i < 2; i ++ ) + for (int j = 0; j < 2; j ++ ) + for (int k = 0; k < 2; k ++ ) + EXPECT_EQ(view(i,j,k), i*(j+1)*(k+2)); + +} + From 74419b617a889d1847b30af49bf3575081eebc23 Mon Sep 17 00:00:00 2001 From: gberg617 Date: Wed, 9 Aug 2023 10:46:19 -0700 Subject: [PATCH 029/193] added multiview test with index layout --- test/unit/view-layout/test-indexlayout.cpp | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/unit/view-layout/test-indexlayout.cpp b/test/unit/view-layout/test-indexlayout.cpp index 33fad7b1fd..55c78d48ff 100644 --- a/test/unit/view-layout/test-indexlayout.cpp +++ b/test/unit/view-layout/test-indexlayout.cpp @@ -170,3 +170,29 @@ TEST(IndexLayout, View3DLayout) } +TEST(IndexLayout, MultiView1DLayout) +{ + Index_type data_squared[4]; + Index_type data_cubed[4]; + + for (int i = 0; i < 4; i ++ ) data_squared[i] = i*i; + for (int i = 0; i < 4; i ++ ) data_cubed[i] = i*i*i; + + Index_type* data_array[2]; + data_array[0] = data_squared; + data_array[1] = data_cubed; + + Index_type index_list[2] = {1,2}; + + auto index_tuple = make_index_tuple(IndexList<>(&index_list[0])); + auto index_layout = make_index_layout(index_tuple, 4); + + auto view = MultiView > >(data_array, index_layout); + + for (int i = 0; i < 2; i ++ ) { + EXPECT_EQ(view(0,i), data_squared[i+1]); + EXPECT_EQ(view(1,i), data_cubed[i+1]); + } + +} + From 637493b71ecebf8eafd07d69ad5ace1afd6854b9 Mon Sep 17 00:00:00 2001 From: gberg617 Date: Wed, 9 Aug 2023 10:50:55 -0700 Subject: [PATCH 030/193] fix curly brace formatting --- include/RAJA/util/IndexLayout.hpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/include/RAJA/util/IndexLayout.hpp b/include/RAJA/util/IndexLayout.hpp index af957aa85b..f0130cfa9c 100644 --- a/include/RAJA/util/IndexLayout.hpp +++ b/include/RAJA/util/IndexLayout.hpp @@ -27,9 +27,12 @@ template struct ConditionalIndexList { RAJA_INLINE constexpr ConditionalIndexList(IdxLin* index_list_in) : - index_list(index_list_in){} + index_list(index_list_in) + { + } - IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr get(const IdxLin idx) const { + IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr get(const IdxLin idx) const + { if (index_list) return index_list[idx]; else return idx; } @@ -43,7 +46,10 @@ struct IndexList { RAJA_INLINE constexpr IndexList(IdxLin* index_list_in) : index_list(index_list_in){} - IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr get(const IdxLin idx) const {return index_list[idx];} + IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr get(const IdxLin idx) const + { + return index_list[idx]; + } IdxLin* index_list; }; @@ -51,9 +57,14 @@ struct IndexList { template struct DirectIndex { - RAJA_INLINE constexpr DirectIndex() {} + RAJA_INLINE constexpr DirectIndex() + { + } - IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr get(const IdxLin idx) const {return idx;} + IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr get(const IdxLin idx) const + { + return idx; + } }; @@ -115,18 +126,20 @@ struct IndexLayout }; template -auto make_index_tuple(IndexTypes... it) -> camp::tuple { +auto make_index_tuple(IndexTypes... it) -> camp::tuple +{ return camp::tuple(it...); } template auto make_index_layout( camp::tuple index_tuple_in, - Types... ns) -> IndexLayout { + Types... ns) -> IndexLayout +{ static_assert(sizeof...(Types) == sizeof...(IndexTypes), ""); return IndexLayout(index_tuple_in, ns...); } } -#endif \ No newline at end of file +#endif From 262794c24c38d7b04ea6f6090bf36b7c553b348c Mon Sep 17 00:00:00 2001 From: gberg617 Date: Thu, 24 Aug 2023 15:10:32 -0700 Subject: [PATCH 031/193] added documentation of index layout unit tests --- test/unit/view-layout/test-indexlayout.cpp | 98 ++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/test/unit/view-layout/test-indexlayout.cpp b/test/unit/view-layout/test-indexlayout.cpp index 55c78d48ff..422c04896d 100644 --- a/test/unit/view-layout/test-indexlayout.cpp +++ b/test/unit/view-layout/test-indexlayout.cpp @@ -12,6 +12,9 @@ using namespace RAJA; TEST(IndexLayout, IndexList1D) { + /* + * Construct a 1D index layout with the index list {1,2,3} + */ Index_type arr[3] = {1,2,3}; @@ -25,6 +28,10 @@ TEST(IndexLayout, IndexList1D) { } TEST(IndexLayout, IndexList1DSubsetOfLayout) { + /* + * Construct a 1D index layout of arbitrary size greater than 3 + * with the index list {2,3,4} + */ Index_type arr[3] = {2,3,4}; @@ -39,6 +46,16 @@ TEST(IndexLayout, IndexList1DSubsetOfLayout) { TEST(IndexLayout, ExtractTwoIndices2DLayoutAxis0) { + /* + * Construct a 2D index layout of size 3x10 with + * the index list {1,2} used along the 0-axis and + * the direct index used along the 1-axis + * Examples: + * (index layout index -> regular layout index -> unit stride index) + * index_layout(0,1) -> layout(1,1) -> 11 + * index_layout(0,5) -> layout(1,5) -> 15 + * index_layout(1,7) -> layout(2,7) -> 27 + */ Index_type arr[2] = {1,2}; @@ -53,6 +70,15 @@ TEST(IndexLayout, ExtractTwoIndices2DLayoutAxis0) { } TEST(IndexLayout, ExtractTwoIndices2DLayoutAxis1) { + /* + * Construct a 2D index layout of size 3x10 with + * the direct index used along the 0-axis and + * the index list {9,5} used along the 1-axis + * Examples: + * (index layout index -> regular layout index -> unit stride index) + * index_layout(0,1) -> layout(0,5) -> 5 + * index_layout(2,0) -> layout(2,9) -> 29 + */ Index_type arr[2] = {9,5}; @@ -69,6 +95,15 @@ TEST(IndexLayout, ExtractTwoIndices2DLayoutAxis1) { } TEST(IndexLayout, ExtractOneIndex2DLayoutAxis0) { + /* + * Construct a 2D index layout of size 3x3 with + * the index list {2} used along the 0-axis and + * the direct index used along the 1-axis + * Examples: + * (index layout index -> regular layout index -> unit stride index) + * index_layout(0,1) -> layout(2,1) -> 7 + * index_layout(0,2) -> layout(2,2) -> 8 + */ Index_type arr[1] = {2}; @@ -82,6 +117,15 @@ TEST(IndexLayout, ExtractOneIndex2DLayoutAxis0) { } TEST(IndexLayout, IndexList2DLayoutExtractOneIndex) { + /* + * Construct a 2D index layout of size 3x3 with + * the direct index used along the 0-axis and + * the index list {2} used along the 1-axis + * Examples: + * (index layout index -> regular layout index -> unit stride index) + * index_layout(1,0) -> layout(1,2) -> 5 + * index_layout(2,0) -> layout(2,2) -> 8 + */ Index_type arr[1] = {2}; @@ -95,6 +139,15 @@ TEST(IndexLayout, IndexList2DLayoutExtractOneIndex) { } TEST(IndexLayout, ConditionalIndexListNullPtr) { + /* + * Construct a 1D index layout of size 3 with + * the conditional index list that is a nullptr + * (conditional index lists always evaluate nullptr to regular indexing) + * Examples: + * (index layout index -> regular layout index -> unit stride index) + * index_layout(0) -> layout(0) -> 0 + * index_layout(2) -> layout(2) -> 2 + */ Index_type* arr_ptr = nullptr; @@ -108,6 +161,15 @@ TEST(IndexLayout, ConditionalIndexListNullPtr) { TEST(IndexLayout, View1DLayout) { + /* + * Construct a 1D index layout of size 5 with + * the index list {4,2,3} and pass to a 1D view with the data {5,10,15,20,25} + * Examples: + * (index layout index -> regular layout index -> unit stride index -> view at index) + * index_layout(0) -> layout(4) -> 4 -> 25 + * index_layout(2) -> layout(3) -> 3 -> 20 + */ + Index_type data[5] = {5,10,15,20,25}; Index_type index_list[3] = {4,2,3}; @@ -124,6 +186,18 @@ TEST(IndexLayout, View1DLayout) TEST(IndexLayout, View2DLayout) { + /* + * Construct a 2D index layout of size 2x3 with + * the direct index used along the 0-axis and + * the index list {1,2} used along the 1-axis and + * pass to a 2D view of size 2x3 with the each entry being i*j + * for i,j in [0,2)x[0,3) (e.g. view(1,2) = 1*2, view(0,3) = 0*3, etc..) + * Examples: + * (index layout index -> view index -> view at index) + * index_layout(0,1) -> view(0,2) -> 0 + * index_layout(2,0) -> view(2,1) -> 2 + */ + Index_type data[2][3]; for (int i = 0; i < 2; i ++ ) @@ -145,6 +219,19 @@ TEST(IndexLayout, View2DLayout) TEST(IndexLayout, View3DLayout) { + /* + * Construct a 3D index layout of size 2x3x4 with + * the direct index used along the 0-axis and + * the index list {1,2} used along the 1-axis and + * the index list {2,3} used along the 2-axis and + * pass to a 3D view of size 2x3x4 with the each entry being i*j*k + * for i,j,k in [0,2)x[0,3)x[0,4) (e.g. view(1,2,3) = 1*2*3, view(0,2,2) = 0*2*2, etc..) + * Examples: + * (index layout index -> view index -> view at index) + * index_layout(0,1,0) -> view(0,2,2)-> 0 + * index_layout(2,1,1) -> view(2,2,3)-> 12 + */ + Index_type data[2][3][4]; for (int i = 0; i < 2; i ++ ) @@ -172,6 +259,17 @@ TEST(IndexLayout, View3DLayout) TEST(IndexLayout, MultiView1DLayout) { + /* + * Construct a 1D index layout of size 4 with + * the index list {1,2} and pass to a 1D multiview containing two 1D views of size 4 with + * the first view having each entry be the square of its index (e.g. view(2) = 2*2 = 4) + * and the second view having each entry be the cube of its index (e.g. view(3) = 3*3*3 = 27) + * Examples: + * (index layout index -> mutiview index -> view at index) + * index_layout(0,1) -> view(0,2) -> 4 + * index_layout(1,0) -> view(1,1) -> 1 + */ + Index_type data_squared[4]; Index_type data_cubed[4]; From c987061a83cd008f8b98286e49ae231890bb64a9 Mon Sep 17 00:00:00 2001 From: gberg617 Date: Fri, 25 Aug 2023 16:50:38 -0700 Subject: [PATCH 032/193] various corrections --- include/RAJA/util/IndexLayout.hpp | 24 +++--------- test/unit/view-layout/test-indexlayout.cpp | 44 ++++++++++++++++------ 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/include/RAJA/util/IndexLayout.hpp b/include/RAJA/util/IndexLayout.hpp index f0130cfa9c..b75f97334b 100644 --- a/include/RAJA/util/IndexLayout.hpp +++ b/include/RAJA/util/IndexLayout.hpp @@ -26,42 +26,30 @@ namespace RAJA template struct ConditionalIndexList { - RAJA_INLINE constexpr ConditionalIndexList(IdxLin* index_list_in) : - index_list(index_list_in) - { - } - - IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr get(const IdxLin idx) const + IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr operator()(const IdxLin idx) const { if (index_list) return index_list[idx]; else return idx; } - IdxLin* index_list; + IdxLin* index_list{nullptr}; }; template struct IndexList { - RAJA_INLINE constexpr IndexList(IdxLin* index_list_in) : - index_list(index_list_in){} - - IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr get(const IdxLin idx) const + IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr operator()(const IdxLin idx) const { return index_list[idx]; } - IdxLin* index_list; + IdxLin* index_list{nullptr}; }; template struct DirectIndex { - RAJA_INLINE constexpr DirectIndex() - { - } - - IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr get(const IdxLin idx) const + IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr operator()(const IdxLin idx) const { return idx; } @@ -97,7 +85,7 @@ struct IndexLayout_impl, IdxLin, IndexTypes...> { Indices... indices) const { return sum( - (base_.strides[RangeInts] * camp::get(tuple).get(indices))...); + (base_.strides[RangeInts] * camp::get(tuple)(indices))...); } camp::tuple tuple; diff --git a/test/unit/view-layout/test-indexlayout.cpp b/test/unit/view-layout/test-indexlayout.cpp index 422c04896d..423e675d58 100644 --- a/test/unit/view-layout/test-indexlayout.cpp +++ b/test/unit/view-layout/test-indexlayout.cpp @@ -18,7 +18,7 @@ TEST(IndexLayout, IndexList1D) { Index_type arr[3] = {1,2,3}; - auto index_tuple = make_index_tuple(IndexList<>(&arr[0])); + auto index_tuple = make_index_tuple(IndexList<>{&arr[0]}); auto index_layout = make_index_layout(index_tuple, 3); EXPECT_EQ(index_layout(0), 1); @@ -35,7 +35,7 @@ TEST(IndexLayout, IndexList1DSubsetOfLayout) { Index_type arr[3] = {2,3,4}; - auto index_tuple = make_index_tuple(IndexList<>(&arr[0])); + auto index_tuple = make_index_tuple(IndexList<>{&arr[0]}); auto index_layout = make_index_layout(index_tuple, 5); EXPECT_EQ(index_layout(0), 2); @@ -59,7 +59,7 @@ TEST(IndexLayout, ExtractTwoIndices2DLayoutAxis0) { Index_type arr[2] = {1,2}; - auto index_tuple = make_index_tuple(IndexList<>(&arr[0]), DirectIndex<>()); + auto index_tuple = make_index_tuple(IndexList<>{&arr[0]}, DirectIndex<>()); auto index_layout = make_index_layout(index_tuple, 3, 10); for (int i = 0; i < 10; i++ ) { @@ -82,7 +82,7 @@ TEST(IndexLayout, ExtractTwoIndices2DLayoutAxis1) { Index_type arr[2] = {9,5}; - auto index_tuple = make_index_tuple(DirectIndex<>(), IndexList<>(&arr[0])); + auto index_tuple = make_index_tuple(DirectIndex<>(), IndexList<>{&arr[0]}); auto index_layout = make_index_layout(index_tuple, 3, 10); EXPECT_EQ(index_layout(0,0), 9); @@ -107,7 +107,7 @@ TEST(IndexLayout, ExtractOneIndex2DLayoutAxis0) { Index_type arr[1] = {2}; - auto index_tuple = make_index_tuple(IndexList<>(&arr[0]), DirectIndex<>()); + auto index_tuple = make_index_tuple(IndexList<>{&arr[0]}, DirectIndex<>()); auto index_layout = make_index_layout(index_tuple, 3, 3); EXPECT_EQ(index_layout(0,0), 6); @@ -129,7 +129,7 @@ TEST(IndexLayout, IndexList2DLayoutExtractOneIndex) { Index_type arr[1] = {2}; - auto index_tuple = make_index_tuple(DirectIndex<>(), IndexList<>(&arr[0])); + auto index_tuple = make_index_tuple(DirectIndex<>(), IndexList<>{&arr[0]}); auto index_layout = make_index_layout(index_tuple, 3, 3); EXPECT_EQ(index_layout(0,0), 2); @@ -151,7 +151,7 @@ TEST(IndexLayout, ConditionalIndexListNullPtr) { Index_type* arr_ptr = nullptr; - auto index_tuple = make_index_tuple(ConditionalIndexList<>(arr_ptr)); + auto index_tuple = make_index_tuple(ConditionalIndexList<>{arr_ptr}); auto index_layout = make_index_layout(index_tuple, 3); EXPECT_EQ(index_layout(0), 0); @@ -159,6 +159,26 @@ TEST(IndexLayout, ConditionalIndexListNullPtr) { EXPECT_EQ(index_layout(2), 2); } +TEST(IndexLayout, ConditionalIndexListWithIndexList) { + /* + * Construct a 1D index layout of size 3 with + * the conditional index list that is not a nullptr + * (conditional index lists with index list act the same as IndexList) + * Examples: + * (index layout index -> regular layout index -> unit stride index) + * index_layout(0) -> layout(1) -> 1 + * index_layout(1) -> layout(2) -> 2 + */ + + Index_type arr[2] = {1,2}; + + auto index_tuple = make_index_tuple(ConditionalIndexList<>{&arr[0]}); + auto index_layout = make_index_layout(index_tuple, 3); + + EXPECT_EQ(index_layout(0), 1); + EXPECT_EQ(index_layout(1), 2); +} + TEST(IndexLayout, View1DLayout) { /* @@ -173,7 +193,7 @@ TEST(IndexLayout, View1DLayout) Index_type data[5] = {5,10,15,20,25}; Index_type index_list[3] = {4,2,3}; - auto index_tuple = make_index_tuple(IndexList<>(&index_list[0])); + auto index_tuple = make_index_tuple(IndexList<>{&index_list[0]}); auto index_layout = make_index_layout(index_tuple, 5); auto view = make_index_view(&data[0], index_layout); @@ -206,7 +226,7 @@ TEST(IndexLayout, View2DLayout) Index_type index_list[2] = {1,2}; - auto index_tuple = make_index_tuple(DirectIndex<>(), IndexList<>(&index_list[0])); + auto index_tuple = make_index_tuple(DirectIndex<>(), IndexList<>{&index_list[0]}); auto index_layout = make_index_layout(index_tuple, 2, 3); auto view = make_index_view(&data[0][0], index_layout); @@ -243,8 +263,8 @@ TEST(IndexLayout, View3DLayout) Index_type index_list_k[2] = {2,3}; auto index_tuple = make_index_tuple(DirectIndex<>(), - IndexList<>(&index_list_j[0]), - IndexList<>(&index_list_k[0])); + IndexList<>{&index_list_j[0]}, + IndexList<>{&index_list_k[0]}); auto index_layout = make_index_layout(index_tuple, 2, 3, 4); @@ -282,7 +302,7 @@ TEST(IndexLayout, MultiView1DLayout) Index_type index_list[2] = {1,2}; - auto index_tuple = make_index_tuple(IndexList<>(&index_list[0])); + auto index_tuple = make_index_tuple(IndexList<>{&index_list[0]}); auto index_layout = make_index_layout(index_tuple, 4); auto view = MultiView > >(data_array, index_layout); From 56e1df403b76c363e63b0be8f1f42a2abbc4fd91 Mon Sep 17 00:00:00 2001 From: gberg617 Date: Mon, 28 Aug 2023 10:39:40 -0700 Subject: [PATCH 033/193] added clarification of unit test --- test/unit/view-layout/test-indexlayout.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/unit/view-layout/test-indexlayout.cpp b/test/unit/view-layout/test-indexlayout.cpp index 423e675d58..c80dfc5b4c 100644 --- a/test/unit/view-layout/test-indexlayout.cpp +++ b/test/unit/view-layout/test-indexlayout.cpp @@ -30,7 +30,9 @@ TEST(IndexLayout, IndexList1D) { TEST(IndexLayout, IndexList1DSubsetOfLayout) { /* * Construct a 1D index layout of arbitrary size greater than 3 - * with the index list {2,3,4} + * with the index list {2,3,4}. + * The purpose of this test is to demonstrate the use case where + * the index list contains a subset of its index layout */ Index_type arr[3] = {2,3,4}; From d7846c08597fc89d7b856ed87679e6ab1e98c91d Mon Sep 17 00:00:00 2001 From: gberg617 Date: Tue, 29 Aug 2023 13:39:44 -0700 Subject: [PATCH 034/193] moved member data to the top of classes and added comments for each method/class --- include/RAJA/util/IndexLayout.hpp | 53 +++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/include/RAJA/util/IndexLayout.hpp b/include/RAJA/util/IndexLayout.hpp index b75f97334b..9e7f4ccd1d 100644 --- a/include/RAJA/util/IndexLayout.hpp +++ b/include/RAJA/util/IndexLayout.hpp @@ -23,35 +23,52 @@ namespace RAJA { +/*! +* DirectIndex struct contains call operator that returns the same index that was input +* +*/ template -struct ConditionalIndexList { +struct DirectIndex { IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr operator()(const IdxLin idx) const { - if (index_list) return index_list[idx]; - else return idx; + return idx; } - IdxLin* index_list{nullptr}; -}; +}; +/*! +* IndexList struct stores a pointer to an array containing the index list. +* Its call operator returns the entry at the input location (idx) of its index list. +* +*/ template struct IndexList { + IdxLin* index_list{nullptr}; + IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr operator()(const IdxLin idx) const { return index_list[idx]; } - IdxLin* index_list{nullptr}; }; +/*! +* ConditionalIndexList struct stores a pointer to an array containing the index list. +* Its call operator returns the same index that was input if the index list is a nullptr, +* or otherwise returns the entry at the input location (idx) of its index list. +* +*/ template -struct DirectIndex { +struct ConditionalIndexList { + + IdxLin* index_list{nullptr}; IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr operator()(const IdxLin idx) const { - return idx; + if (index_list) return index_list[idx]; + else return idx; } }; @@ -71,6 +88,8 @@ struct IndexLayout_impl, IdxLin, IndexTypes...> { static constexpr size_t n_dims = sizeof...(RangeInts); + camp::tuple tuple; + template constexpr RAJA_INLINE IndexLayout_impl( camp::tuple index_tuple_in, @@ -80,6 +99,13 @@ struct IndexLayout_impl, IdxLin, IndexTypes...> { { } + /*! + * Computes a linear space index from entries of index lists stored in tuple. + * This is accomplished through the inner product of the strides and the + * entry in the index list along each dimension. + * @param indices Indices in the n-dimensional space of this layout + * @return Linear space index. + */ template RAJA_INLINE RAJA_HOST_DEVICE constexpr IdxLin operator()( Indices... indices) const @@ -88,8 +114,6 @@ struct IndexLayout_impl, IdxLin, IndexTypes...> { (base_.strides[RangeInts] * camp::get(tuple)(indices))...); } - camp::tuple tuple; - }; } // namespace internal @@ -113,12 +137,21 @@ struct IndexLayout }; +/*! + * creates of a camp::tuple of index types + * (such as DirectIndex, IndexList, or ConditionalIndexList) + * + */ template auto make_index_tuple(IndexTypes... it) -> camp::tuple { return camp::tuple(it...); } +/*! + * creates an index layout based on the input camp::tuple of index types + * + */ template auto make_index_layout( camp::tuple index_tuple_in, From b2cd657818fd0cf3589b72cf19de24c63d2f7659 Mon Sep 17 00:00:00 2001 From: Rich Hornung Date: Fri, 1 Sep 2023 15:42:30 -0700 Subject: [PATCH 035/193] Clean up and update CI descriptions --- docs/sphinx/dev_guide/ci.rst | 264 ++++++------------ .../dev_guide/figures/RAJA-Gitlab-Files.png | Bin 265270 -> 263039 bytes 2 files changed, 88 insertions(+), 176 deletions(-) diff --git a/docs/sphinx/dev_guide/ci.rst b/docs/sphinx/dev_guide/ci.rst index d3341878b2..9f57f6650f 100644 --- a/docs/sphinx/dev_guide/ci.rst +++ b/docs/sphinx/dev_guide/ci.rst @@ -17,23 +17,20 @@ Continuous Integration (CI) Testing viewed by clicking the appropriate link in the **checks** section of a GitHub pull request. -The RAJA project uses to CI tools to run its tests: +The RAJA project uses two CI tools to run tests: * **Azure Pipelines** runs builds and tests for Linux, Windows, and MacOS - environments using recent versions of various compilers. While we do some - GPU builds on Azure, RAJA tests are only run for CPU-only builds. Docker - container images we use for the Linux testing are maintained in the - `RSE Ops Project `_. Please see - the `RAJA Azure DevOps `_ project to learn - more about our testing there. + environments using compilers in container image maintained in the + `RSE Ops Project `_. + While we do some GPU builds on Azure, RAJA tests are only run for CPU-only + builds. The current set of builds run on Azure can be seen by looking at + the ``RAJA/azure-pipelines.yml`` and ``RAJA/Dockerfile`` files. * **GitLab** instance in the Collaboration Zone (CZ) of the Livermore - Computing (LC) Center run builds and tests on LC platforms using + Computing (LC) Center runs builds and tests on LC platforms using software stacks (compilers, etc.) important to many RAJA user applications. - Execution of LC GitLab CI on LC resources has restrictions, which are - described below. If you have access to LC platforms, you can access - information about - `LC GitLab CI `_ + GitLab build configurations are more complex than Azure; they will be + described in detail in :ref:`gitlab_ci-label`. These tools integrate with the RAJA GitHub project and automatically run RAJA builds and tests when a PR is created and when changes are pushed to a PR @@ -54,38 +51,39 @@ machine and compiler environments important to RAJA user applications at LLNL. Constraints ----------- -How projects can run GitLab CI on LC platforms is constrained by LC -security policies. The policies require that all members of a GitHub project -be members of the LLNL GitHub organization and have two-factor authentication +LC security policies constrain how projects can run GitLab CI on LC platforms. +Specifically, policies require that all members of a GitHub project be members +of the LLNL GitHub organization and have two-factor authentication enabled on their GitHub accounts. When these requirements are satisfied, GitLab on the LC CZ can mirror a GitHub project and trigger GitLab CI when changes are made to the GitHub repo. If the requirements are not met, LC -GitLab CI checks will not be run for a project. This implies, for example, -that GitLab CI will not run for a PR made on an LLNL organization project -from a fork of the project repo by someone not in the LLNL organization. +GitLab CI checks will not run. This implies, for example, that GitLab CI will +not run an LLNL organization project for a PR made from a fork of the project +repo by someone not in the LLNL organization. For a compliant LLNL GitHub project like RAJA, auto-mirroring of the -GitHub repo on LC GitLab is done every 30 minutes or so, triggering builds and +GitHub repo to LC GitLab is done every 30 minutes or so, triggering builds and tests on new changes pushed to the RAJA GitHub project. If you have access to LC platforms, you can learn more about `LC GitLab mirroring `_. -.. note:: **GitLab CI will not run for a PR branch on a fork of the RAJA repo.** - We manually manage contributions made on a fork of the RAJA repo - using the procedure described in :ref:`contributing-label`. +.. important:: **GitLab CI will not run for a PR branch on a fork of the RAJA + repo.** The RAJA project manually manages contributions made + on forks of the RAJA repo using the procedure described in + :ref:`contributing-label`. .. _gitlab_ci_workflow-label: GitLab CI (LC) Testing Workflow -------------------------------------- -The figure below shows the high-level steps in the RAJA GitLab CI testing -process. The main steps, which we will discuss in more detail later, are: +The figure below shows the sequence of steps in the RAJA GitLab CI testing +process. More details about these steps will appear in the in later sections: #. A *mirror* of the RAJA GitHub repo is updated in the RAJA LC CZ GitLab - project automatically every 30 minutes approximately. + project automatically (approximately every 30 minutes). .. note:: There may be a delay in the mirroring, since it is not - synhronous with changes to the RAJA GitHub project. + synchronous with changes to the RAJA GitHub project. #. GitLab launches CI test pipelines for any new changes made to the ``develop`` or ``main`` branches or any non-fork PR branch. While @@ -104,7 +102,7 @@ process. The main steps, which we will discuss in more detail later, are: #. When test pipelines complete, results are reported to GitLab. - #. Lastly, GitLab reports to GitHub to show the status of checks there. + #. Lastly, GitLab reports to GitHub indicating the the status of checks there. .. figure:: ./figures/RAJA-Gitlab-Workflow2.png @@ -130,23 +128,24 @@ collaboratively with other projects. These include * `Spack `_, a multi-platform package manager that builds and installs HPC software stacks. * `Uberenv `_, a Python script - that helps to automate the use of Spack and other tools for building + that helps to simplify the workflow of Spack and other tools for building third-party dependencies. Uberenv is a submodule in RAJA that lives in ``RAJA/scripts/uberenv/``. * `RADIUSS Spack Configs `_, a collection of Spack compiler and package configurations used by Spack - to generate host-config files for CMake. The build configurations are + to generate build configurations. The build configurations are specific to LLNL LC platforms. Spack packages for multiple projects are maintained in this project. RADIUSS Spack Configs is a submodule in RAJA that lives in ``RAJA/scripts/radiuss-spack-configs/``. The relationships among these dependencies in a project that uses them is -illustrated in the `RADIUSS Shared CI User Guide `_. The guide also describes +described in the `RADIUSS Shared CI User Guide `_ along with information about how the framework works and how to set up a project to use it. -.. important:: The RAJA Spack package is maintained in the `RADIUSS Spack Configs `_ project. When it is updated, it is pushed to the Spack repo on GitHub. +.. important:: The RAJA Spack package is maintained in the `RADIUSS Spack Configs `_ project. After packages are +updated there, they are pushed to the Spack repo on GitHub via a pull request. -In the rest of the this section, we describe files in the RAJA repo that are +The remainder of this section describes files in the RAJA repo that are used to configure and customize the shared CI framework specifically for the RAJA project. @@ -162,25 +161,27 @@ support LC GitLab CI testing. The figure shows directories and files in the RAJA repo that support GitLab CI testing. Files in blue are specific to RAJA and are maintained in the - RAJA repo. Red directories and files are in Git submodules that are + RAJA repo. Red directories and files correspond to Git submodules that are shared and maintained with other projects. -Briefly, these files play the following roles in our GitLab CI testing: - - * The ``RAJA/.gitlab-ci.yml`` file is the root file for GitLab CI - configuration. We place jobs is small pipelines described by separate - files that are included by this one. Global variables can also be defined - here. - * The ``.uberenv_config.json`` file defines the Spack version we use, where - Spack packages live, etc. - * Files in the ``RAJA/.gitlab`` directory define test pipelines that RAJA - subscribes to an which are defined in the +Briefly, these files play the following roles in GitLab CI testing: + + * The `RAJA/.gitlab-ci.yml `_ file is the top-level file for GitLab CI configuration. It defines + variables used in all GItLab pipelines such as + GitHub project name and organization, service user account name, version + information for RADIUSS Shared CI project we are using, and + top-level information for triggering build-and-test sub-pipelines. + * The `RAJA/.uberenv_config.json `_ file defines information about Spack such as + Spack version we are using, location of Spack packages, etc. + * The `RAJA/.gitlab `_ + directory contains several files that connect RAJA GitLab pipelines to + shared pipelines defined in the `RADIUSS Shared CI `_ project, - as well as RAJA-specific jobs, and any job customization that we use, - such as job time limits, etc. These files are customizations of templates - provided by `RADIUSS Shared CI `_. - * The ``RAJA/scripts/gitlab/build_and_test.sh`` file defines the RAJA build - and test process and commands that are run during it. + as well as RAJA-specific jobs and shared job customizations that we use, + such as job time limits, etc. These files are modified from templates + provided by the RADIUSS Shared CI project. + * The `RAJA/scripts/gitlab/build_and_test.sh `_ contains commands that are run + during the RAJA build and test process. In the following sections, we discuss how these files are used in the steps of the RAJA GitLab CI testing process summarized above. @@ -190,39 +191,24 @@ steps of the RAJA GitLab CI testing process summarized above. Launching CI pipelines (step 2) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -In **step 2** of the diagram above, GitLab launches RAJA test pipelines. -The `RAJA/.gitlab-ci.yml `_ file contains high-level testing information that applies to all RAJA -GitLab CI testing pipelines. This includes - - * **GitLab pipeline variables**, such as project name, service user account - name, etc. - - * **High-level pipeline stages** for build and test, multi-project testing, - etc. - - * **Build and test sub-pipelines**. Note that this is where the connection - is made to the RADIUSS Shared CI project (and version on the LC CZ GitLab - instance) and to files in the ``RAJA/.gitlab`` directory that define the - Spack specs for build configurations that are run on each machine on - which RAJA tests are run. - - * **Cross-project test pipelines**, which are triggered when testing - certain RAJA branches, mainly the develop branch. - - * **CI subscribed pipelines**, which are defined in the - RADIUSS Shared CI project. - -.. important:: Variables that define how resources are allocated and job time - limits for LC machines that are used to run RAJA CI are defined - in the ``RAJA/.gilab/custom-jobs-and-variables.yml`` file. +In **step 2** of the diagram above, GitLab launches RAJA test pipelines +starting with the content of the ``RAJA/.gitlab-ci.yml`` file described above. +Most importantly, this file identifies the location of two files +`RAJA/.gitlab/subscribed-pipelines.yml `_ and +`RAJA/.gitlab/custom-jobs-and-variables.yml `_. +The ``subscribed-pipelines.yml`` file connects the RAJA GitLab environment to +the platform and pipelines defined in the RADIUSS Shared CI project. +The ``custom-jobs-and-variables.yml`` file defines how resources are +allocated to run test jobs on various LC platforms and common build +configuration variants for those platforms Each job that is run is defined by a Spack spec in one of two places, depending on whether it is *shared* with other projects or it is specific to RAJA. The shared jobs are defined in files named ``-build-and-test.yml`` in the top-level directory of the `RADIUSS Shared CI Project `_. -RAJA-specific jobs are defined in -``RAJA/.gitlab/-build-and-test-extra.yml`` files. +Overrides (modifications) of those jobs and other RAJA-specific jobs are +defined in ``RAJA/.gitlab/-build-and-test-extra.yml`` files. **Each shared job will be run as-is unless it is overridden** in the RAJA 'extra' file for the corresponding machine. For example, a shared job for the @@ -244,7 +230,7 @@ file as:: extends: .build_and_test_on_ruby In this example, the Spack build spec is the same, but the job is configured -with a timeout limit and number of nodes appropriate for RAJA testing. +with a specific timeout limit and number of nodes appropriate for RAJA testing. .. important:: A shared job override **must use the same job label as the shared job** defined in the RADIUSS Shared CI project. @@ -272,105 +258,31 @@ Running a CI build and test pipeline (steps 3, 4, 5, 6) The `RAJA/scripts/gitlab/build_and_test.sh `_ file defines the steps executed for each build and test pipeline as well as information that will appear in the -log output for each step. - -After some basic set up, the script invokes the -``RAJA/scripts/uberenv/uberenv.py`` Python script that drives Spack to generate -host-config files:: - - ... - - python3 scripts/uberenv/uberenv.py --spec="${spec}" ${prefix_opt} - - ... - -Project specific settings related to which Spack version to use, where -Spack packages live, etc. are located in the +log output for each step. The script "echoes" information to the test logs +indicating what it is doing. Following the echo commands in the file may help +one understand the workflow. + +The details of the various steps in the process may change from time to time. +However, the basic sequence is: + + #. Perform some basic (platform-independent) setup. + #. Invoke the ``RAJA/scripts/uberenv/uberenv.py`` Python script that drives + Spack to generate a host-config file from a given spec **(step 3)**. + #. Run CMake to configure a build space passing the host-config file to it + which contains all CMake variable settings for the configuration. + #. Build RAJA and tests **(step 4)**. + #. Run RAJA tests via ctest **(step 5)**. + #. Export XML test reports for reporting in GitLab **(step 6)**, which is + done by the RADIUSS Shared CI Framework. + #. Perform clean up tasks. + +Recall that RAJA project specific settings defining the Spack version to use, +locations of Spack packages, etc. are located in the `RAJA/.uberenv_config.json `_ file. -The Uberenv Python script invokes Spack to generate a CMake *host-config* -file containing a RAJA build specification **(step 3)**. To generate -a *host-config* file, Spack uses the packages and specs maintained in the -`RADIUSS Spack Configs project -`_, plus RAJA-specific specs -defined in files in the `RAJA/.gitlab `_ directory, as described earlier. - -.. note:: Please see :ref:`spack_host_config-label` for more information about - how to manually generate host-config files and use them for local - debugging. - -After the host-config file is generated, the -``RAJA/scripts/gitlab/build_and_test.sh`` script creates a build space -directory and runs CMake in it, passing the host-config (cache) file. Then, -it builds the RAJA code and tests **(step 4)**:: - - ... - - build_dir="${build_root}/build_${hostconfig//.cmake/}" - install_dir="${build_root}/install_${hostconfig//.cmake/}" - - ... - - date - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - echo "~~~~~ Host-config: ${hostconfig_path}" - echo "~~~~~ Build Dir: ${build_dir}" - echo "~~~~~ Project Dir: ${project_dir}" - echo "~~~~~ Install Dir: ${install_dir}" - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - echo "" - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - echo "~~~~~ Building RAJA" - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - - .. - - rm -rf ${build_dir} 2>/dev/null - mkdir -p ${build_dir} && cd ${build_dir} - - ... - - $cmake_exe \ - -C ${hostconfig_path} \ - -DCMAKE_INSTALL_PREFIX=${install_dir} \ - ${project_dir} - - ... - - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - echo "~~~~~ RAJA Built" - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - date - -Next, it runs the tests **(step 5)**:: - - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - echo "~~~~~ Testing RAJA" - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - - ... - - cd ${build_dir} - - ... - - ctest --output-on-failure -T test 2>&1 | tee tests_output.txt - - ... - - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - echo "~~~~~ RAJA Tests Complete" - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - date - -Lastly, test results are collected in a JUnit XML file that -GitLab uses for reporting the results in its GUI **(step 6)**. This is -done by the -`RADIUSS Shared CI Framework `_ - -The commands shown here intermingle with other commands that emit messages, -timing information for various operations, etc. which appear in a log -file that can be viewed in the GitLab GUI. +Also, recall that to generate a hist-config file, Spack uses packages and +specs in the `RADIUSS Spack Configs project `_ (a RAJA submodule), +plus RAJA-specific specs defined in files in the `RAJA/.gitlab `_ directory, as described earlier. .. _azure_ci-label: @@ -378,15 +290,15 @@ file that can be viewed in the GitLab GUI. Azure Pipelines CI ================== -The Azure Pipelines tool builds and tests for Linux, Windows, and MacOS -environments. While we do builds for CUDA, HIP, and SYCL RAJA back-ends +We use Azure Pipelines to run builds and tests for Linux, Windows, and MacOS +environments. While we do builds for CUDA, HIP, and SYCL RAJA GPU back-ends in the Azure Linux environment, RAJA tests are only run for CPU-only pipelines. Azure Pipelines Testing Workflow -------------------------------- The Azure Pipelines testing workflow for RAJA is much simpler than the GitLab -testing process described above. +testing process described earlier. The test jobs we run for each OS environment are specified in the `RAJA/azure-pipelines.yml `_ file. This file defines the job steps, commands, diff --git a/docs/sphinx/dev_guide/figures/RAJA-Gitlab-Files.png b/docs/sphinx/dev_guide/figures/RAJA-Gitlab-Files.png index 5bd3dde5a59ca8e0d8677d42be4f0336f95ec2d2..69e72b2367e4fce1a974b802dcf1f4bd7c3b8f74 100644 GIT binary patch delta 20877 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 delta 23162 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 Date: Thu, 7 Sep 2023 11:38:52 -0700 Subject: [PATCH 036/193] Updating and cleaning up docs --- .../sphinx/dev_guide/build_configurations.rst | 9 ++- docs/sphinx/dev_guide/ci_tasks.rst | 69 ++++++++++++------- 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/docs/sphinx/dev_guide/build_configurations.rst b/docs/sphinx/dev_guide/build_configurations.rst index d43048ac98..c4232cef1f 100644 --- a/docs/sphinx/dev_guide/build_configurations.rst +++ b/docs/sphinx/dev_guide/build_configurations.rst @@ -152,7 +152,14 @@ Generating a host-config file ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To generate a host-config file for a desired configuration, run the -``uberenv.py`` python script from the top-level RAJA directory. For example, +``uberenv.py`` python script from the top-level RAJA directory. + +.. important:: **Do not** run the ``uberenv.py`` script, which invokes Spack + in your LC home directory since Spack uses a lot of disk space. + Running Spack in your home directory may cause you to exceed + your LC disk space quota. + +For example, .. code-block:: bash diff --git a/docs/sphinx/dev_guide/ci_tasks.rst b/docs/sphinx/dev_guide/ci_tasks.rst index ac39b40453..da7b47223f 100644 --- a/docs/sphinx/dev_guide/ci_tasks.rst +++ b/docs/sphinx/dev_guide/ci_tasks.rst @@ -21,8 +21,10 @@ how to perform common RAJA CI testing maintenance tasks. GitLab CI Tasks ================= -The tasks in this section apply to GitLab CI testing on Livermore -Computing (LC) platforms. +The tasks in this section apply to GitLab CI testing on Livermore +Computing (LC) platforms. LC folks and others maintain Confluence pages +with a lot of useful information for setting up and maintaining GitLab CI +for a project, mirroring a GitHub to GitLab, etc. Please refer to `LC GitLab CI `_ for such information. Changing build and test configurations ---------------------------------------- @@ -36,25 +38,30 @@ Remove a configuration To remove a RAJA-specific test configuration, simply delete the entry for it in the ``RAJA/.gitlab/-build-and-test-extra.yml`` file where it is -defined. +defined. Here, ``MACHINE`` is the name of an LC platform where GitLab CI is +run. To remove a shared configuration, it must be removed from the appropriate ``-build-and-test.yml`` file in the `RADIUSS Shared CI `_ project. Create a branch there, remove the job entry, and create a pull request. +.. important:: The RADIUSS Shared CI project is used by several other projects. + When changing a shared configuration file, please make sure the + change is OK with those other projects. + Add a configuration ^^^^^^^^^^^^^^^^^^^^^^^^^^ -To add a RAJA-specific test configuration, add the entry for it to the +To add a RAJA-specific test configuration, add an entry for it to the ``RAJA/.gitlab/-build-and-test-extra.yml`` file, where ``MACHINE`` is the name of the LC platform where it will be run. When adding a -RAJA-specific test configuration, it is important to note two -items that must be set properly: +test configuration, it is important to note two items that must be +specified properly: - * the unique **job label**, which identifies it in the machine configuration + * A unique **job label**, which identifies it in the machine configuration file and also on a web page for a GitLab CI pipeline - * the build **Spack spec**, which identifies the compiler and version, + * A build **Spack spec**, which identifies the compiler and version, compiler flags, build options, etc. For example, an entry for a build using the clang 12.0.1 compiler with CUDA @@ -67,22 +74,26 @@ For example, an entry for a build using the clang 12.0.1 compiler with CUDA SPEC: " ~shared +openmp +tests +cuda cuda_arch=70 %clang@12.0.1 ^cuda@11.5.0" extends: .build_and_test_on_lassen -Here, we enable OpenMP and CUDA, both of which must be enabled to use them, -and specify the CUDA target architecture 'sm_70'. +Here, we enable OpenMP and CUDA, both of which must be enabled to test those +RAJA back-ends, and specify the CUDA target architecture 'sm_70'. To add a shared configuration, it must be added to the appropriate ``-build-and-test.yml`` file in the `RADIUSS Shared CI `_ project. Create a branch there, add the job entry, and create a pull request. +.. important:: The RADIUSS Shared CI project is used by several other projects. + When changing a shared configuration file, please make sure the + change is OK with those other projects. + Modifying a configuration ^^^^^^^^^^^^^^^^^^^^^^^^^^ To change an existing configuration, change the relevant information in the -configuration, such variant(s) or target compute architecture, in the -appropriate +configuration in the appropriate ``RAJA/.gitlab/-build-and-test-extra.yml`` file. Make sure to -also modify the job label, so it is descriptive of the configuration. +also modify the job label as needed, so it is descriptive of the configuration +(and remains unique!!). To modify a shared configuration, it must be changed in the appropriate ``-build-and-test.yml`` file in the @@ -100,7 +111,7 @@ Create a branch there, modify the job entry, and create a pull request. any version of the RADIUSS Spack Configs project, create a branch there, add the needed spec info, and create a pull request. Then, when that PR is merged, update the RAJA submodule - to the new version. + for the RADIUSS Spack Configs project to the new version. Changing run parameters ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -111,9 +122,9 @@ RAJA, such as job time limits, resource allocations, etc. are defined in the remain as is, for the most part, and should not be changed unless absolutely necessary. -Sometimes a particular job will take longer to build and run than the -default allotted time for jobs on a machine. In this case, the time for the -job can be adjusted in the job entry in the associated +For example, sometimes a particular job will take longer to build and run +than the default allotted time for jobs on a machine. In this case, the +time for the job can be adjusted in the job entry in the associated ``RAJA/.gitlab/-build-and-test-extra.yml`` file. For example: @@ -147,8 +158,10 @@ annotate the job for this. For example: we call that "overriding": The job label must be kept the same as in the ``-build-and-test.yml`` file in the `RADIUSS Shared CI `_, - and the job implementation can be adapted. If you override a - shared job, please add a comment to describe the change. + and the RAJA-specific job can be adapted. If you override a + shared job, please add a comment to describe the change in the + ``RAJA/.gitlab/-build-and-test-extra.yml`` file where + the job is overridden. ================= Azure CI Tasks @@ -185,8 +198,9 @@ In the ``Dockerfile`` we will want to add our section that defines the commands COPY . /home/raja/workspace WORKDIR /home/raja/workspace/build RUN cmake -DCMAKE_CXX_COMPILER=compilerX ... && \ - make -j 6 &&\ - ctest -T test --output-on-failure + make -j 6 && \ + ctest -T test --output-on-failure && \ + cd .. && rm -rf build Each of our docker builds is built up on a base image maintained by RSE-Ops, a table of available base containers can be found `here `_. We are also able to add target names to each build with ``AS ...``. This target name correlates to the ``docker_target: ...`` defined in ``azure-pipelines.yml``. @@ -267,11 +281,14 @@ identical to that for RAJA, which is described in :ref:`ci-label`. Specifically, * The ``build_and_test.sh`` script resides in the `RAJAPerf/scripts/gitlab `_ directory. * The `RAJAPerf/Dockerfile `_ drives the Azure testing pipelines. -The main difference is that for GitLab CI, is that the Performance Suite uses -the RAJA submodules for ``uberenv`` and ``radiuss-spack-configs`` located in -the RAJA submodule to avoid redundant submodules. This is reflected in the +The Performance Suite GitLab CI uses the ``uberenv`` and +``radiuss-spack-configs`` versions located in +the RAJA submodule to make the testing consistent across projects and avoid +redundancy. This is reflected in the `RAJAPerf/.uberenv_config.json `_ -file which point at the relevant RAJA submodule locations. +file which point at the relevant RAJA submodule locations. That is the paths +contain ``tpl/RAJA/...``. Apart from this minor difference, all CI maintenance and development tasks for -the RAJA Performance Suite follow the guidance in :ref:`ci_tasks-label`. +the RAJA Performance Suite follow the same pattern that is described in +:ref:`ci_tasks-label`. From c4dec8a535cbd90c1c9882035b404e73aa7ea6d2 Mon Sep 17 00:00:00 2001 From: Rich Hornung Date: Thu, 7 Sep 2023 12:17:45 -0700 Subject: [PATCH 037/193] Fixes from review comments. --- docs/sphinx/dev_guide/build_configurations.rst | 5 ++--- docs/sphinx/dev_guide/ci.rst | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/sphinx/dev_guide/build_configurations.rst b/docs/sphinx/dev_guide/build_configurations.rst index c4232cef1f..e8ee81fba2 100644 --- a/docs/sphinx/dev_guide/build_configurations.rst +++ b/docs/sphinx/dev_guide/build_configurations.rst @@ -155,9 +155,8 @@ To generate a host-config file for a desired configuration, run the ``uberenv.py`` python script from the top-level RAJA directory. .. important:: **Do not** run the ``uberenv.py`` script, which invokes Spack - in your LC home directory since Spack uses a lot of disk space. - Running Spack in your home directory may cause you to exceed - your LC disk space quota. + in your LC home directory. Running Spack in your home directory + may cause you to exceed your LC disk space quota. For example, diff --git a/docs/sphinx/dev_guide/ci.rst b/docs/sphinx/dev_guide/ci.rst index 9f57f6650f..601ae7aa74 100644 --- a/docs/sphinx/dev_guide/ci.rst +++ b/docs/sphinx/dev_guide/ci.rst @@ -167,7 +167,7 @@ support LC GitLab CI testing. Briefly, these files play the following roles in GitLab CI testing: * The `RAJA/.gitlab-ci.yml `_ file is the top-level file for GitLab CI configuration. It defines - variables used in all GItLab pipelines such as + variables used in all GitLab pipelines such as GitHub project name and organization, service user account name, version information for RADIUSS Shared CI project we are using, and top-level information for triggering build-and-test sub-pipelines. @@ -175,7 +175,7 @@ Briefly, these files play the following roles in GitLab CI testing: Spack version we are using, location of Spack packages, etc. * The `RAJA/.gitlab `_ directory contains several files that connect RAJA GitLab pipelines to - shared pipelines defined in the + shared pipelines defined in the `RADIUSS Shared CI `_ project, as well as RAJA-specific jobs and shared job customizations that we use, such as job time limits, etc. These files are modified from templates @@ -280,7 +280,7 @@ Recall that RAJA project specific settings defining the Spack version to use, locations of Spack packages, etc. are located in the `RAJA/.uberenv_config.json `_ file. -Also, recall that to generate a hist-config file, Spack uses packages and +Also, recall that to generate a host-config file, Spack uses packages and specs in the `RADIUSS Spack Configs project `_ (a RAJA submodule), plus RAJA-specific specs defined in files in the `RAJA/.gitlab `_ directory, as described earlier. From 1c7e176fb9a0e766e7498bae33b1196ebd46dc94 Mon Sep 17 00:00:00 2001 From: Rich Hornung Date: Thu, 7 Sep 2023 12:39:21 -0700 Subject: [PATCH 038/193] Fix from review. --- docs/sphinx/dev_guide/ci.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/dev_guide/ci.rst b/docs/sphinx/dev_guide/ci.rst index 601ae7aa74..7308c29f48 100644 --- a/docs/sphinx/dev_guide/ci.rst +++ b/docs/sphinx/dev_guide/ci.rst @@ -20,7 +20,7 @@ Continuous Integration (CI) Testing The RAJA project uses two CI tools to run tests: * **Azure Pipelines** runs builds and tests for Linux, Windows, and MacOS - environments using compilers in container image maintained in the + environments using compilers in container images maintained in the `RSE Ops Project `_. While we do some GPU builds on Azure, RAJA tests are only run for CPU-only builds. The current set of builds run on Azure can be seen by looking at From 710a840e13ada24212f76e33df9540e6154c5536 Mon Sep 17 00:00:00 2001 From: Brian Homerding Date: Mon, 11 Sep 2023 20:36:01 +0000 Subject: [PATCH 039/193] Remove redundant wait, add nontrivial nonempty fparams support --- include/RAJA/policy/sycl/forall.hpp | 142 +++++++++++++++++++++++----- 1 file changed, 120 insertions(+), 22 deletions(-) diff --git a/include/RAJA/policy/sycl/forall.hpp b/include/RAJA/policy/sycl/forall.hpp index 75ea8b42af..7e529e991b 100644 --- a/include/RAJA/policy/sycl/forall.hpp +++ b/include/RAJA/policy/sycl/forall.hpp @@ -66,10 +66,10 @@ namespace impl ****************************************************************************** */ RAJA_INLINE -cl::sycl::range<1> getGridDim(size_t len, size_t block_size) +::sycl::range<1> getGridDim(size_t len, size_t block_size) { size_t size = {block_size * ((len + block_size - 1) / block_size)}; - cl::sycl::range<1> gridSize(size); + ::sycl::range<1> gridSize(size); return gridSize; } @@ -121,17 +121,17 @@ forall_impl(resources::Sycl &sycl_res, sycl_dim_t blockSize{BlockSize}; sycl_dim_t gridSize = impl::getGridDim(static_cast(len), BlockSize); - cl::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); + ::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); // Global resource was not set, use the resource that was passed to forall // Determine if the default SYCL res is being used if (!q) { q = sycl_res.get_queue(); } - q->submit([&](cl::sycl::handler& h) { + q->submit([&](::sycl::handler& h) { - h.parallel_for( cl::sycl::nd_range<1>{gridSize, blockSize}, - [=] (cl::sycl::nd_item<1> it) { + h.parallel_for( ::sycl::nd_range<1>{gridSize, blockSize}, + [=] (::sycl::nd_item<1> it) { IndexType ii = it.get_global_id(0); if (ii < len) { @@ -178,7 +178,7 @@ resources::EventProxy forall_impl(resources::Sycl &sycl_res, sycl_dim_t blockSize{BlockSize}; sycl_dim_t gridSize = impl::getGridDim(static_cast(len), BlockSize); - cl::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); + ::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); // Global resource was not set, use the resource that was passed to forall // Determine if the default SYCL res is being used if (!q) { @@ -192,16 +192,16 @@ resources::EventProxy forall_impl(resources::Sycl &sycl_res, // Kernel body is nontrivially copyable, create space on device and copy to // Workaround until "is_device_copyable" is supported // - lbody = (LOOP_BODY*) cl::sycl::malloc_device(sizeof(LOOP_BODY), *q); + lbody = (LOOP_BODY*) ::sycl::malloc_device(sizeof(LOOP_BODY), *q); q->memcpy(lbody, &loop_body, sizeof(LOOP_BODY)).wait(); - beg = (Iterator*) cl::sycl::malloc_device(sizeof(Iterator), *q); + beg = (Iterator*) ::sycl::malloc_device(sizeof(Iterator), *q); q->memcpy(beg, &begin, sizeof(Iterator)).wait(); - q->submit([&](cl::sycl::handler& h) { + q->submit([&](::sycl::handler& h) { - h.parallel_for( cl::sycl::nd_range<1>{gridSize, blockSize}, - [=] (cl::sycl::nd_item<1> it) { + h.parallel_for( ::sycl::nd_range<1>{gridSize, blockSize}, + [=] (::sycl::nd_item<1> it) { Index_type ii = it.get_global_id(0); @@ -256,7 +256,7 @@ forall_impl(resources::Sycl &sycl_res, sycl_dim_t blockSize{BlockSize}; sycl_dim_t gridSize = impl::getGridDim(static_cast(len), BlockSize); - cl::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); + ::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); // Global resource was not set, use the resource that was passed to forall // Determine if the default SYCL res is being used if (!q) { @@ -272,10 +272,10 @@ forall_impl(resources::Sycl &sycl_res, RAJA::expt::ParamMultiplexer::init(*res); auto reduction = ::sycl::reduction(res, f_params, combiner); - q->submit([&](cl::sycl::handler& h) { - h.parallel_for( cl::sycl::range<1>(len), + q->submit([&](::sycl::handler& h) { + h.parallel_for( ::sycl::range<1>(len), reduction, - [=] (cl::sycl::item<1> it, auto & red) { + [=] (::sycl::item<1> it, auto & red) { ForallParam fp; RAJA::expt::ParamMultiplexer::init(fp); @@ -287,10 +287,107 @@ forall_impl(resources::Sycl &sycl_res, }); }); - if (!Async) { q->wait(); } - q->wait(); - RAJA::expt::ParamMultiplexer::combine( f_params, *res ); - ::sycl::free(res, *q); + q->wait(); + RAJA::expt::ParamMultiplexer::combine( f_params, *res ); + ::sycl::free(res, *q); + } + RAJA::expt::ParamMultiplexer::resolve(f_params); + + return resources::EventProxy(sycl_res); + +} + +template {},bool>::type = true> +RAJA_INLINE +concepts::enable_if_t< + resources::EventProxy, + RAJA::expt::type_traits::is_ForallParamPack, + concepts::negate> > +forall_impl(resources::Sycl &sycl_res, + sycl_exec, + Iterable&& iter, + LoopBody&& loop_body, + ForallParam f_params) + +{ + using Iterator = camp::decay; + using LOOP_BODY = camp::decay; + using IndexType = camp::decay; + using EXEC_POL = RAJA::sycl_exec; + // + // Compute the requested iteration space size + // + Iterator begin = std::begin(iter); + Iterator end = std::end(iter); + IndexType len = std::distance(begin, end); + + RAJA::expt::ParamMultiplexer::init(f_params); + + // Only launch kernel if we have something to iterate over + if (len > 0 && BlockSize > 0) { + // + // Compute the number of blocks + // + sycl_dim_t blockSize{BlockSize}; + sycl_dim_t gridSize = impl::getGridDim(static_cast(len), BlockSize); + + ::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); + // Global resource was not set, use the resource that was passed to forall + // Determine if the default SYCL res is being used + if (!q) { + q = sycl_res.get_queue(); + } + + auto combiner = []( ForallParam x, ForallParam y ) { + RAJA::expt::ParamMultiplexer::combine( x, y ); + return x; + }; + + // START + // + LOOP_BODY* lbody; + Iterator* beg; + RAJA_FT_BEGIN; + // + // Setup shared memory buffers + // Kernel body is nontrivially copyable, create space on device and copy to + // Workaround until "is_device_copyable" is supported + // + lbody = (LOOP_BODY*) ::sycl::malloc_device(sizeof(LOOP_BODY), *q); + q->memcpy(lbody, &loop_body, sizeof(LOOP_BODY)).wait(); + + beg = (Iterator*) ::sycl::malloc_device(sizeof(Iterator), *q); + q->memcpy(beg, &begin, sizeof(Iterator)).wait(); + + ForallParam* res = ::sycl::malloc_shared(1,*q); + RAJA::expt::ParamMultiplexer::init(*res); + auto reduction = ::sycl::reduction(res, f_params, combiner); + + q->submit([&](::sycl::handler& h) { + h.parallel_for( ::sycl::range<1>(len), + reduction, + [=] (::sycl::item<1> it, auto & red) { + + + Index_type ii = it.get_id(0); + ForallParam fp; + RAJA::expt::ParamMultiplexer::init(fp); + if (ii < len) { + RAJA::expt::invoke_body(fp, *lbody, (*beg)[ii]); + } + red.combine(fp); + + }); + }).wait(); // Need to wait for completion to free memory + RAJA::expt::ParamMultiplexer::combine( f_params, *res ); + // Free our device memory + ::sycl::free(res, *q); + ::sycl::free(lbody, *q); + ::sycl::free(beg, *q); + + RAJA_FT_END; + } RAJA::expt::ParamMultiplexer::resolve(f_params); @@ -298,6 +395,7 @@ forall_impl(resources::Sycl &sycl_res, } + // ////////////////////////////////////////////////////////////////////// // @@ -333,7 +431,7 @@ RAJA_INLINE void forall_impl(ExecPolicy>, } // iterate over segments of index set if (!Async) { - cl::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); + ::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); q->wait(); }; } @@ -358,7 +456,7 @@ RAJA_INLINE resources::EventProxy forall_impl(resources::Sycl & } // iterate over segments of index set if (!Async) { - cl::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); + ::sycl::queue* q = ::RAJA::sycl::detail::getQueue(); q->wait(); } From bcacace33b77db4fbea106ef72c96e52d5bc332a Mon Sep 17 00:00:00 2001 From: Jason Burmark Date: Thu, 21 Sep 2023 09:49:18 -0700 Subject: [PATCH 040/193] Update toss4_amdclang_asan.sh --- scripts/lc-builds/toss4_amdclang_asan.sh | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/scripts/lc-builds/toss4_amdclang_asan.sh b/scripts/lc-builds/toss4_amdclang_asan.sh index c7011db1a0..9dcc7ac266 100755 --- a/scripts/lc-builds/toss4_amdclang_asan.sh +++ b/scripts/lc-builds/toss4_amdclang_asan.sh @@ -15,7 +15,7 @@ if [[ $# -lt 2 ]]; then echo " 3...) optional arguments to cmake" echo echo "For example: " - echo " toss4_amdclang.sh 4.1.0 gfx906" + echo " toss4_amdclang_asan.sh 5.7.0 gfx90a" exit fi @@ -36,10 +36,10 @@ else echo "Unknown hip version, using ${HOSTCONFIG} host-config" fi -BUILD_SUFFIX=lc_toss4-amdclang-${COMP_VER}-${COMP_ARCH} +BUILD_SUFFIX=lc_toss4-amdclang-${COMP_VER}-${COMP_ARCH}-asan echo -echo "Creating build directory ${BUILD_SUFFIX} and generating configuration in it" +echo "Creating build directory build_${BUILD_SUFFIX} and generating configuration in it" echo "Configuration extra arguments:" echo " $@" echo @@ -57,17 +57,19 @@ module load cmake/3.23.1 # are inconsistent causing the rocprim from the module to be used unexpectedly module unload rocm +ROCM_PATH="/usr/tce/packages/rocm/rocm-${COMP_VER}" cmake \ -DCMAKE_BUILD_TYPE=Release \ - -DROCM_ROOT_DIR="/opt/rocm-${COMP_VER}" \ - -DHIP_ROOT_DIR="/opt/rocm-${COMP_VER}/hip" \ - -DHIP_PATH=/opt/rocm-${COMP_VER}/llvm/bin \ - -DCMAKE_C_COMPILER=/opt/rocm-${COMP_VER}/llvm/bin/amdclang \ - -DCMAKE_CXX_COMPILER=/opt/rocm-${COMP_VER}/llvm/bin/amdclang++ \ + -DROCM_ROOT_DIR="${ROCM_PATH}" \ + -DHIP_ROOT_DIR="${ROCM_PATH}/hip" \ + -DHIP_PATH=${ROCM_PATH}/llvm/bin \ + -DCMAKE_C_COMPILER=${ROCM_PATH}/llvm/bin/amdclang \ + -DCMAKE_CXX_COMPILER=${ROCM_PATH}/llvm/bin/amdclang++ \ -DCMAKE_HIP_ARCHITECTURES="${COMP_ARCH}:xnack+" \ -DGPU_TARGETS="${COMP_ARCH}:xnack+" \ -DAMDGPU_TARGETS="${COMP_ARCH}:xnack+" \ + -DCMAKE_C_FLAGS="-fsanitize=address -shared-libsan" \ -DCMAKE_CXX_FLAGS="-fsanitize=address -shared-libsan" \ -DBLT_CXX_STD=c++14 \ -C "../host-configs/lc-builds/toss4/${HOSTCONFIG}.cmake" \ @@ -91,8 +93,8 @@ echo " module unload rocm" echo " srun -n1 make" echo echo " Run with these environment options" -echo " ASAN_OPTIONS=detect_leaks=0" +echo " ASAN_OPTIONS=print_suppressions=0:detect_leaks=0" echo " HSA_XNACK=1" -echo " LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:/opt/rocm-${COMP_VER}/llvm/lib/clang/15.0.0/lib/linux" +echo " LD_LIBRARY_PATH=${ROCM_PATH}/lib:\$LD_LIBRARY_PATH" echo echo "***********************************************************************" From f9821a7e7c2afe985911dd7a8caf4db93b906dbe Mon Sep 17 00:00:00 2001 From: Jason Burmark Date: Thu, 21 Sep 2023 12:01:55 -0700 Subject: [PATCH 041/193] More updates --- scripts/lc-builds/toss4_amdclang_asan.sh | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/scripts/lc-builds/toss4_amdclang_asan.sh b/scripts/lc-builds/toss4_amdclang_asan.sh index 9dcc7ac266..3b4333c734 100755 --- a/scripts/lc-builds/toss4_amdclang_asan.sh +++ b/scripts/lc-builds/toss4_amdclang_asan.sh @@ -43,6 +43,9 @@ echo "Creating build directory build_${BUILD_SUFFIX} and generating configuratio echo "Configuration extra arguments:" echo " $@" echo +echo "To get cmake to work you may have to configure with" +echo " -DHIP_PLATFORM=amd" +echo echo "To use fp64 HW atomics you must configure with these options when using gfx90a and hip >= 5.2" echo " -DCMAKE_CXX_FLAGS=\"-munsafe-fp-atomics\"" echo @@ -55,9 +58,13 @@ module load cmake/3.23.1 # unload rocm to avoid configuration problems where the loaded rocm and COMP_VER # are inconsistent causing the rocprim from the module to be used unexpectedly -module unload rocm +# module unload rocm -ROCM_PATH="/usr/tce/packages/rocm/rocm-${COMP_VER}" +if [[ ${COMP_VER} =~ .*magic.* ]]; then + ROCM_PATH="/usr/tce/packages/rocmcc/rocmcc-${COMP_VER}" +else + ROCM_PATH="/usr/tce/packages/rocmcc-tce/rocmcc-${COMP_VER}" +fi cmake \ -DCMAKE_BUILD_TYPE=Release \ @@ -86,15 +93,14 @@ echo echo "cd into directory build_${BUILD_SUFFIX} and run make to build RAJA" echo echo " Please note that you have to have a consistent build environment" -echo " when you make RAJA as cmake may reconfigure; unload the rocm module" -echo " or load the appropriate rocm module (${COMP_VER}) when building." +echo " when you make RAJA as cmake may reconfigure; load the appropriate" +echo " rocm and rocmcc modules (${COMP_VER}) when building." echo -echo " module unload rocm" +echo " module load rocm/COMP_VER rocmcc/COMP_VER" echo " srun -n1 make" echo -echo " Run with these environment options" +echo " Run with these environment options when using asan" echo " ASAN_OPTIONS=print_suppressions=0:detect_leaks=0" echo " HSA_XNACK=1" -echo " LD_LIBRARY_PATH=${ROCM_PATH}/lib:\$LD_LIBRARY_PATH" echo echo "***********************************************************************" From 749ef2852f217cddd303f84e53f6bdbfec302675 Mon Sep 17 00:00:00 2001 From: gberg617 Date: Fri, 29 Sep 2023 09:28:21 -0700 Subject: [PATCH 042/193] added curly braces --- include/RAJA/util/IndexLayout.hpp | 7 ++-- test/unit/view-layout/test-indexlayout.cpp | 41 +++++++++++++++------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/include/RAJA/util/IndexLayout.hpp b/include/RAJA/util/IndexLayout.hpp index 9e7f4ccd1d..452245720e 100644 --- a/include/RAJA/util/IndexLayout.hpp +++ b/include/RAJA/util/IndexLayout.hpp @@ -67,8 +67,11 @@ struct ConditionalIndexList { IdxLin RAJA_INLINE RAJA_HOST_DEVICE constexpr operator()(const IdxLin idx) const { - if (index_list) return index_list[idx]; - else return idx; + if (index_list) { + return index_list[idx]; + } else { + return idx; + } } }; diff --git a/test/unit/view-layout/test-indexlayout.cpp b/test/unit/view-layout/test-indexlayout.cpp index c80dfc5b4c..e867d781bc 100644 --- a/test/unit/view-layout/test-indexlayout.cpp +++ b/test/unit/view-layout/test-indexlayout.cpp @@ -222,9 +222,11 @@ TEST(IndexLayout, View2DLayout) Index_type data[2][3]; - for (int i = 0; i < 2; i ++ ) - for (int j = 0; j < 3; j ++ ) + for (int i = 0; i < 2; i ++ ) { + for (int j = 0; j < 3; j ++ ) { data[i][j] = i*j; + } + } Index_type index_list[2] = {1,2}; @@ -233,9 +235,11 @@ TEST(IndexLayout, View2DLayout) auto view = make_index_view(&data[0][0], index_layout); - for (int i = 0; i < 2; i ++ ) - for (int j = 0; j < 2; j ++ ) + for (int i = 0; i < 2; i ++ ) { + for (int j = 0; j < 2; j ++ ) { EXPECT_EQ(view(i,j), i*(j+1)); + } + } } @@ -256,10 +260,13 @@ TEST(IndexLayout, View3DLayout) Index_type data[2][3][4]; - for (int i = 0; i < 2; i ++ ) - for (int j = 0; j < 3; j ++ ) - for (int k = 0; k < 4; k ++ ) - data[i][j][k] = i*j*k; + for (int i = 0; i < 2; i ++ ) { + for (int j = 0; j < 3; j ++ ) { + for (int k = 0; k < 4; k ++ ) { + data[i][j][k] = i*j*k; + } + } + } Index_type index_list_j[2] = {1,2}; Index_type index_list_k[2] = {2,3}; @@ -272,10 +279,13 @@ TEST(IndexLayout, View3DLayout) auto view = make_index_view(&data[0][0][0], index_layout); - for (int i = 0; i < 2; i ++ ) - for (int j = 0; j < 2; j ++ ) - for (int k = 0; k < 2; k ++ ) + for (int i = 0; i < 2; i ++ ) { + for (int j = 0; j < 2; j ++ ) { + for (int k = 0; k < 2; k ++ ) { EXPECT_EQ(view(i,j,k), i*(j+1)*(k+2)); + } + } + } } @@ -295,8 +305,13 @@ TEST(IndexLayout, MultiView1DLayout) Index_type data_squared[4]; Index_type data_cubed[4]; - for (int i = 0; i < 4; i ++ ) data_squared[i] = i*i; - for (int i = 0; i < 4; i ++ ) data_cubed[i] = i*i*i; + for (int i = 0; i < 4; i ++ ) { + data_squared[i] = i*i; + } + + for (int i = 0; i < 4; i ++ ) { + data_cubed[i] = i*i*i; + } Index_type* data_array[2]; data_array[0] = data_squared; From 73fd43123f9f62067395b20d85c2f165e584e382 Mon Sep 17 00:00:00 2001 From: Rich Hornung Date: Fri, 29 Sep 2023 11:29:00 -0700 Subject: [PATCH 043/193] Remove remnants of loop_exec policy --- include/RAJA/RAJA.hpp | 5 -- include/RAJA/policy/loop.hpp | 35 -------- include/RAJA/policy/loop/policy.hpp | 87 ------------------- ...launch-direct-teams-threads-3D-execpol.hpp | 22 ++--- ...t-launch-loop-teams-threads-1D-execpol.hpp | 6 +- ...t-launch-loop-teams-threads-3D-execpol.hpp | 22 ++--- 6 files changed, 25 insertions(+), 152 deletions(-) delete mode 100644 include/RAJA/policy/loop.hpp delete mode 100644 include/RAJA/policy/loop/policy.hpp diff --git a/include/RAJA/RAJA.hpp b/include/RAJA/RAJA.hpp index 7c5484c922..7d49352da4 100644 --- a/include/RAJA/RAJA.hpp +++ b/include/RAJA/RAJA.hpp @@ -57,11 +57,6 @@ // #include "RAJA/policy/sequential.hpp" -// -// All platforms must support loop execution. -// -#include "RAJA/policy/loop.hpp" - // // All platforms should support simd and vector execution. // diff --git a/include/RAJA/policy/loop.hpp b/include/RAJA/policy/loop.hpp deleted file mode 100644 index c60689797a..0000000000 --- a/include/RAJA/policy/loop.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/*! -****************************************************************************** -* -* \file -* -* \brief Header file containing RAJA headers for sequential execution. -* -* These methods work on all platforms. -* -****************************************************************************** -*/ - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -// Copyright (c) 2016-23, Lawrence Livermore National Security, LLC -// and RAJA project contributors. See the RAJA/LICENSE file for details. -// -// SPDX-License-Identifier: (BSD-3-Clause) -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - -#ifndef RAJA_loop_HPP -#define RAJA_loop_HPP - -#if !defined(RAJA_ENABLE_DESUL_ATOMICS) - #include "RAJA/policy/sequential/atomic.hpp" -#endif - -#include "RAJA/policy/sequential/forall.hpp" -#include "RAJA/policy/sequential/kernel.hpp" -#include "RAJA/policy/loop/policy.hpp" -#include "RAJA/policy/sequential/scan.hpp" -#include "RAJA/policy/sequential/sort.hpp" -#include "RAJA/policy/sequential/launch.hpp" -#include "RAJA/policy/sequential/WorkGroup.hpp" - -#endif // closing endif for header file include guard diff --git a/include/RAJA/policy/loop/policy.hpp b/include/RAJA/policy/loop/policy.hpp deleted file mode 100644 index 7c73c19860..0000000000 --- a/include/RAJA/policy/loop/policy.hpp +++ /dev/null @@ -1,87 +0,0 @@ -/*! - ****************************************************************************** - * - * \file - * - * \brief Header file containing RAJA sequential policy definitions. - * - ****************************************************************************** - */ - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -// Copyright (c) 2016-23, Lawrence Livermore National Security, LLC -// and RAJA project contributors. See the RAJA/LICENSE file for details. -// -// SPDX-License-Identifier: (BSD-3-Clause) -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - -#ifndef policy_loop_HPP -#define policy_loop_HPP - -#include "RAJA/policy/PolicyBase.hpp" - -#include "RAJA/policy/sequential/policy.hpp" - -namespace RAJA -{ -namespace policy -{ -namespace loop -{ - -// -////////////////////////////////////////////////////////////////////// -// -// Execution policies -// -////////////////////////////////////////////////////////////////////// -// - -/// -/// Segment execution policies -/// - -using loop_exec = seq_exec; - -/// -/// Index set segment iteration policies -/// -using loop_segit = seq_exec; - -/// -/// WorkGroup execution policies -/// -using loop_work = seq_work; - -/// -/////////////////////////////////////////////////////////////////////// -/// -/// Reduction execution policies -/// -/////////////////////////////////////////////////////////////////////// -/// -using loop_reduce = seq_reduce; - - -/// -/////////////////////////////////////////////////////////////////////// -/// -/// Atomic execution policies -/// -/////////////////////////////////////////////////////////////////////// -/// -using loop_atomic = seq_atomic; - -} // end namespace loop - -} // end namespace policy - -using policy::loop::loop_atomic; -using policy::loop::loop_exec; -using policy::loop::loop_reduce; -using policy::loop::loop_segit; -using policy::loop::loop_work; - -} // namespace RAJA - -#endif diff --git a/test/include/RAJA_test-launch-direct-teams-threads-3D-execpol.hpp b/test/include/RAJA_test-launch-direct-teams-threads-3D-execpol.hpp index 42fca2ccfe..38bc4c8bb0 100644 --- a/test/include/RAJA_test-launch-direct-teams-threads-3D-execpol.hpp +++ b/test/include/RAJA_test-launch-direct-teams-threads-3D-execpol.hpp @@ -19,12 +19,12 @@ using seq_policies = camp::list< RAJA::LaunchPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy + RAJA::LoopPolicy, + RAJA::LoopPolicy, + RAJA::LoopPolicy, + RAJA::LoopPolicy, + RAJA::LoopPolicy, + RAJA::LoopPolicy >; using Sequential_launch_policies = camp::list; @@ -35,11 +35,11 @@ using omp_policies = camp::list< RAJA::LaunchPolicy, RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy + RAJA::LoopPolicy, + RAJA::LoopPolicy, + RAJA::LoopPolicy, + RAJA::LoopPolicy, + RAJA::LoopPolicy >; using OpenMP_launch_policies = camp::list; diff --git a/test/include/RAJA_test-launch-loop-teams-threads-1D-execpol.hpp b/test/include/RAJA_test-launch-loop-teams-threads-1D-execpol.hpp index 43a2c3ccd6..9e5779853c 100644 --- a/test/include/RAJA_test-launch-loop-teams-threads-1D-execpol.hpp +++ b/test/include/RAJA_test-launch-loop-teams-threads-1D-execpol.hpp @@ -18,8 +18,8 @@ //Launch policies using seq_policies = camp::list< RAJA::LaunchPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy + RAJA::LoopPolicy, + RAJA::LoopPolicy >; using Sequential_launch_policies = camp::list< @@ -30,7 +30,7 @@ using Sequential_launch_policies = camp::list< using omp_policies = camp::list< RAJA::LaunchPolicy, RAJA::LoopPolicy, - RAJA::LoopPolicy + RAJA::LoopPolicy >; using OpenMP_launch_policies = camp::list< diff --git a/test/include/RAJA_test-launch-loop-teams-threads-3D-execpol.hpp b/test/include/RAJA_test-launch-loop-teams-threads-3D-execpol.hpp index 604d52065e..9d217757b2 100644 --- a/test/include/RAJA_test-launch-loop-teams-threads-3D-execpol.hpp +++ b/test/include/RAJA_test-launch-loop-teams-threads-3D-execpol.hpp @@ -18,12 +18,12 @@ //Launch policies using seq_policies = camp::list< RAJA::LaunchPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy + RAJA::LoopPolicy, + RAJA::LoopPolicy, + RAJA::LoopPolicy, + RAJA::LoopPolicy, + RAJA::LoopPolicy, + RAJA::LoopPolicy >; using Sequential_launch_policies = camp::list< @@ -34,11 +34,11 @@ using Sequential_launch_policies = camp::list< using omp_policies = camp::list< RAJA::LaunchPolicy, RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy, - RAJA::LoopPolicy + RAJA::LoopPolicy, + RAJA::LoopPolicy, + RAJA::LoopPolicy, + RAJA::LoopPolicy, + RAJA::LoopPolicy >; using OpenMP_launch_policies = camp::list< From 3458b65064e1d33a9a136fea1f423fb0901924e6 Mon Sep 17 00:00:00 2001 From: Rich Hornung Date: Fri, 29 Sep 2023 11:29:31 -0700 Subject: [PATCH 044/193] Remove remnants of loop_exec from user docs --- .../sphinx/user_guide/feature/local_array.rst | 6 +-- docs/sphinx/user_guide/feature/plugins.rst | 2 +- docs/sphinx/user_guide/feature/policies.rst | 37 ++++++++----------- docs/sphinx/user_guide/feature/tiling.rst | 4 +- docs/sphinx/user_guide/tutorial.rst | 4 +- .../user_guide/tutorial/add_vectors.rst | 19 +++------- .../user_guide/tutorial/kernel_exec_pols.rst | 2 +- .../user_guide/tutorial/launch_basic.rst | 8 ++-- .../user_guide/tutorial/matrix_transpose.rst | 2 +- 9 files changed, 36 insertions(+), 48 deletions(-) diff --git a/docs/sphinx/user_guide/feature/local_array.rst b/docs/sphinx/user_guide/feature/local_array.rst index 92db00be56..0aafa221f9 100644 --- a/docs/sphinx/user_guide/feature/local_array.rst +++ b/docs/sphinx/user_guide/feature/local_array.rst @@ -57,12 +57,12 @@ its constituent parts:: // using POL = RAJA::KernelPolicy< - RAJA::statement::For<1, RAJA::loop_exec, + RAJA::statement::For<1, RAJA::seq_exec, RAJA::statement::InitLocalMem, - RAJA::statement::For<0, RAJA::loop_exec, + RAJA::statement::For<0, RAJA::seq_exec, RAJA::statement::Lambda<0> >, - RAJA::statement::For<0, RAJA::loop_exec, + RAJA::statement::For<0, RAJA::seq_exec, RAJA::statement::Lambda<1> > > diff --git a/docs/sphinx/user_guide/feature/plugins.rst b/docs/sphinx/user_guide/feature/plugins.rst index 72aae00add..c591951eb5 100644 --- a/docs/sphinx/user_guide/feature/plugins.rst +++ b/docs/sphinx/user_guide/feature/plugins.rst @@ -212,7 +212,7 @@ After CHAI has been built with RAJA support enabled, applications can use CHAI array[i] = i * 2.0f; }); - RAJA::forall(0, 1000, [=] (int i) { + RAJA::forall(0, 1000, [=] (int i) { std::cout << "array[" << i << "] is " << array[i] << std::endl; }); diff --git a/docs/sphinx/user_guide/feature/policies.rst b/docs/sphinx/user_guide/feature/policies.rst index 2f707c5efd..6594cd7771 100644 --- a/docs/sphinx/user_guide/feature/policies.rst +++ b/docs/sphinx/user_guide/feature/policies.rst @@ -49,21 +49,19 @@ apply during code compilation. ====================================== ============= ========================== seq_launch_t launch Creates a sequential execution space. - seq_exec forall, Strictly sequential - kernel (For), execution. - scan, - sort + seq_exec forall, Sequential execution, + kernel (For), where the compiler is + scan, allowed to apply any + sort any optimizations + that its heuristics deem + beneficial; i.e., no loop + decorations (pragmas or + intrinsics) in the RAJA + implementation. simd_exec forall, Try to force generation of kernel (For), SIMD instructions via scan compiler hints in RAJA's internal implementation. - loop_exec forall, Allow the compiler to - kernel (For), generate any optimizations - scan, that its heuristics deem - sort beneficial; - i.e., no loop decorations - (pragmas or intrinsics) in - RAJA implementation. ====================================== ============= ========================== @@ -686,11 +684,11 @@ surround code that uses execution back-ends other than OpenMP. For example:: RAJA::region([=]() { - RAJA::forall(segment, [=] (int idx) { + RAJA::forall(segment, [=] (int idx) { // do something at iterate 'idx' } ); - RAJA::forall(segment, [=] (int idx) { + RAJA::forall(segment, [=] (int idx) { // do something else at iterate 'idx' } ); @@ -725,7 +723,6 @@ Reduction Policy Loop Policies Brief description to Use With ======================= ============= ========================================== seq_reduce seq_exec, Non-parallel (sequential) reduction. - loop_exec omp_reduce any OpenMP OpenMP parallel reduction. policy omp_reduce_ordered any OpenMP OpenMP parallel reduction with result @@ -766,7 +763,7 @@ Atomic Policy Loop Policies Brief description to Use With ============================= ============= ======================================== seq_atomic seq_exec, Atomic operation performed in a - loop_exec non-parallel (sequential) kernel. + non-parallel (sequential) kernel. omp_atomic any OpenMP Atomic operation in OpenM kernel.P policy multithreading or target kernel; i.e., apply ``omp atomic`` pragma. @@ -781,14 +778,12 @@ cuda/hip_atomic_explicit any CUDA/HIP Atomic operation performed in a CUDA argument. See additional explanation and example below. builtin_atomic seq_exec, Compiler *builtin* atomic operation. - loop_exec, any OpenMP policy -auto_atomic seq_exec, Atomic operation *compatible* with loop - loop_exec, execution policy. See example below. - any OpenMP Can not be used inside cuda/hip - policy, explicit atomic policies. - any +auto_atomic seq_exec, Atomic operation *compatible* with + any OpenMP loop execution policy. See example + policy, below. Cannot be used inside CUDA or + any HIP explicit atomic policies. CUDA/HIP/SYCL policy ============================= ============= ======================================== diff --git a/docs/sphinx/user_guide/feature/tiling.rst b/docs/sphinx/user_guide/feature/tiling.rst index b42ac964c0..6855843a8a 100644 --- a/docs/sphinx/user_guide/feature/tiling.rst +++ b/docs/sphinx/user_guide/feature/tiling.rst @@ -79,7 +79,7 @@ The ``RAJA::launch`` API also supports loop tiling through specialized methods. The launch version of the code above is :: using launch_t = RAJA::LaunchPolicy; - using loop_t = RAJA::LoopPolicy; + using loop_t = RAJA::LoopPolicy; RAJA::launch( RAJA::LaunchParams(), RAJA_HOST_DEVICE(RAJA::launchContext ctx) { @@ -154,7 +154,7 @@ The launch API uses ``RAJA::tile_tcount`` and ``RAJA::loop_icount`` methods which has a second argument on the lambda for the index. We illustrate usage below:: using launch_t = RAJA::LaunchPolicy; - using loop_t = RAJA::LoopPolicy; + using loop_t = RAJA::LoopPolicy; RAJA::launch( RAJA::LaunchParams(), RAJA_HOST_DEVICE(RAJA::launchContext ctx) { diff --git a/docs/sphinx/user_guide/tutorial.rst b/docs/sphinx/user_guide/tutorial.rst index 9a8c04b419..9529a53275 100644 --- a/docs/sphinx/user_guide/tutorial.rst +++ b/docs/sphinx/user_guide/tutorial.rst @@ -95,7 +95,7 @@ Here, "ExecPol", "IdxType", and "LoopBody" are C++ types that a user specifies in her code and which are seen by the compiler when the code is built. For example:: - RAJA::forall< RAJA::loop_exec >( RAJA::TypedRangeSegment(0, N), [=](int i) { + RAJA::forall< RAJA::seq_exec >( RAJA::TypedRangeSegment(0, N), [=](int i) { a[i] = b[i] + c[i]; }); @@ -106,7 +106,7 @@ The C-style analogue of this kernel is:: a[i] = b[i] + c[i]; } -The execution policy type ``RAJA::loop_exec`` template argument +The execution policy type ``RAJA::seq_exec`` template argument is used to choose as specific implementation of the ``RAJA::forall`` method. The ``IdxType`` and ``LoopBody`` types are deduced by the compiler based the arguments passed to the ``RAJA::forall`` method; diff --git a/docs/sphinx/user_guide/tutorial/add_vectors.rst b/docs/sphinx/user_guide/tutorial/add_vectors.rst index 5bfc913d02..7c773dab9e 100644 --- a/docs/sphinx/user_guide/tutorial/add_vectors.rst +++ b/docs/sphinx/user_guide/tutorial/add_vectors.rst @@ -59,22 +59,15 @@ policy type: :end-before: _rajaseq_vector_add_end :language: C++ -The RAJA sequential execution policy enforces strictly sequential execution; -in particular, no SIMD vectorization instructions or other substantial -optimizations will be generated by the compiler. To attempt to force the -compiler to generate SIMD vector instructions, we would use the RAJA SIMD -execution policy:: +When using the RAJA sequential execution policy, the resulting loop +implementation is essentially the same as writing a C-style for-loop +with no directives applied to the loop. The compiler is allowed to +perform any optimizations that its heuristics deem are safe and potentially +beneficial for performance. To attempt to force the compiler to generate SIMD +vector instructions, we would use the RAJA SIMD execution policy:: RAJA::simd_exec -An alternative RAJA policy is:: - - RAJA::loop_exec - -which allows the compiler to generate optimizations based on how its internal -heuristics suggest that it is safe to do so and potentially -beneficial for performance, but the optimizations are not forced. - To run the kernel with OpenMP multithreaded parallelism on a CPU, we use the ``RAJA::omp_parallel_for_exec`` execution policy: diff --git a/docs/sphinx/user_guide/tutorial/kernel_exec_pols.rst b/docs/sphinx/user_guide/tutorial/kernel_exec_pols.rst index fedea62209..da720e7f1c 100644 --- a/docs/sphinx/user_guide/tutorial/kernel_exec_pols.rst +++ b/docs/sphinx/user_guide/tutorial/kernel_exec_pols.rst @@ -133,7 +133,7 @@ and :language: C++ The first of these, in which we parallelize the outer 'k' loop, replaces -the ``RAJA::loop_exec`` loop execution policy with the +the ``RAJA::seq_exec`` loop execution policy with the ``RAJA::omp_parallel_for_exec`` policy, which applies the same OpenMP directive to the outer loop used in the C-style variant. diff --git a/docs/sphinx/user_guide/tutorial/launch_basic.rst b/docs/sphinx/user_guide/tutorial/launch_basic.rst index 19f6f153ca..2682037860 100644 --- a/docs/sphinx/user_guide/tutorial/launch_basic.rst +++ b/docs/sphinx/user_guide/tutorial/launch_basic.rst @@ -74,10 +74,10 @@ The mapping between teams and threads to the underlying programming model depends on how the ``RAJA::loop`` template parameter types are defined. For example, we may define host and device mapping strategies as:: - using teams_x = RAJA::LoopPolicy; - using thread_x = RAJA::LoopPolicy; + using teams_x = RAJA::LoopPolicy< RAJA::seq_exec, + RAJA::cuda_block_x_direct >; + using thread_x = RAJA::LoopPolicy< RAJA::seq_exec, + RAJA::cuda_block_x_direct >; Here, the ``RAJA::LoopPolicy`` type holds both the host (CPU) and device (CUDA GPU) loop mapping strategies. On the host, both the team/thread diff --git a/docs/sphinx/user_guide/tutorial/matrix_transpose.rst b/docs/sphinx/user_guide/tutorial/matrix_transpose.rst index b3d4f0bda1..602f5efdd9 100644 --- a/docs/sphinx/user_guide/tutorial/matrix_transpose.rst +++ b/docs/sphinx/user_guide/tutorial/matrix_transpose.rst @@ -99,7 +99,7 @@ and number of blocks to launch is determined by the implementation of the For ``RAJA::launch`` variants, we use ``RAJA::loop`` methods to write a loop hierarchy within the kernel execution space. For a sequential implementation, we pass the ``RAJA::seq_launch_t`` template parameter -to the launch method and pass the ``RAJA::loop_exec`` parameter to the loop +to the launch method and pass the ``RAJA::seq_exec`` parameter to the loop methods. The complete sequential ``RAJA::launch`` variant is: .. literalinclude:: ../../../../exercises/launch-matrix-transpose_solution.cpp From 36f5ab424faedd426d2cb6294fe3a8b6d7031a7b Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Mon, 2 Oct 2023 17:21:27 +0200 Subject: [PATCH 045/193] Update radiuss-shared-ci to new release (with radiuss-spack-configs) --- .gitlab-ci.yml | 71 +++++++++++-------- .gitlab/custom-jobs-and-variables.yml | 16 ++--- .../corona.yml} | 2 +- .../lassen.yml} | 16 ++--- .../ruby.yml} | 20 +++--- .../tioga.yml} | 4 +- .gitlab/subscribed-pipelines.yml | 37 +++++++--- scripts/radiuss-spack-configs | 2 +- 8 files changed, 100 insertions(+), 68 deletions(-) rename .gitlab/{corona-build-and-test-extra.yml => jobs/corona.yml} (96%) rename .gitlab/{lassen-build-and-test-extra.yml => jobs/lassen.yml} (86%) rename .gitlab/{ruby-build-and-test-extra.yml => jobs/ruby.yml} (78%) rename .gitlab/{tioga-build-and-test-extra.yml => jobs/tioga.yml} (94%) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index be4161bc21..0b8a9e9ee2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,69 +1,82 @@ ############################################################################### -# Copyright (c) 2016-22, Lawrence Livermore National Security, LLC +# Copyright (c) 2016-23, Lawrence Livermore National Security, LLC # and RAJA project contributors. See the RAJA/LICENSE file for details. # # SPDX-License-Identifier: (BSD-3-Clause) ############################################################################### +# DESCRIPTION: ############################################################################### # General GitLab pipelines configurations for supercomputers and Linux clusters # at Lawrence Livermore National Laboratory (LLNL). -# # This entire pipeline is LLNL-specific # -# Important note: This file is a template provided by -# llnl/radiuss-shared-ci. Changes needed consists in setting variable values, -# change the reference to the radiuss-shared-ci repo, opt-in and out optional -# features. The project can then extend it with additional stages. +# Important note: This file is a template provided by llnl/radiuss-shared-ci. +# Remains to set variable values, change the reference to the radiuss-shared-ci +# repo, opt-in and out optional features. The project can then extend it with +# additional stages. # -# However, each project should provide: +# In addition, each project should copy over and complete: # - .gitlab/custom-jobs-and-variables.yml # - .gitlab/subscribed-pipelines.yml -# - .gitlab/${MACHINE}-build-and-test-extra.yml +# +# The jobs should be specified in a file local to the project, +# - .gitlab/jobs/${CI_MACHINE}.yml +# or generated (see LLNL/Umpire for an example). ############################################################################### # We define the following GitLab pipeline variables: variables: - MP_BRANCH: "develop" - GITHUB_PROJECT_NAME: "RAJA" - GITHUB_PROJECT_ORG: "LLNL" -# Use a service user to run CI. This prevents from running pipelines as an -# actual user. +##### LC GITLAB CONFIGURATION +# Use the umdev LLNL service user to run CI. This prevents from running +# pipelines as an actual user. LLNL_SERVICE_USER: rajasa -# Use a service user workspace. Solves permission issues, stores everything +# Use the service user workspace. Solves permission issues, stores everything # at the same location whoever triggers a pipeline. -# CUSTOM_CI_BUILDS_DIR: "" +# CUSTOM_CI_BUILDS_DIR: /usr/workspace/umdev/gitlab-runner # Tells Gitlab to recursively update the submodules when cloning the project. GIT_SUBMODULE_STRATEGY: recursive + +##### PROJECT VARIABLES + MP_BRANCH: "develop" # We build the projects in the CI clone directory. -# TODO: add a clean-up mechanism +# Used in script/gitlab/build_and_test.sh script. +# TODO: add a clean-up mechanism. BUILD_ROOT: ${CI_PROJECT_DIR} + +##### SHARED_CI CONFIGURATION +# Shared CI reference to use + SHARED_CI_REF: "v2023.09.0" +# Required information about GitHub repository + GITHUB_PROJECT_NAME: "RAJA" + GITHUB_PROJECT_ORG: "LLNL" # Set the build-and-test command. - BUILD_AND_TEST_CMD: "./scripts/gitlab/build_and_test.sh" -# Override the pattern describing branches that will skip the "draft PR test". -# Add protected branches here. See default value in + JOB_CMD: "./scripts/gitlab/build_and_test.sh" +# Override the pattern describing branches that will skip the "draft PR filter +# test". Add protected branches here. See default value in # preliminary-ignore-draft-pr.yml. ALWAYS_RUN_PATTERN: "^develop$|^main$|^v[0-9.]*-RC$" -# We organize the build-and-test stage in sub-pipelines. Each sub-pipeline +# We organize the build-and-test stage with sub-pipelines. Each sub-pipeline # corresponds to a test batch on a given machine. # High level stages stages: - - machine-checks + - prerequisites - build-and-test - - multi_project + - multi-project -# Template for jobs triggering a build-and-test sub-pipelines: +# Template for jobs triggering a build-and-test sub-pipeline: .build-and-test: stage: build-and-test trigger: include: - local: '.gitlab/custom-jobs-and-variables.yml' - project: 'radiuss/radiuss-shared-ci' - ref: v2023.08.0 - file: '${CI_MACHINE}-build-and-test.yml' - - local: '.gitlab/${CI_MACHINE}-build-and-test-extra.yml' + ref: '${SHARED_CI_REF}' + file: 'pipelines/${CI_MACHINE}.yml' + - artifact: '${CI_MACHINE}-jobs.yml' + job: 'generate-job-lists' strategy: depend forward: pipeline_variables: true @@ -74,7 +87,7 @@ stages: # This will prevent from sticking to a branch (here develop). # MP_BRANCH is short for "Multi-Project Branch" and will usually be develop. trigger-rajaperf: - stage: multi_project + stage: multi-project rules: - if: '$CI_COMMIT_BRANCH == "${MP_BRANCH}" || $MULTI_PROJECT == "ON"' #run only if ... variables: @@ -85,9 +98,9 @@ trigger-rajaperf: strategy: depend include: - # checks preliminary to running the actual CI test (optional) + # [Optional] checks preliminary to running the actual CI test - project: 'radiuss/radiuss-shared-ci' - ref: v2023.08.0 + ref: '${SHARED_CI_REF}' file: 'preliminary-ignore-draft-pr.yml' # pipelines subscribed by the project - local: '.gitlab/subscribed-pipelines.yml' diff --git a/.gitlab/custom-jobs-and-variables.yml b/.gitlab/custom-jobs-and-variables.yml index 935f5c23d0..fc6f3d1441 100644 --- a/.gitlab/custom-jobs-and-variables.yml +++ b/.gitlab/custom-jobs-and-variables.yml @@ -14,9 +14,9 @@ variables: # Ruby # Arguments for top level allocation - RUBY_BUILD_AND_TEST_SHARED_ALLOC: "--exclusive --reservation=ci --qos=ci_ruby --time=60 --nodes=2" + RUBY_SHARED_ALLOC: "--exclusive --reservation=ci --qos=ci_ruby --time=60 --nodes=2" # Arguments for job level allocation - RUBY_BUILD_AND_TEST_JOB_ALLOC: "--reservation=ci --qos=ci_ruby --time=45 --nodes=1" + RUBY_JOB_ALLOC: "--reservation=ci --qos=ci_ruby --time=45 --nodes=1" # Project specific variants for ruby PROJECT_RUBY_VARIANTS: "~shared +openmp +tests" # Project specific deps for ruby @@ -24,9 +24,9 @@ variables: # Corona # Arguments for top level allocation - CORONA_BUILD_AND_TEST_SHARED_ALLOC: "--exclusive --time-limit=60m --nodes=1" + CORONA_SHARED_ALLOC: "--exclusive --time-limit=60m --nodes=1" # Arguments for job level allocation - CORONA_BUILD_AND_TEST_JOB_ALLOC: "--time-limit=45m --nodes=1 --begin-time=+5s" + CORONA_JOB_ALLOC: "--time-limit=45m --nodes=1 --begin-time=+5s" # Project specific variants for corona PROJECT_CORONA_VARIANTS: "~shared ~openmp +tests" # Project specific deps for corona @@ -34,9 +34,9 @@ variables: # Tioga # Arguments for top level allocation - TIOGA_BUILD_AND_TEST_SHARED_ALLOC: "--exclusive --time-limit=60m --nodes=1" + TIOGA_SHARED_ALLOC: "--exclusive --time-limit=60m --nodes=1" # Arguments for job level allocation - TIOGA_BUILD_AND_TEST_JOB_ALLOC: "--time-limit=45m --nodes=1 --begin-time=+5s" + TIOGA_JOB_ALLOC: "--time-limit=45m --nodes=1 --begin-time=+5s" # Project specific variants for corona PROJECT_TIOGA_VARIANTS: "~shared ~openmp +tests" # Project specific deps for corona @@ -45,7 +45,7 @@ variables: # Lassen and Butte use a different job scheduler (spectrum lsf) that does not # allow pre-allocation the same way slurm does. # Arguments for job level allocation - LASSEN_BUILD_AND_TEST_JOB_ALLOC: "1 -W 60" + LASSEN_JOB_ALLOC: "1 -W 60" # Project specific variants for lassen PROJECT_LASSEN_VARIANTS: "~shared +openmp +tests cuda_arch=70" # Project specific deps for lassen @@ -55,7 +55,7 @@ variables: # Not all configuration can be shared. Here projects can fine tune the # CI behavior. # See Umpire for an example (export junit test reports). -.custom_build_and_test: +.custom_job: artifacts: reports: junit: junit.xml diff --git a/.gitlab/corona-build-and-test-extra.yml b/.gitlab/jobs/corona.yml similarity index 96% rename from .gitlab/corona-build-and-test-extra.yml rename to .gitlab/jobs/corona.yml index 87474144be..bd1e7b4fc9 100644 --- a/.gitlab/corona-build-and-test-extra.yml +++ b/.gitlab/jobs/corona.yml @@ -24,5 +24,5 @@ rocmcc_5_6_0_hip_desul_atomics: variables: SPEC: " ~shared +rocm ~openmp +tests +desul amdgpu_target=gfx906 %rocmcc@5.6.0 ^hip@5.6.0 ^blt@develop" - extends: .build_and_test_on_corona + extends: .job_on_corona diff --git a/.gitlab/lassen-build-and-test-extra.yml b/.gitlab/jobs/lassen.yml similarity index 86% rename from .gitlab/lassen-build-and-test-extra.yml rename to .gitlab/jobs/lassen.yml index fc0b65c450..f281dbde2a 100644 --- a/.gitlab/lassen-build-and-test-extra.yml +++ b/.gitlab/jobs/lassen.yml @@ -17,8 +17,8 @@ xl_2022_08_19_gcc_8_3_1_cuda_11_2_0: variables: SPEC: "${PROJECT_LASSEN_VARIANTS} +cuda cxxflags==\"-qthreaded -std=c++14 -O3 -qstrict -qxlcompatmacros -qlanglvl=extended0x -qalias=noansi -qhot -qpic -qsmp=omp -qsuppress=1500-029 -qsuppress=1500-036\" %xl@16.1.1.12.gcc.8.3.1 ^cuda@11.2.0+allow-unsupported-compilers ${PROJECT_LASSEN_DEPS}" MODULE_LIST: "cuda/11.2.0" - LASSEN_BUILD_AND_TEST_JOB_ALLOC: "1 -W 120" - extends: .build_and_test_on_lassen + LASSEN_JOB_ALLOC: "1 -W 120" + extends: .job_on_lassen ############ @@ -31,14 +31,14 @@ xl_2022_08_19_gcc_8_3_1_cuda_11_2_0: gcc_8_3_1_omptask: variables: SPEC: " ~shared +openmp +omptask +tests %gcc@8.3.1" - extends: .build_and_test_on_lassen + extends: .job_on_lassen gcc_8_3_1_cuda_11_5_0_ats_disabled: - extends: .build_and_test_on_lassen + extends: .job_on_lassen variables: SPEC: " ~shared +openmp +tests +cuda %gcc@8.3.1 cuda_arch=70 ^cuda@11.5.0+allow-unsupported-compilers" MODULE_LIST: "cuda/11.5.0" - LASSEN_BUILD_AND_TEST_JOB_ALLOC: "1 --atsdisable -W 60" + LASSEN_JOB_ALLOC: "1 --atsdisable -W 60" ########## # OTHERS @@ -47,16 +47,16 @@ gcc_8_3_1_cuda_11_5_0_ats_disabled: clang_13_0_1_libcpp: variables: SPEC: " ~shared +openmp +tests %clang@13.0.1 cflags==\"-DGTEST_HAS_CXXABI_H_=0\" cxxflags==\"-stdlib=libc++ -DGTEST_HAS_CXXABI_H_=0\"" - extends: .build_and_test_on_lassen + extends: .job_on_lassen #clang_14_0_5_asan: # variables: # SPEC: " ~shared +openmp +tests %clang@14.0.5 cxxflags==\"-fsanitize=address\" " # ASAN_OPTIONS: "detect_leaks=1" # LSAN_OPTIONS: "suppressions=${CI_PROJECT_DIR}/suppressions.asan" -# extends: .build_and_test_on_lassen +# extends: .job_on_lassen gcc_8_3_1_cuda_10_1_243_desul_atomics: variables: SPEC: " ~shared +openmp +tests +cuda +desul %gcc@8.3.1 cuda_arch=70 ^cuda@10.1.243+allow-unsupported-compilers" - extends: .build_and_test_on_lassen + extends: .job_on_lassen diff --git a/.gitlab/ruby-build-and-test-extra.yml b/.gitlab/jobs/ruby.yml similarity index 78% rename from .gitlab/ruby-build-and-test-extra.yml rename to .gitlab/jobs/ruby.yml index ae3cdcf2d4..53bc33c8ea 100644 --- a/.gitlab/ruby-build-and-test-extra.yml +++ b/.gitlab/jobs/ruby.yml @@ -15,25 +15,25 @@ clang_14_0_6: variables: SPEC: " ~shared +openmp +omptask +tests %clang@14.0.6" - extends: .build_and_test_on_ruby + extends: .job_on_ruby gcc_10_3_1: variables: SPEC: " ~shared +openmp +omptask +tests %gcc@10.3.1" - RUBY_BUILD_AND_TEST_JOB_ALLOC: "--time=60 --nodes=1" - extends: .build_and_test_on_ruby + RUBY_JOB_ALLOC: "--time=60 --nodes=1" + extends: .job_on_ruby intel_19_1_2_gcc_10_3_1: variables: SPEC: " ~shared +openmp +omptask +tests %intel@19.1.2.gcc.10.3.1" - RUBY_BUILD_AND_TEST_JOB_ALLOC: "--time=90 --nodes=1" - extends: .build_and_test_on_ruby + RUBY_JOB_ALLOC: "--time=90 --nodes=1" + extends: .job_on_ruby intel_2022_1_0: variables: SPEC: "${PROJECT_RUBY_VARIANTS} %intel@2022.1.0 ${PROJECT_RUBY_DEPS}" allow_failure: true - extends: .build_and_test_on_ruby + extends: .job_on_ruby ############ # Extra jobs @@ -45,16 +45,16 @@ intel_2022_1_0: clang_14_0_6_openmp_off: variables: SPEC: " ~shared ~openmp +tests %clang@14.0.6" - extends: .build_and_test_on_ruby + extends: .job_on_ruby gcc_10_3_1_openmp_default: variables: SPEC: " ~shared +tests %gcc@10.3.1" - RUBY_BUILD_AND_TEST_JOB_ALLOC: "--time=60 --nodes=1" - extends: .build_and_test_on_ruby + RUBY_JOB_ALLOC: "--time=60 --nodes=1" + extends: .jobs_on_ruby # OTHERS clang_14_0_6_gcc_10_3_1_desul_atomics: variables: SPEC: " ~shared +openmp +tests +desul %clang@14.0.6.gcc.10.3.1" - extends: .build_and_test_on_ruby + extends: .jobs_on_ruby diff --git a/.gitlab/tioga-build-and-test-extra.yml b/.gitlab/jobs/tioga.yml similarity index 94% rename from .gitlab/tioga-build-and-test-extra.yml rename to .gitlab/jobs/tioga.yml index bbf60ad430..17daf7d202 100644 --- a/.gitlab/tioga-build-and-test-extra.yml +++ b/.gitlab/jobs/tioga.yml @@ -24,9 +24,9 @@ rocmcc_5_6_0_hip_desul_atomics: variables: SPEC: "~shared +rocm ~openmp +desul +tests amdgpu_target=gfx90a %rocmcc@5.6.0 ^hip@5.6.0 ^blt@develop" - extends: .build_and_test_on_tioga + extends: .job_on_tioga rocmcc_5_6_0_hip_openmp: variables: SPEC: "~shared +rocm +openmp +omptask +tests amdgpu_target=gfx90a %rocmcc@5.6.0 ^hip@5.6.0 ^blt@develop" - extends: .build_and_test_on_tioga + extends: .job_on_tioga diff --git a/.gitlab/subscribed-pipelines.yml b/.gitlab/subscribed-pipelines.yml index 8e9e34a552..ecd7f5b360 100644 --- a/.gitlab/subscribed-pipelines.yml +++ b/.gitlab/subscribed-pipelines.yml @@ -8,7 +8,7 @@ # The template job to test whether a machine is up. # Expects CI_MACHINE defined to machine name. .machine-check: - stage: machine-checks + stage: prerequisites tags: [shell, oslic] variables: GIT_STRATEGY: none @@ -29,52 +29,71 @@ # Comment the jobs for machines you don’t need. ### +# One job to generate the job list for all the subpipelines +generate-job-lists: + stage: prerequisites + tags: [shell, oslic] + variables: + RADIUSS_JOBS_PATH: "scripts/radiuss-spack-configs/gitlab/radiuss-jobs" + LOCAL_JOBS_PATH: ".gitlab/jobs" + script: + - cat ${RADIUSS_JOBS_PATH}/ruby.yml ${LOCAL_JOBS_PATH}/ruby.yml > ruby-jobs.yml + - cat ${RADIUSS_JOBS_PATH}/lassen.yml ${LOCAL_JOBS_PATH}/lassen.yml > lassen-jobs.yml + - cat ${RADIUSS_JOBS_PATH}/corona.yml ${LOCAL_JOBS_PATH}/corona.yml > corona-jobs.yml + - cat ${RADIUSS_JOBS_PATH}/tioga.yml ${LOCAL_JOBS_PATH}/tioga.yml > tioga-jobs.yml + artifacts: + paths: + - ruby-jobs.yml + - lassen-jobs.yml + - corona-jobs.yml + - tioga-jobs.yml + # RUBY ruby-up-check: variables: CI_MACHINE: "ruby" - extends: [.machine-check] + extends: [.machine-check, generate-job-lists] ruby-build-and-test: variables: CI_MACHINE: "ruby" needs: [ruby-up-check] - extends: [.build-and-test] + extends: [.build-and-test, generate-job-lists] # CORONA corona-up-check: variables: CI_MACHINE: "corona" - extends: [.machine-check] + extends: [.machine-check, generate-job-lists] corona-build-and-test: variables: CI_MACHINE: "corona" needs: [corona-up-check] - extends: [.build-and-test] + extends: [.build-and-test, generate-job-lists] # TIOGA tioga-up-check: variables: CI_MACHINE: "tioga" - extends: [.machine-check] + extends: [.machine-check, generate-job-lists] tioga-build-and-test: variables: CI_MACHINE: "tioga" needs: [tioga-up-check] - extends: [.build-and-test] + extends: [.build-and-test, generate-job-lists] # LASSEN lassen-up-check: variables: CI_MACHINE: "lassen" - extends: [.machine-check] + extends: [.machine-check, generate-job-lists] lassen-build-and-test: variables: CI_MACHINE: "lassen" needs: [lassen-up-check] - extends: [.build-and-test] + extends: [.build-and-test, generate-job-lists] diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index bdf3d423b9..56c30b4ac5 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit bdf3d423b92324668db91a151b6d400507562282 +Subproject commit 56c30b4ac50b49240ef4c8ef5441456f02c550f8 From fcc73b8789286010b8dc2ecac9015c13482e7692 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Mon, 2 Oct 2023 17:36:02 +0200 Subject: [PATCH 046/193] Fix --- .gitlab/subscribed-pipelines.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.gitlab/subscribed-pipelines.yml b/.gitlab/subscribed-pipelines.yml index ecd7f5b360..1a65b52a37 100644 --- a/.gitlab/subscribed-pipelines.yml +++ b/.gitlab/subscribed-pipelines.yml @@ -52,48 +52,48 @@ generate-job-lists: ruby-up-check: variables: CI_MACHINE: "ruby" - extends: [.machine-check, generate-job-lists] + extends: [.machine-check] ruby-build-and-test: variables: CI_MACHINE: "ruby" - needs: [ruby-up-check] - extends: [.build-and-test, generate-job-lists] + needs: [ruby-up-check, generate-job-lists] + extends: [.build-and-test] # CORONA corona-up-check: variables: CI_MACHINE: "corona" - extends: [.machine-check, generate-job-lists] + extends: [.machine-check] corona-build-and-test: variables: CI_MACHINE: "corona" - needs: [corona-up-check] - extends: [.build-and-test, generate-job-lists] + needs: [corona-up-check, generate-job-lists] + extends: [.build-and-test] # TIOGA tioga-up-check: variables: CI_MACHINE: "tioga" - extends: [.machine-check, generate-job-lists] + extends: [.machine-check] tioga-build-and-test: variables: CI_MACHINE: "tioga" - needs: [tioga-up-check] - extends: [.build-and-test, generate-job-lists] + needs: [tioga-up-check, generate-job-lists] + extends: [.build-and-test] # LASSEN lassen-up-check: variables: CI_MACHINE: "lassen" - extends: [.machine-check, generate-job-lists] + extends: [.machine-check] lassen-build-and-test: variables: CI_MACHINE: "lassen" - needs: [lassen-up-check] - extends: [.build-and-test, generate-job-lists] + needs: [lassen-up-check, generate-job-lists] + extends: [.build-and-test] From ea690ab1d8697ee36fb36a33a9fc4dd982c5ffb6 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Mon, 2 Oct 2023 18:00:32 +0200 Subject: [PATCH 047/193] Fix --- .gitlab-ci.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0b8a9e9ee2..e4c6583aaa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -45,8 +45,6 @@ variables: BUILD_ROOT: ${CI_PROJECT_DIR} ##### SHARED_CI CONFIGURATION -# Shared CI reference to use - SHARED_CI_REF: "v2023.09.0" # Required information about GitHub repository GITHUB_PROJECT_NAME: "RAJA" GITHUB_PROJECT_ORG: "LLNL" @@ -73,7 +71,7 @@ stages: include: - local: '.gitlab/custom-jobs-and-variables.yml' - project: 'radiuss/radiuss-shared-ci' - ref: '${SHARED_CI_REF}' + ref: 'v2023.09.0' file: 'pipelines/${CI_MACHINE}.yml' - artifact: '${CI_MACHINE}-jobs.yml' job: 'generate-job-lists' @@ -100,7 +98,7 @@ trigger-rajaperf: include: # [Optional] checks preliminary to running the actual CI test - project: 'radiuss/radiuss-shared-ci' - ref: '${SHARED_CI_REF}' + ref: 'v2023.09.0' file: 'preliminary-ignore-draft-pr.yml' # pipelines subscribed by the project - local: '.gitlab/subscribed-pipelines.yml' From 20fb1ea3525ef9a81e173be3940dd81efcac88a3 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Mon, 2 Oct 2023 18:02:05 +0200 Subject: [PATCH 048/193] Fix --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e4c6583aaa..ef7e46622d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -99,6 +99,6 @@ include: # [Optional] checks preliminary to running the actual CI test - project: 'radiuss/radiuss-shared-ci' ref: 'v2023.09.0' - file: 'preliminary-ignore-draft-pr.yml' + file: 'utilities/preliminary-ignore-draft-pr.yml' # pipelines subscribed by the project - local: '.gitlab/subscribed-pipelines.yml' From f6e30bcf978c35fb319dadf82ad061656e7455c1 Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Mon, 2 Oct 2023 18:35:19 +0200 Subject: [PATCH 049/193] Fix --- .gitlab/jobs/ruby.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab/jobs/ruby.yml b/.gitlab/jobs/ruby.yml index 53bc33c8ea..2d157c8c86 100644 --- a/.gitlab/jobs/ruby.yml +++ b/.gitlab/jobs/ruby.yml @@ -51,10 +51,10 @@ gcc_10_3_1_openmp_default: variables: SPEC: " ~shared +tests %gcc@10.3.1" RUBY_JOB_ALLOC: "--time=60 --nodes=1" - extends: .jobs_on_ruby + extends: .job_on_ruby # OTHERS clang_14_0_6_gcc_10_3_1_desul_atomics: variables: SPEC: " ~shared +openmp +tests +desul %clang@14.0.6.gcc.10.3.1" - extends: .jobs_on_ruby + extends: .job_on_ruby From 713e802ebeb0cf750c907976598e5ce5468b987a Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:19:19 +0200 Subject: [PATCH 050/193] Adapt documentation --- docs/sphinx/dev_guide/ci.rst | 101 ++++++++------- docs/sphinx/dev_guide/ci_tasks.rst | 190 ++++++++++++++--------------- 2 files changed, 151 insertions(+), 140 deletions(-) diff --git a/docs/sphinx/dev_guide/ci.rst b/docs/sphinx/dev_guide/ci.rst index 7308c29f48..9462155e8e 100644 --- a/docs/sphinx/dev_guide/ci.rst +++ b/docs/sphinx/dev_guide/ci.rst @@ -142,8 +142,10 @@ The relationships among these dependencies in a project that uses them is described in the `RADIUSS Shared CI User Guide `_ along with information about how the framework works and how to set up a project to use it. -.. important:: The RAJA Spack package is maintained in the `RADIUSS Spack Configs `_ project. After packages are -updated there, they are pushed to the Spack repo on GitHub via a pull request. +.. important:: The RAJA Spack package is maintained in the `RADIUSS Spack + Configs `_ project. After + packages are updated there, they are pushed to the Spack repo on GitHub via + a pull request. The remainder of this section describes files in the RAJA repo that are used to configure and customize the shared CI framework specifically for the @@ -166,22 +168,34 @@ support LC GitLab CI testing. Briefly, these files play the following roles in GitLab CI testing: - * The `RAJA/.gitlab-ci.yml `_ file is the top-level file for GitLab CI configuration. It defines - variables used in all GitLab pipelines such as - GitHub project name and organization, service user account name, version - information for RADIUSS Shared CI project we are using, and - top-level information for triggering build-and-test sub-pipelines. - * The `RAJA/.uberenv_config.json `_ file defines information about Spack such as - Spack version we are using, location of Spack packages, etc. - * The `RAJA/.gitlab `_ - directory contains several files that connect RAJA GitLab pipelines to - shared pipelines defined in the - `RADIUSS Shared CI `_ project, - as well as RAJA-specific jobs and shared job customizations that we use, - such as job time limits, etc. These files are modified from templates - provided by the RADIUSS Shared CI project. - * The `RAJA/scripts/gitlab/build_and_test.sh `_ contains commands that are run - during the RAJA build and test process. + * The `RAJA/.gitlab-ci.yml + `_ file is the + top-level file for GitLab CI configuration. It defines variables used in + all GitLab pipelines such as GitHub project name and organization, service + user account name, version information for RADIUSS Shared CI project we are + using, and top-level information for triggering build-and-test + sub-pipelines. + * The `RAJA/.uberenv_config.json + `_ file + defines information about Spack such as Spack version we are using, + location of Spack packages, etc. + * The `RAJA/.gitlab `_ + directory contains several files that connect RAJA GitLab pipelines to + shared pipelines defined in the `RADIUSS Shared CI + `_ project, as well as + RAJA-specific jobs and global job customizations that we use, such as job + time limits, etc. These files are modified from templates provided by the + RADIUSS Shared CI project. + * In particular, `RAJA/.gitlab/jobs + `_ directory + contains the files defining RAJA specific jobs per machine. This file is + appended to the list of shared CI jobs provided by `RADIUSS Spack Configs + `_. Each job ultimately consists + in one Spack spec. + * The `RAJA/scripts/gitlab/build_and_test.sh + `_ + contains commands that are run during the RAJA build and test process. It is + set in the CI using the ``JOB_CMD`` variable. In the following sections, we discuss how these files are used in the steps of the RAJA GitLab CI testing process summarized above. @@ -203,53 +217,52 @@ allocated to run test jobs on various LC platforms and common build configuration variants for those platforms Each job that is run is defined by a Spack spec in one of two places, depending -on whether it is *shared* with other projects or it is specific to RAJA. The -shared jobs are defined in files named ``-build-and-test.yml`` in -the top-level directory of the -`RADIUSS Shared CI Project `_. -Overrides (modifications) of those jobs and other RAJA-specific jobs are -defined in ``RAJA/.gitlab/-build-and-test-extra.yml`` files. - -**Each shared job will be run as-is unless it is overridden** in the RAJA -'extra' file for the corresponding machine. For example, a shared job for the -LC ruby machine may appear in the RADIUSS Shared CI file -``ruby-build-and-test.yml`` as:: +on whether it is *shared* with other projects or it is specific to RAJA. The +shared jobs are defined in files located in ``gitlab/jobs/.yml`` in +the `RADIUSS Spack Configs Project +`_. Overrides (modifications) of +those jobs and other RAJA-specific jobs are defined in +``RAJA/.gitlab/jobs/.yml`` files. + +**Each shared job will be run as-is unless it is overridden** in the RAJA local +jobs file for the corresponding machine. For example, a shared job for the LC +ruby machine may appear in the RADIUSS Spack Configs file +``gitlab/jobs/ruby.yml`` as:: gcc_8_1_0: variables: SPEC: "${PROJECT_RUBY_VARIANTS} %gcc@8.1.0 ${PROJECT_RUBY_DEPS}" - extends: .build_and_test_on_ruby + extends: .job_on_ruby -and then may be overridden in the ``RAJA/.gitlab/ruby-build-and-test-extra.yml`` +and then may be overridden in the ``RAJA/.gitlab/jobs/ruby.yml`` file as:: gcc_8_1_0: variables: SPEC: " ${PROJECT_RUBY_VARIANTS} %gcc@8.1.0 ${PROJECT_RUBY_DEPS}" - RUBY_BUILD_AND_TEST_JOB_ALLOC: "--time=60 --nodes=1" - extends: .build_and_test_on_ruby + RUBY_JOB_ALLOC: "--time=60 --nodes=1" + extends: .job_on_ruby In this example, the Spack build spec is the same, but the job is configured with a specific timeout limit and number of nodes appropriate for RAJA testing. -.. important:: A shared job override **must use the same job label as the - shared job** defined in the RADIUSS Shared CI project. +.. important:: A shared job override **must use the same job label as the + shared job** defined in the RADIUSS Shared CI project. -RAJA-specific jobs whose configurations are not shared with other projects -are also defined in the -``RAJA/.gitlab/-build-and-test-extra.yml`` files. For example:: +RAJA-specific jobs whose configurations are not shared with other projects are +also defined in the ``RAJA/.gitlab/jobs/.yml`` files. For example:: clang_10_0_1_gcc_8_3_1_desul_atomics: variables: SPEC: " ~shared +openmp +tests +desul %clang@10.0.1 cxxflags=--gcc-toolchain=/usr/tce/packages/gcc/gcc-8.3.1 cflags=--gcc-toolchain=/usr/tce/packages/gcc/gcc-8.3.1" - extends: .build_and_test_on_ruby + extends: .job_on_ruby defines a RAJA job with desul atomics enabled to be run on the ruby machine. -.. important:: Each base compiler configuration that is used in GitLab CI - testing must have a Spack spec defined for it in the appropriate - file for the machine that it will be tested on in the - `RADIUSS Spack Configs `_ project. +.. important:: Each base compiler configuration that is used in GitLab CI + testing must have a Spack spec defined for it in the appropriate file for + the machine that it will be tested on in the `RADIUSS Spack Configs + `_ project. .. _gitlab_ci_running-label: @@ -309,7 +322,7 @@ A summary of the configurations we build are: for the Windows test builds. For example, we build and test RAJA as a static and shared library. This is indicated in the Windows ``strategy`` section:: - + strategy: matrix: shared: diff --git a/docs/sphinx/dev_guide/ci_tasks.rst b/docs/sphinx/dev_guide/ci_tasks.rst index da7b47223f..fe7821ef30 100644 --- a/docs/sphinx/dev_guide/ci_tasks.rst +++ b/docs/sphinx/dev_guide/ci_tasks.rst @@ -8,18 +8,18 @@ .. _ci_tasks-label: -****************************************************** +***************************************************** Continuous Integration (CI) Testing Maintenance Tasks -****************************************************** +***************************************************** In :ref:`ci-label`, we described RAJA CI workflows. This section describes how to perform common RAJA CI testing maintenance tasks. .. _gitlab_ci_tasks-label: -================= +=============== GitLab CI Tasks -================= +=============== The tasks in this section apply to GitLab CI testing on Livermore Computing (LC) platforms. LC folks and others maintain Confluence pages @@ -27,37 +27,35 @@ with a lot of useful information for setting up and maintaining GitLab CI for a project, mirroring a GitHub to GitLab, etc. Please refer to `LC GitLab CI `_ for such information. Changing build and test configurations ----------------------------------------- +-------------------------------------- The build for each test we run is defined by a Spack spec in one of two places, depending on whether it is *shared* with other projects or it is specific to RAJA. The details are described in :ref:`gitlab_ci_pipelines-label`. Remove a configuration -^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^ -To remove a RAJA-specific test configuration, simply delete the entry for it -in the ``RAJA/.gitlab/-build-and-test-extra.yml`` file where it is -defined. Here, ``MACHINE`` is the name of an LC platform where GitLab CI is -run. +To remove a RAJA-specific test configuration, simply delete the entry for it in +the ``RAJA/.gitlab/jobs/.yml`` file where it is defined. Here, +``MACHINE`` is the name of an LC platform where GitLab CI is run. To remove a shared configuration, it must be removed from the appropriate -``-build-and-test.yml`` file in the -`RADIUSS Shared CI `_ project. -Create a branch there, remove the job entry, and create a pull request. +``gitlab/jobs/.yml`` file in the `RADIUSS Spack Configs +`_ project. Create a branch +there, remove the job entry, and create a pull request. -.. important:: The RADIUSS Shared CI project is used by several other projects. - When changing a shared configuration file, please make sure the - change is OK with those other projects. +.. important:: The RADIUSS Spack Configs project is used by several other + projects. When changing a shared configuration file, please make sure the + change is OK with those other projects. Add a configuration -^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^ -To add a RAJA-specific test configuration, add an entry for it to the -``RAJA/.gitlab/-build-and-test-extra.yml`` file, where ``MACHINE`` -is the name of the LC platform where it will be run. When adding a -test configuration, it is important to note two items that must be -specified properly: +To add a RAJA-specific test configuration, add an entry for it to the +``RAJA/.gitlab/jobs/.yml`` file, where ``MACHINE`` is the name of the +LC platform where it will be run. When adding a test configuration, it is +important to note two items that must be specified properly: * A unique **job label**, which identifies it in the machine configuration file and also on a web page for a GitLab CI pipeline @@ -72,49 +70,47 @@ For example, an entry for a build using the clang 12.0.1 compiler with CUDA clang_12_0_1_cuda_11_5_0: variables: SPEC: " ~shared +openmp +tests +cuda cuda_arch=70 %clang@12.0.1 ^cuda@11.5.0" - extends: .build_and_test_on_lassen + extends: .job_on_lassen Here, we enable OpenMP and CUDA, both of which must be enabled to test those RAJA back-ends, and specify the CUDA target architecture 'sm_70'. To add a shared configuration, it must be added to the appropriate -``-build-and-test.yml`` file in the -`RADIUSS Shared CI `_ project. -Create a branch there, add the job entry, and create a pull request. +``.gitlab/jobs/.yml`` file in the `RADIUSS Spack Configs +`_ project. Create a branch +there, add the job entry, and create a pull request. -.. important:: The RADIUSS Shared CI project is used by several other projects. - When changing a shared configuration file, please make sure the - change is OK with those other projects. +.. important:: The RADIUSS Spack Configs project is used by several other + projects. When changing a shared configuration file, please make sure the + change is OK with those other projects. Modifying a configuration -^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^ -To change an existing configuration, change the relevant information in the -configuration in the appropriate -``RAJA/.gitlab/-build-and-test-extra.yml`` file. Make sure to -also modify the job label as needed, so it is descriptive of the configuration -(and remains unique!!). +To change an existing configuration, change the relevant information in the +configuration in the appropriate ``RAJA/.gitlab/jobs/.yml`` file. Make +sure to also modify the job label as needed, so it is descriptive of the +configuration (and remains unique!!). To modify a shared configuration, it must be changed in the appropriate -``-build-and-test.yml`` file in the -`RADIUSS Shared CI `_ project. -Create a branch there, modify the job entry, and create a pull request. - -.. important:: Build spec information used in RAJA GitLab CI pipelines - must exist in the ``compilers.yaml`` file and/or - ``packages.yaml`` file for the appropriate system type in - the `RADIUSS Spack Configs `_ repo. - - If the desired entry is not there, but exists in a newer version - of the RADIUSS Spack Configs project, update the RAJA submodule - to use the newer version. If the information does not exist in - any version of the RADIUSS Spack Configs project, create a - branch there, add the needed spec info, and create a pull - request. Then, when that PR is merged, update the RAJA submodule - for the RADIUSS Spack Configs project to the new version. +``gitlab/jobs/.yml`` file in the `RADIUSS Spack Configs +`_ project. Create a branch +there, modify the job entry, and create a pull request. + +.. important:: Build spec information used in RAJA GitLab CI pipelines must + exist in the ``compilers.yaml`` file and/or ``packages.yaml`` file for the + appropriate system type in the `RADIUSS Spack Configs + `_ repo. + + If the desired entry is not there, but exists in a newer version of the RADIUSS + Spack Configs project, update the RAJA submodule to use the newer version. If + the information does not exist in any version of the RADIUSS Spack Configs + project, create a branch there, add the needed spec info, and create a pull + request. Then, when that PR is merged, update the RAJA submodule for the + RADIUSS Spack Configs project to the new version. Changing run parameters -^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^ The parameters for each system/scheduler on which we run GitLab CI for RAJA, such as job time limits, resource allocations, etc. are defined in the @@ -122,11 +118,10 @@ RAJA, such as job time limits, resource allocations, etc. are defined in the remain as is, for the most part, and should not be changed unless absolutely necessary. -For example, sometimes a particular job will take longer to build and run -than the default allotted time for jobs on a machine. In this case, the -time for the job can be adjusted in the job entry in the associated -``RAJA/.gitlab/-build-and-test-extra.yml`` file. -For example: +For example, sometimes a particular job will take longer to build and run than +the default allotted time for jobs on a machine. In this case, the time for the +job can be adjusted in the job entry in the associated +``RAJA/.gitlab/jobs/.yml`` file. For example: .. code-block:: bash @@ -134,13 +129,13 @@ For example: variables: SPEC: " ${PROJECT_RUBY_VARIANTS} %gcc@8.1.0 ${PROJECT_RUBY_DEPS}" RUBY_BUILD_AND_TEST_JOB_ALLOC: "--time=60 --nodes=1" - extends: .build_and_test_on_ruby + extends: .job_on_ruby This example sets the build and test allocation time to 60 minutes and the the run resource to one node. Allowing failures -^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^ Sometimes a shared job configuration is known to fail for RAJA. To allow the job to fail without the CI check associated with it failing, we can @@ -151,31 +146,30 @@ annotate the job for this. For example: ibm_clang_9_0_0: variables: SPEC: " ${PROJECT_LASSEN_VARIANTS} %clang@ibm.9.0.0 ${PROJECT_LASSEN_DEPS}" - extends: .build_and_test_on_lassen + extends: .job_on_lassen allow_failure: true -.. important:: When a shared job needs to be modified for RAJA specifically, - we call that "overriding": The job label must be kept the same - as in the ``-build-and-test.yml`` file in the - `RADIUSS Shared CI `_, - and the RAJA-specific job can be adapted. If you override a - shared job, please add a comment to describe the change in the - ``RAJA/.gitlab/-build-and-test-extra.yml`` file where - the job is overridden. +.. important:: When a shared job needs to be modified for RAJA specifically, we + call that "overriding": The job label must be kept the same as in the + ``.gitlab/jobs/.yml`` file in the `RADIUSS Spack Configs + `_, and the RAJA-specific job + can be adapted. If you override a shared job, please add a comment to + describe the change in the ``RAJA/.gitlab/jobs/.yml`` file where + the job is overridden. -================= +============== Azure CI Tasks -================= +============== The tasks in this section apply to RAJA Azure Pipelines CI. Changing Builds/Container Images ---------------------------------------- +-------------------------------- The builds we run in Azure are defined in the `RAJA/azure-pipelines.yml `_ file. Linux/Docker -^^^^^^^^^^^^^ +^^^^^^^^^^^^ To update or add a new compiler / job to Azure CI we need to edit both ``azure-pipelines.yml`` and ``Dockerfile``. @@ -209,7 +203,7 @@ The base containers are shared across multiple projects and are regularly rebuil Check `here `_ for a list of all currently available RSE-Ops containers. Please see the `RSE-Ops Containers Project `_ on GitHub to get new containers built that aren't yet available. Windows / MacOS -^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^ We run our Windows / MacOS builds directly on the Azure virtual machine instances. In order to update the Windows / MacOS instance we can change the ``pool`` under ``-job: Windows`` or ``-job: Mac``:: @@ -227,7 +221,7 @@ Changing Build/Run Parameters ----------------------------- Linux/Docker -^^^^^^^^^^^^^^ +^^^^^^^^^^^^ We can edit the build and run configurations of each docker build, in the ``RUN`` command. Such as adding CMake options or changing the parallel build value of ``make -j N`` for adjusting throughput. @@ -250,7 +244,7 @@ Each base image is built using `spack `_. For th source /opt/view/setvars.sh Windows / MacOS -^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^ Windows and MacOS build / run parameters can be configured directly in ``azure-pipelines.yml``. CMake options can be configured with ``CMAKE_EXTRA_FLAGS`` for each job. The ``-j`` value can also be edited directly in the Azure ``script`` definitions for each job. @@ -264,30 +258,34 @@ matches an entry in the Docker test matrix in the .. _rajaperf_ci_tasks-label: -================================ +=============================== RAJA Performance Suite CI Tasks -================================ +=============================== The `RAJA Performance Suite `_ project CI -testing processes, directory/file structure, and dependencies are nearly -identical to that for RAJA, which is described in :ref:`ci-label`. Specifically, - - * The RAJA Performance Suite GitLab CI process is driven by the - `RAJAPerf/.gitlab-ci.yml `_ file. - * The ``-jobs.yml`` and ``-templates.yml`` files reside - in the - `RAJAPerf/.gitlab `_ - directory. - * The ``build_and_test.sh`` script resides in the `RAJAPerf/scripts/gitlab `_ directory. - * The `RAJAPerf/Dockerfile `_ drives the Azure testing pipelines. - -The Performance Suite GitLab CI uses the ``uberenv`` and -``radiuss-spack-configs`` versions located in -the RAJA submodule to make the testing consistent across projects and avoid -redundancy. This is reflected in the -`RAJAPerf/.uberenv_config.json `_ -file which point at the relevant RAJA submodule locations. That is the paths -contain ``tpl/RAJA/...``. +testing processes, directory/file structure, and dependencies are nearly +identical to that for RAJA, which is described in :ref:`ci-label`. +Specifically, + + * The RAJA Performance Suite GitLab CI process is driven by the + `RAJAPerf/.gitlab-ci.yml + `_ file. + * The ``custom-jobs-and-variables.yml`` and ``subscribed-pipelines.yml`` + files reside in the `RAJAPerf/.gitlab + `_ directory. + * The ``build_and_test.sh`` script resides in the `RAJAPerf/scripts/gitlab + `_ directory. + * The `RAJAPerf/Dockerfile + `_ drives the + Azure testing pipelines. + +The Performance Suite GitLab CI uses the ``uberenv`` and +``radiuss-spack-configs`` versions located in the RAJA submodule to make the +testing consistent across projects and avoid redundancy. This is reflected in +the `RAJAPerf/.uberenv_config.json +`_ file +which point at the relevant RAJA submodule locations. That is the paths contain +``tpl/RAJA/...``. Apart from this minor difference, all CI maintenance and development tasks for the RAJA Performance Suite follow the same pattern that is described in From fa244b24c48af79e70d2354a9c425d7c5c314ead Mon Sep 17 00:00:00 2001 From: "Adrien M. BERNEDE" <51493078+adrienbernede@users.noreply.github.com> Date: Tue, 3 Oct 2023 15:12:46 +0200 Subject: [PATCH 051/193] Some doc fixes --- docs/sphinx/dev_guide/ci.rst | 49 ++++++++++-------- docs/sphinx/dev_guide/ci_tasks.rst | 8 +-- .../dev_guide/figures/RAJA-Gitlab-Files.png | Bin 263039 -> 750803 bytes 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/docs/sphinx/dev_guide/ci.rst b/docs/sphinx/dev_guide/ci.rst index 9462155e8e..55346f0bb6 100644 --- a/docs/sphinx/dev_guide/ci.rst +++ b/docs/sphinx/dev_guide/ci.rst @@ -131,15 +131,16 @@ collaboratively with other projects. These include that helps to simplify the workflow of Spack and other tools for building third-party dependencies. Uberenv is a submodule in RAJA that lives in ``RAJA/scripts/uberenv/``. - * `RADIUSS Spack Configs `_, - a collection of Spack compiler and package configurations used by Spack - to generate build configurations. The build configurations are - specific to LLNL LC platforms. Spack packages for multiple projects are - maintained in this project. RADIUSS Spack Configs is a submodule in RAJA - that lives in ``RAJA/scripts/radiuss-spack-configs/``. + * `RADIUSS Spack Configs `_, a + collection of Spack compiler and package configurations used by Spack to + generate build configurations. The build configurations are specific to + LLNL LC platforms. Spack packages for multiple projects are maintained in + this project. Shared RADIUSS CI jobs are also hosted by this project as + they relate to the Spack configuration. RADIUSS Spack Configs is a + submodule in RAJA that lives in ``RAJA/scripts/radiuss-spack-configs/``. The relationships among these dependencies in a project that uses them is -described in the `RADIUSS Shared CI User Guide `_ along with information about +described in the `RADIUSS Shared CI User Guide `_ along with information about how the framework works and how to set up a project to use it. .. important:: The RAJA Spack package is maintained in the `RADIUSS Spack @@ -161,20 +162,22 @@ support LC GitLab CI testing. .. figure:: ./figures/RAJA-Gitlab-Files.png - The figure shows directories and files in the RAJA repo that support GitLab - CI testing. Files in blue are specific to RAJA and are maintained in the - RAJA repo. Red directories and files correspond to Git submodules that are - shared and maintained with other projects. + The figure shows directories and files in the RAJA repo that support GitLab + CI testing. Files in blue are specific to the CI while those in red relates + to the build (Spack) environment description. The ``build_and_test.sh`` + scripts stands at the interface between CI and Spack. ``uberenv`` and + ``radiuss-spack-configs`` are both Git submodules that are shared and + maintained with other projects. Briefly, these files play the following roles in GitLab CI testing: * The `RAJA/.gitlab-ci.yml `_ file is the - top-level file for GitLab CI configuration. It defines variables used in - all GitLab pipelines such as GitHub project name and organization, service - user account name, version information for RADIUSS Shared CI project we are - using, and top-level information for triggering build-and-test - sub-pipelines. + top-level file for GitLab CI configuration. It defines variables used + throughout the CI configuration such as GitHub project name and + organization, service user account name, version information for RADIUSS + Shared CI project we are using, and top-level information for triggering + build-and-test sub-pipelines. * The `RAJA/.uberenv_config.json `_ file defines information about Spack such as Spack version we are using, @@ -218,16 +221,16 @@ configuration variants for those platforms Each job that is run is defined by a Spack spec in one of two places, depending on whether it is *shared* with other projects or it is specific to RAJA. The -shared jobs are defined in files located in ``gitlab/jobs/.yml`` in -the `RADIUSS Spack Configs Project -`_. Overrides (modifications) of -those jobs and other RAJA-specific jobs are defined in -``RAJA/.gitlab/jobs/.yml`` files. +shared jobs are defined in files located in +``gitlab/radiuss-jobs/.yml`` in the `RADIUSS Spack Configs Project +`_. Overrides (modifications) +of those jobs and other RAJA-specific jobs are defined in +``RAJA/.gitlab/jobs/.yml`` files. **Each shared job will be run as-is unless it is overridden** in the RAJA local jobs file for the corresponding machine. For example, a shared job for the LC ruby machine may appear in the RADIUSS Spack Configs file -``gitlab/jobs/ruby.yml`` as:: +``gitlab/radiuss-jobs/ruby.yml`` as:: gcc_8_1_0: variables: @@ -295,7 +298,7 @@ locations of Spack packages, etc. are located in the Also, recall that to generate a host-config file, Spack uses packages and specs in the `RADIUSS Spack Configs project `_ (a RAJA submodule), -plus RAJA-specific specs defined in files in the `RAJA/.gitlab `_ directory, as described earlier. +plus RAJA-specific specs defined in files in the `RAJA/.gitlab/jobs `_ directory, as described earlier. .. _azure_ci-label: diff --git a/docs/sphinx/dev_guide/ci_tasks.rst b/docs/sphinx/dev_guide/ci_tasks.rst index fe7821ef30..9d734c2f9d 100644 --- a/docs/sphinx/dev_guide/ci_tasks.rst +++ b/docs/sphinx/dev_guide/ci_tasks.rst @@ -41,7 +41,7 @@ the ``RAJA/.gitlab/jobs/.yml`` file where it is defined. Here, ``MACHINE`` is the name of an LC platform where GitLab CI is run. To remove a shared configuration, it must be removed from the appropriate -``gitlab/jobs/.yml`` file in the `RADIUSS Spack Configs +``gitlab/radiuss-jobs/.yml`` file in the `RADIUSS Spack Configs `_ project. Create a branch there, remove the job entry, and create a pull request. @@ -76,7 +76,7 @@ Here, we enable OpenMP and CUDA, both of which must be enabled to test those RAJA back-ends, and specify the CUDA target architecture 'sm_70'. To add a shared configuration, it must be added to the appropriate -``.gitlab/jobs/.yml`` file in the `RADIUSS Spack Configs +``gitlab/radiuss-jobs/.yml`` file in the `RADIUSS Spack Configs `_ project. Create a branch there, add the job entry, and create a pull request. @@ -93,7 +93,7 @@ sure to also modify the job label as needed, so it is descriptive of the configuration (and remains unique!!). To modify a shared configuration, it must be changed in the appropriate -``gitlab/jobs/.yml`` file in the `RADIUSS Spack Configs +``gitlab/radiuss-jobs/.yml`` file in the `RADIUSS Spack Configs `_ project. Create a branch there, modify the job entry, and create a pull request. @@ -151,7 +151,7 @@ annotate the job for this. For example: .. important:: When a shared job needs to be modified for RAJA specifically, we call that "overriding": The job label must be kept the same as in the - ``.gitlab/jobs/.yml`` file in the `RADIUSS Spack Configs + ``gitlab/radiuss-jobs/.yml`` file in the `RADIUSS Spack Configs `_, and the RAJA-specific job can be adapted. If you override a shared job, please add a comment to describe the change in the ``RAJA/.gitlab/jobs/.yml`` file where diff --git a/docs/sphinx/dev_guide/figures/RAJA-Gitlab-Files.png b/docs/sphinx/dev_guide/figures/RAJA-Gitlab-Files.png index 69e72b2367e4fce1a974b802dcf1f4bd7c3b8f74..c0704c38895e2e20ab958fea54353a3c0555ea79 100644 GIT binary patch literal 750803 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

yS2m;e&TLRbiZ;g- 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

aLjq4A{ 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ℳn9jKkME0`81#n~QMh*~d@ZVqL@T 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