diff --git a/.clang-format b/.clang-format index 19b92e36..1deea9cc 100644 --- a/.clang-format +++ b/.clang-format @@ -1,3 +1,10 @@ +############################################################################## +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +############################################################################## + BasedOnStyle : google IndentWidth : 2 BreakBeforeBraces : Linux diff --git a/.dockerignore b/.dockerignore index c6f8745a..7c30ffc2 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,9 @@ +############################################################################## +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +############################################################################## + .git build* diff --git a/.github/hubcast.yml b/.github/hubcast.yml new file mode 100644 index 00000000..6017604d --- /dev/null +++ b/.github/hubcast.yml @@ -0,0 +1,24 @@ +Repo: + # Destination organization + dest_org: RADIUSS + + # Destination repository + dest_name: CHAI + + # Name of the CI check as reported back to GitHub + check_name: gitlab-ci + + # Report status of pipeline, child pipelines, and individual jobs + check_types: [pipeline, child-pipelines, jobs] + + # Delete branches from destination when source PR is closed + delete_closed: true + + # Sync draft PRs/MRs + sync_drafts: false + + # Post message when draft sync is disabled + sync_drafts_msg: true + + # Disable creation of GitLab MRs from GitHub PRs + create_mr: false diff --git a/.gitignore b/.gitignore index 86325648..06e33edd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,10 @@ +############################################################################## +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +############################################################################## + build*/ install*/ .vscode/ @@ -9,3 +16,5 @@ Win32/x64/ *.aps *.orig *.code-workspace +slirp.out +.codex diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5b9d97e8..cd47f756 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,9 +1,9 @@ -############################################################################### -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +############################################################################## +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # -# SPDX-License-Identifier: (MIT) -############################################################################### +# SPDX-License-Identifier: BSD-3-Clause +############################################################################## # DESCRIPTION: ############################################################################### @@ -72,11 +72,11 @@ include: file: 'id_tokens.yml' # Base pipeline templates and utilities - - component: $CI_SERVER_FQDN/radiuss/radiuss-shared-ci/base-pipeline@woptim/migrate-to-components + - component: $CI_SERVER_FQDN/radiuss/radiuss-shared-ci/base-pipeline@2026.6.0 inputs: github_project_name: $GITHUB_PROJECT_NAME github_project_org: $GITHUB_PROJECT_ORG - github_token: $GITHUB_TOKEN + github_token: $RSCI_GITHUB_STATUS_TOKEN # Local custom variables (used for component inputs and forwarded to child pipelines) - local: '.gitlab/custom-variables.yml' @@ -86,7 +86,7 @@ include: ############################################################################### # We organize the build-and-test stage with sub-pipelines. Each sub-pipeline # corresponds to a test batch on a given machine. -# + # Note: .machine-check template is provided by the base-pipeline component # and includes better error handling, validation, and GitHub status reporting. # Trigger a build-and-test pipeline for each machine. @@ -116,13 +116,15 @@ generate-job-lists: # DANE dane-up-check: extends: [.dane, .machine-check] + variables: + ASSOCIATED_CHILD_PIPELINE: "dane-build-and-test" dane-build-and-test: extends: [.dane, .build-and-test] needs: [dane-up-check, generate-job-lists] trigger: include: - - component: $CI_SERVER_FQDN/radiuss/radiuss-shared-ci/dane-pipeline@woptim/migrate-to-components + - component: $CI_SERVER_FQDN/radiuss/radiuss-shared-ci/dane-pipeline@2026.6.0 inputs: job_cmd: $JOB_CMD shared_alloc: $DANE_SHARED_ALLOC @@ -136,13 +138,15 @@ dane-build-and-test: # MATRIX matrix-up-check: extends: [.matrix, .machine-check] + variables: + ASSOCIATED_CHILD_PIPELINE: "matrix-build-and-test" matrix-build-and-test: extends: [.matrix, .build-and-test] needs: [matrix-up-check, generate-job-lists] trigger: include: - - component: $CI_SERVER_FQDN/radiuss/radiuss-shared-ci/matrix-pipeline@woptim/migrate-to-components + - component: $CI_SERVER_FQDN/radiuss/radiuss-shared-ci/matrix-pipeline@2026.6.0 inputs: job_cmd: $JOB_CMD shared_alloc: $MATRIX_SHARED_ALLOC @@ -156,13 +160,15 @@ matrix-build-and-test: # CORONA corona-up-check: extends: [.corona, .machine-check] + variables: + ASSOCIATED_CHILD_PIPELINE: "corona-build-and-test" corona-build-and-test: extends: [.corona, .build-and-test] needs: [corona-up-check, generate-job-lists] trigger: include: - - component: $CI_SERVER_FQDN/radiuss/radiuss-shared-ci/corona-pipeline@woptim/migrate-to-components + - component: $CI_SERVER_FQDN/radiuss/radiuss-shared-ci/corona-pipeline@2026.6.0 inputs: job_cmd: $JOB_CMD shared_alloc: $CORONA_SHARED_ALLOC @@ -176,13 +182,15 @@ corona-build-and-test: # TIOGA tioga-up-check: extends: [.tioga, .machine-check] + variables: + ASSOCIATED_CHILD_PIPELINE: "tioga-build-and-test" tioga-build-and-test: extends: [.tioga, .build-and-test] needs: [tioga-up-check, generate-job-lists] trigger: include: - - component: $CI_SERVER_FQDN/radiuss/radiuss-shared-ci/tioga-pipeline@woptim/migrate-to-components + - component: $CI_SERVER_FQDN/radiuss/radiuss-shared-ci/tioga-pipeline@2026.6.0 inputs: job_cmd: $JOB_CMD shared_alloc: $TIOGA_SHARED_ALLOC @@ -196,13 +204,15 @@ tioga-build-and-test: # TUOLUMNE tuolumne-up-check: extends: [.tuolumne, .machine-check] + variables: + ASSOCIATED_CHILD_PIPELINE: "tuolumne-build-and-test" tuolumne-build-and-test: extends: [.tuolumne, .build-and-test] needs: [tuolumne-up-check, generate-job-lists] trigger: include: - - component: $CI_SERVER_FQDN/radiuss/radiuss-shared-ci/tuolumne-pipeline@woptim/migrate-to-components + - component: $CI_SERVER_FQDN/radiuss/radiuss-shared-ci/tuolumne-pipeline@2026.6.0 inputs: job_cmd: $JOB_CMD shared_alloc: $TUOLUMNE_SHARED_ALLOC @@ -213,15 +223,18 @@ tuolumne-build-and-test: - artifact: 'tuolumne-jobs.yml' job: 'generate-job-lists' - -## If testing develop branch, trigger RAJA downstream tests with this version of CHAI. -# trigger-raja: -# stage: multi-project -# rules: -# - if: '$CI_COMMIT_BRANCH == "develop" || $MULTI_PROJECT == "ON"' -# variables: -# UPDATE_CHAI: develop -# trigger: -# project: radiuss/raja -# branch: develop -# strategy: depend +# MULTI-PROJECT PIPELINE +trigger-care: + stage: multi-project + rules: + - if: $MULTI_PROJECT != "OFF" + when: manual + - when: never + allow_failure: true + inherit: + variables: false + variables: + UPDATE_CHAI: ${CI_COMMIT_SHA} + trigger: + project: radiuss/multi-project/care-trigger + branch: develop diff --git a/.gitlab/custom-jobs.yml b/.gitlab/custom-jobs.yml index 0a8713d7..cca6edb2 100644 --- a/.gitlab/custom-jobs.yml +++ b/.gitlab/custom-jobs.yml @@ -1,8 +1,8 @@ ############################################################################### -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # -# SPDX-License-Identifier: (MIT) +# SPDX-License-Identifier: BSD-3-Clause ############################################################################### # This file defines JOB TEMPLATES ONLY. diff --git a/.gitlab/custom-variables.yml b/.gitlab/custom-variables.yml index a5bc55be..2cb1b0a0 100644 --- a/.gitlab/custom-variables.yml +++ b/.gitlab/custom-variables.yml @@ -1,8 +1,8 @@ ############################################################################### -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # -# SPDX-License-Identifier: (MIT) +# SPDX-License-Identifier: BSD-3-Clause ############################################################################### # This file defines project-specific VARIABLES ONLY. @@ -19,42 +19,42 @@ variables: # Dane (SLURM) allocation settings DANE_SHARED_ALLOC: "--exclusive --reservation=ci --time=7 --nodes=1" -# Note: We repeat the reservation, necessary when jobs are manually re-triggered. + # Note: We repeat the reservation, necessary when jobs are manually re-triggered. DANE_JOB_ALLOC: "--overlap --reservation=ci --nodes=1" # Project specific variants for dane - PROJECT_DANE_VARIANTS: "~shared +raja tests=basic " + PROJECT_DANE_VARIANTS: "~shared +raja tests=basic" # Project specific deps for dane - PROJECT_DANE_DEPS: "^raja~examples~exercises " + PROJECT_DANE_DEPS: "^raja~examples~exercises cxxstd=20 ^fmt@12.1.0" # Matrix (SLURM) allocation settings - MATRIX_SHARED_ALLOC: "--exclusive --partition=pci --time=7 --nodes=1" -# Note: We repeat the reservation, necessary when jobs are manually re-triggered. - MATRIX_JOB_ALLOC: "--partition=pci --overlap --nodes=1" + MATRIX_SHARED_ALLOC: "OFF" + # Note: We repeat the reservation, necessary when jobs are manually re-triggered. + MATRIX_JOB_ALLOC: "--partition=pci --time=7 --gpus=1" # Project specific variants for matrix PROJECT_MATRIX_VARIANTS: "~shared +raja tests=basic +cuda cuda_arch=90" # Project specific deps for matrix - PROJECT_MATRIX_DEPS: "^raja~examples~exercises " + PROJECT_MATRIX_DEPS: "^raja~examples~exercises cxxstd=20 ^fmt@12.1.0" # Corona (flux) allocation settings CORONA_SHARED_ALLOC: "--exclusive --time-limit=9m --nodes=1" CORONA_JOB_ALLOC: "--nodes=1 --begin-time=+5s" # Project specific variants for corona - PROJECT_CORONA_VARIANTS: "~shared +raja tests=basic " + PROJECT_CORONA_VARIANTS: "~shared +raja tests=basic" # Project specific deps for corona - PROJECT_CORONA_DEPS: "^raja~examples~exercises " + PROJECT_CORONA_DEPS: "^raja~examples~exercises cxxstd=20 ^fmt@12.1.0" # Tioga (flux) allocation settings TIOGA_SHARED_ALLOC: "--queue=pci --exclusive --time-limit=16m --nodes=1" TIOGA_JOB_ALLOC: "--nodes=1 --begin-time=+5s" # Project specific variants for tioga - PROJECT_TIOGA_VARIANTS: "~shared +raja tests=basic " + PROJECT_TIOGA_VARIANTS: "~shared +raja tests=basic" # Project specific deps for tioga - PROJECT_TIOGA_DEPS: "^raja~examples~exercises " + PROJECT_TIOGA_DEPS: "^raja~examples~exercises cxxstd=20 ^fmt@12.1.0" # Tuolumne (flux) allocation settings TUOLUMNE_SHARED_ALLOC: "--queue=pci --exclusive --time-limit=16m --nodes=1" TUOLUMNE_JOB_ALLOC: "--nodes=1 --begin-time=+5s" # Project specific variants for tuolumne - PROJECT_TUOLUMNE_VARIANTS: "~shared +raja tests=basic " + PROJECT_TUOLUMNE_VARIANTS: "~shared +raja tests=basic" # Project specific deps for tuolumne - PROJECT_TUOLUMNE_DEPS: "^raja~examples~exercises " + PROJECT_TUOLUMNE_DEPS: "^raja~examples~exercises cxxstd=20 ^fmt@12.1.0" diff --git a/.gitlab/jobs/corona.yml b/.gitlab/jobs/corona.yml index d98d97d0..e5aec944 100644 --- a/.gitlab/jobs/corona.yml +++ b/.gitlab/jobs/corona.yml @@ -1,8 +1,8 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # -# SPDX-License-Identifier: (MIT) +# SPDX-License-Identifier: BSD-3-Clause ############################################################################## # Override reproducer section to define project specific variables. @@ -17,7 +17,11 @@ # project. We keep ${PROJECT__VARIANTS} and ${PROJECT__DEPS} # So that the comparison with the original job is easier. -# No overridden jobs so far. +# Due to a compiler bug, ROCm 5.7.1 with C++20 is failing. +rocmcc_5_7_1_hip: + extends: .job_on_corona + variables: + ON_CORONA: "OFF" ############ # Extra jobs diff --git a/.gitlab/jobs/dane.yml b/.gitlab/jobs/dane.yml index 4b3b5cb7..7e027099 100644 --- a/.gitlab/jobs/dane.yml +++ b/.gitlab/jobs/dane.yml @@ -1,8 +1,8 @@ ############################################################################### -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # -# SPDX-License-Identifier: (MIT) +# SPDX-License-Identifier: BSD-3-Clause ############################################################################### # Override reproducer section to define projet specific variables. @@ -26,14 +26,8 @@ # ${PROJECT__DEPS} in the extra jobs. There is no reason not to fully # describe the spec here. -clang_14_0_6_develop_tpls: - variables: - SPEC: " ~shared +raja tests=basic %clang@=14.0.6 ^umpire@develop ^raja@develop~examples~exercises ^camp@main" - extends: .job_on_dane - allow_failure: true - clang_19_1_3_develop_tpls: variables: - SPEC: " ~shared +raja tests=basic %clang@=19.1.3 ^umpire@develop ^raja@develop~examples~exercises ^camp@main" + SPEC: " ~shared +raja tests=basic %clang@=19.1.3 ^raja@develop~examples~exercises cxxstd=20 ^umpire@develop ^camp@main ^fmt@12.1.0" extends: .job_on_dane allow_failure: true diff --git a/.gitlab/jobs/matrix.yml b/.gitlab/jobs/matrix.yml index 3b7eaa06..25f4fbc4 100644 --- a/.gitlab/jobs/matrix.yml +++ b/.gitlab/jobs/matrix.yml @@ -1,8 +1,8 @@ ############################################################################### -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # -# SPDX-License-Identifier: (MIT) +# SPDX-License-Identifier: BSD-3-Clause ############################################################################### # Override reproducer section to define projet specific variables. @@ -17,11 +17,10 @@ # project. We keep ${PROJECT__VARIANTS} and ${PROJECT__DEPS} # So that the comparison with the original job is easier. -# No overridden jobs so far. clang_18_1_8_gcc_13_cuda_12_6_0: extends: .job_on_matrix variables: - SPEC: " ~shared +raja tests=basic +cuda cuda_arch=90 %clang-18-gcc-13 ^cuda@12.6.0+allow-unsupported-compilers ^raja~examples~exercises" + SPEC: " ~shared +raja tests=basic +cuda cuda_arch=90 %clang-18-gcc-13 ^cuda@12.6.0+allow-unsupported-compilers ^raja~examples~exercises cxxstd=20 ^fmt@12.1.0" allow_failure: true ############ diff --git a/.gitlab/jobs/tioga.yml b/.gitlab/jobs/tioga.yml index c4390aa6..a19e949d 100644 --- a/.gitlab/jobs/tioga.yml +++ b/.gitlab/jobs/tioga.yml @@ -1,8 +1,8 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # -# SPDX-License-Identifier: (MIT) +# SPDX-License-Identifier: BSD-3-Clause ############################################################################## # Override reproducer section to define project specific variables. diff --git a/.gitlab/jobs/tuolumne.yml b/.gitlab/jobs/tuolumne.yml index 44c562b3..ff881d65 100644 --- a/.gitlab/jobs/tuolumne.yml +++ b/.gitlab/jobs/tuolumne.yml @@ -1,8 +1,8 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # -# SPDX-License-Identifier: (MIT) +# SPDX-License-Identifier: BSD-3-Clause ############################################################################## # Override reproducer section to define project specific variables. diff --git a/.uberenv_config.json b/.uberenv_config.json index 38485328..1e323614 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": "v1.0.2", +"spack_branch": "v1.1.1", "spack_configs_path": "scripts/radiuss-spack-configs", "spack_packages_path": "scripts/radiuss-spack-configs/spack_repo/llnl_radiuss/packages", "spack_setup_clingo": false diff --git a/CMakeLists.txt b/CMakeLists.txt index 2465a9c2..c190a065 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## @@ -15,7 +15,7 @@ cmake_policy(SET CMP0096 OLD) # Drops leading zeros in version numbers include(CMakeDependentOption) include(CMakePackageConfigHelpers) -project(Chai LANGUAGES C CXX VERSION 2025.12.0) +project(Chai LANGUAGES C CXX VERSION 2026.07.0) include(cmake/SetupChaiOptions.cmake) @@ -29,12 +29,13 @@ message(STATUS "Using CMake version ${CMAKE_VERSION}") ################################ # BLT ################################ -set(BLT_CXX_STD c++17 CACHE STRING "") +set(BLT_CXX_STD c++20 CACHE STRING "") if(("${BLT_CXX_STD}" STREQUAL "c++98") OR ("${BLT_CXX_STD}" STREQUAL "c++11") OR - ("${BLT_CXX_STD}" STREQUAL "c++14")) - message(FATAL_ERROR "CHAI requires a minimum C++ standard of c++17. Please set BLT_CXX_STD appropriately.") + ("${BLT_CXX_STD}" STREQUAL "c++14") OR + ("${BLT_CXX_STD}" STREQUAL "c++17")) + message(FATAL_ERROR "CHAI requires a minimum C++ standard of c++20. Please set BLT_CXX_STD appropriately.") endif() if (NOT BLT_LOADED) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index c7151205..9d8313fa 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,10 @@ +[comment]: # (#################################################################) +[comment]: # (Copyright Lawrence Livermore National Security, LLC and other CHAI) +[comment]: # (contributors. See the CHAI LICENSE and COPYRIGHT files for details.) +[comment]: # +[comment]: # (# SPDX-License-Identifier: BSD-3-Clause) +[comment]: # (#################################################################) + # Contributor Covenant Code of Conduct ## Our Pledge diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3b2f2538..648ed631 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,10 @@ +[comment]: # (#################################################################) +[comment]: # (Copyright Lawrence Livermore National Security, LLC and other CHAI) +[comment]: # (contributors. See the CHAI LICENSE and COPYRIGHT files for details.) +[comment]: # +[comment]: # (# SPDX-License-Identifier: BSD-3-Clause) +[comment]: # (#################################################################) + # Contributing to CHAI This document is intented for developers who want to add new features or diff --git a/COPYRIGHT b/COPYRIGHT index 3bc5dea5..b5e9207f 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,11 +1,45 @@ Intellectual Property Notice ------------------------------ -CHAI is licensed under the BSD 3 Clause license (LICENSE or -https://opensource.org/licenses/BSD-3-Clause). +This file is part of CHAI. +For details, see https://github.com/llnl/CHAI -Copyrights and patents in the CHAI project are retained by contributors. No -copyright assignment is required to contribute to CHAI. +CHAI is produced at the Lawrence Livermore National Laboratory. +See NOTICE file. + +Unlimited Open Source - BSD Distribution +LLNL-CODE-705877 +OCEC-16-189 + +CHAI licensed under the BSD 3-Clause license +(BSD-3-Clause or https://opensource.org/licenses/BSD-3-Clause). +See LICENSE file. + +Copyrights and patents in the CHAI project are retained by contributors. +No copyright assignment is required to contribute to CHAI. + +See https://github.com/llnl/CHAI/contributors for the list of contributors. + +Additional BSD Notice + +1. This notice is required to be provided under our contract with the U.S. +Department of Energy (DOE). This work was produced at Lawrence Livermore +National Laboratory under Contract No. DE-AC52-07NA27344 with the DOE. + +2. Neither the United States Government nor Lawrence Livermore National +Security, LLC nor any of their employees, makes any warranty, express or +implied, or assumes any liability or responsibility for the accuracy, +completeness, or usefulness of any information, apparatus, product, or process +disclosed, or represents that its use would not infringe privately-owned rights. + +3. Also, reference herein to any specific commercial products, process, or +services by trade name, trademark, manufacturer or otherwise does not +necessarily constitute or imply its endorsement, recommendation, or favoring by +the United States Government or Lawrence Livermore National Security, LLC. The +views and opinions of authors expressed herein do not necessarily state or +reflect those of the United States Government or Lawrence Livermore National +Security, LLC, and shall not be used for advertising or product endorsement +purposes. SPDX usage ------------ diff --git a/Dockerfile b/Dockerfile index 8636ac3e..1aec1b2f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,11 @@ -FROM ghcr.io/llnl/radiuss:ubuntu-22.04-gcc-13 AS gcc +############################################################################## +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +############################################################################## + +FROM ghcr.io/llnl/radiuss:ubuntu-24.04-gcc-13 AS gcc ENV GTEST_COLOR=1 COPY . /home/chai/workspace WORKDIR /home/chai/workspace/build @@ -6,7 +13,7 @@ RUN cmake -DENABLE_COVERAGE=On -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=g++ make -j 16 && \ ctest -T test --output-on-failure -FROM ghcr.io/llnl/radiuss:clang-15-ubuntu-22.04 AS clang +FROM ghcr.io/llnl/radiuss:ubuntu-24.04-clang-19 AS clang ENV GTEST_COLOR=1 COPY . /home/chai/workspace WORKDIR /home/chai/workspace/build @@ -14,7 +21,7 @@ RUN cmake -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang .. && \ make -j 16 && \ ctest -T test --output-on-failure -FROM ghcr.io/llnl/radiuss:intel-2024.0-ubuntu-20.04 AS intel +FROM ghcr.io/llnl/radiuss:ubuntu-24.04-intel-2024.2 AS intel ENV GTEST_COLOR=1 COPY . /home/chai/workspace WORKDIR /home/chai/workspace/build @@ -23,15 +30,14 @@ RUN /bin/bash -c "source /opt/intel/oneapi/setvars.sh 2>&1 > /dev/null && \ make -j 16 && \ ctest -T test --output-on-failure" -FROM ghcr.io/llnl/radiuss:ubuntu-22.04-cuda-12-3 AS cuda +FROM ghcr.io/llnl/radiuss:ubuntu-24.04-cuda-12-9 AS cuda ENV GTEST_COLOR=1 COPY . /home/chai/workspace WORKDIR /home/chai/workspace/build RUN cmake -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_COMPILER=gcc -DENABLE_CUDA=On -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc -DCMAKE_CUDA_ARCHITECTURES=70 .. && \ make -j 16 -# TODO: switch to ROCM 6 -FROM ghcr.io/llnl/radiuss:hip-5.6.1-ubuntu-20.04 AS hip +FROM ghcr.io/llnl/radiuss:ubuntu-24.04-hip-6.4.3 AS hip ENV GTEST_COLOR=1 ENV HCC_AMDGPU_TARGET=gfx900 COPY . /home/chai/workspace @@ -39,7 +45,7 @@ WORKDIR /home/chai/workspace/build RUN cmake -DCMAKE_CXX_COMPILER=amdclang++ -DCMAKE_C_COMPILER=amdclang -DENABLE_HIP=On -DENABLE_WARNINGS_AS_ERRORS=Off .. && \ make -j 16 -FROM ghcr.io/llnl/radiuss:intel-2024.0-ubuntu-20.04 AS sycl +FROM ghcr.io/llnl/radiuss:ubuntu-24.04-intel-2024.2 AS sycl ENV GTEST_COLOR=1 COPY . /home/chai/workspace WORKDIR /home/chai/workspace/build diff --git a/LICENSE b/LICENSE index 9ff1fff0..b41397cf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,7 @@ -Copyright (c) 2016-25, Lawrence Livermore National Security, LLC. +BSD 3-Clause License + +Copyright (c) 2016-2026, Lawrence Livermore National Security, LLC and other CHAI contributors. + All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index 21b9602b..79981780 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ [comment]: # (#################################################################) -[comment]: # (Copyright 2016-25, Lawrence Livermore National Security, LLC) -[comment]: # (and CHAI project contributors. See the CHAI LICENSE file for) -[comment]: # (details.) +[comment]: # (Copyright Lawrence Livermore National Security, LLC and other CHAI) +[comment]: # (contributors. See the CHAI LICENSE and COPYRIGHT files for details.) [comment]: # [comment]: # (# SPDX-License-Identifier: BSD-3-Clause) [comment]: # (#################################################################) @@ -50,15 +49,17 @@ Contributors include: ## Release -Copyright (c) 2016, Lawrence Livermore National Security, LLC. -Produced at the Lawrence Livermore National Laboratory +Copyright (c) 2016-2026, Lawrence Livermore National Security, LLC and other CHAI contributors. +Produced at the Lawrence Livermore National Laboratory. All rights reserved. Unlimited Open Source - BSD Distribution +`LLNL-CODE-705877` +`OCEC-16-189` -For release details and restrictions, please read the LICENSE file. -It is also linked here: [LICENSE](./LICENSE) +For release details and restrictions, please read the following: +- [LICENSE](./LICENSE) +- [COPYRIGHT](./COPYRIGHT) +- [NOTICE](./NOTICE) -- `LLNL-CODE-705877` -- `OCEC-16-189` diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 8cf02c05..9c3d7803 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,7 +1,6 @@ [comment]: # (#################################################################) -[comment]: # (Copyright 2016-24, Lawrence Livermore National Security, LLC) -[comment]: # (and CHAI project contributors. See the CHAI LICENSE file for) -[comment]: # (details.) +[comment]: # (Copyright Lawrence Livermore National Security, LLC and other CHAI) +[comment]: # (contributors. See the CHAI LICENSE and COPYRIGHT files for details.) [comment]: # [comment]: # (# SPDX-License-Identifier: BSD-3-Clause) [comment]: # (#################################################################) @@ -13,7 +12,21 @@ in this file. The format of this file is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). -## [Version 2025.12.0] = Release date 2025-12-22 +## [Version 2026.07.0] - Release date 2025-08-05 + +### Changed +- CHAI now requires C++20 as the minimum C++ standard. +- CHAI now requires ROCm 6 as the minimum ROCm version when ROCm is enabled. +- CHAI now requires CUDA 12 as the minimum CUDA version when CUDA is enabled. +- Updated BLT to v0.7.2. +- Updated RAJA to v2026.07.0. +- Updated Umpire to v2026.07.1. +- Made a ManagedArray constructor explicit to prevent unwanted implicit conversions. +- Added size\_type, value\_type, reference, const\_reference, pointer, and const\_pointer typenames to ManagedArray. +- In CUDA builds, prevent resource manager from being created during construction of an empty ManagedArray. +- Added experimental re-implementation of CHAI. See docs/sphinx/expt/design.rst for details. It is still subject to change and has some limitations, but is anticipated to be more performant and flexible. + +## [Version 2025.12.0] - Release date 2025-12-22 ### Fixed - Fixed compiler error related to using a lambda as a default function argument. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b560c325..d7dccbe8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,3 +1,10 @@ +############################################################################## +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +############################################################################## + jobs: - job: Docker timeoutInMinutes: 360 diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index acb248ed..5f66dd50 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## @@ -48,3 +48,7 @@ if (CHAI_ENABLE_MANAGED_PTR) NAME managed_ptr_benchmarks COMMAND managed_ptr_benchmarks) endif () + +if (CHAI_ENABLE_EXPERIMENTAL) + add_subdirectory(expt) +endif () diff --git a/benchmarks/chai_arraymanager_benchmarks.cpp b/benchmarks/chai_arraymanager_benchmarks.cpp index 369e288c..4aa1eb10 100644 --- a/benchmarks/chai_arraymanager_benchmarks.cpp +++ b/benchmarks/chai_arraymanager_benchmarks.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/benchmarks/chai_benchmark_utils.hpp b/benchmarks/chai_benchmark_utils.hpp index 390a1ac8..b4f516a3 100644 --- a/benchmarks/chai_benchmark_utils.hpp +++ b/benchmarks/chai_benchmark_utils.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/benchmarks/chai_managed_ptr_benchmarks.cpp b/benchmarks/chai_managed_ptr_benchmarks.cpp index ffa16962..3cb09e89 100644 --- a/benchmarks/chai_managed_ptr_benchmarks.cpp +++ b/benchmarks/chai_managed_ptr_benchmarks.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/benchmarks/chai_managedarray_benchmarks.cpp b/benchmarks/chai_managedarray_benchmarks.cpp index 08f3a7fe..cffa438b 100644 --- a/benchmarks/chai_managedarray_benchmarks.cpp +++ b/benchmarks/chai_managedarray_benchmarks.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/benchmarks/expt/CMakeLists.txt b/benchmarks/expt/CMakeLists.txt new file mode 100644 index 00000000..b1be9d40 --- /dev/null +++ b/benchmarks/expt/CMakeLists.txt @@ -0,0 +1,42 @@ +############################################################################## +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +############################################################################## + +set(chai_expt_benchmark_depends + chai + gbenchmark) + +if (CHAI_ENABLE_CUDA) + set(chai_expt_benchmark_depends + ${chai_expt_benchmark_depends} + cuda) +endif () + +if (CHAI_ENABLE_HIP) + set(chai_expt_benchmark_depends + ${chai_expt_benchmark_depends} + blt::hip) +endif () + +if (CHAI_ENABLE_CUDA OR CHAI_ENABLE_HIP) + blt_add_executable( + NAME DualArrayManagerBenchmarks + SOURCES DualArrayManagerBenchmarks.cpp + DEPENDS_ON ${chai_expt_benchmark_depends}) + + blt_add_benchmark( + NAME DualArrayManagerBenchmarks + COMMAND DualArrayManagerBenchmarks) + + blt_add_executable( + NAME UnifiedArrayManagerBenchmarks + SOURCES UnifiedArrayManagerBenchmarks.cpp + DEPENDS_ON ${chai_expt_benchmark_depends}) + + blt_add_benchmark( + NAME UnifiedArrayManagerBenchmarks + COMMAND UnifiedArrayManagerBenchmarks) +endif () diff --git a/benchmarks/expt/DualArrayManagerBenchmarks.cpp b/benchmarks/expt/DualArrayManagerBenchmarks.cpp new file mode 100644 index 00000000..587158f1 --- /dev/null +++ b/benchmarks/expt/DualArrayManagerBenchmarks.cpp @@ -0,0 +1,206 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#include "benchmark/benchmark.h" + +#include + +#include "chai/expt/ContextGuard.hpp" +#include "chai/expt/DualArrayManager.hpp" + +namespace { + using ::chai::expt::Context; + using ::chai::expt::ContextGuard; + using ::chai::expt::ContextManager; + using ::chai::expt::DualArrayManager; + + static void DualArrayManager_DataSequence(benchmark::State& state, + Context initial_context, + bool initial_touch, + Context call_context, + bool call_touch) + { + const auto size = static_cast(state.range(0)); + + for (auto _ : state) + { + state.PauseTiming(); + + auto& contextManager = ContextManager::getInstance(); + contextManager.reset(); + + DualArrayManager manager{size}; + { + ContextGuard guard{initial_context}; + int* initial_data = manager.data(/*touch=*/initial_touch); + benchmark::DoNotOptimize(initial_data); + } + + { + ContextGuard guard{call_context}; + state.ResumeTiming(); // measure only the data() call + int* data = manager.data(/*touch=*/call_touch); + benchmark::DoNotOptimize(data); + state.PauseTiming(); // exclude guard destruction + } + } + + state.SetItemsProcessed(state.iterations()); + state.SetBytesProcessed(state.iterations() * size * sizeof(int)); + } + + static void DualArrayManager_DefaultConstruct(benchmark::State& state) + { + for (auto _ : state) + { + DualArrayManager manager{}; + benchmark::DoNotOptimize(manager); + } + } + + BENCHMARK(DualArrayManager_DefaultConstruct); + + static void DualArrayManager_SizeConstruct(benchmark::State& state) + { + const auto size = static_cast(state.range(0)); + + for (auto _ : state) + { + DualArrayManager manager{size}; + benchmark::DoNotOptimize(manager); + } + + state.SetBytesProcessed(state.iterations() * size * sizeof(int)); + } + + BENCHMARK(DualArrayManager_SizeConstruct) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20); + + static void DualArrayManager_AfterHostRead_DataHostRead(benchmark::State& state) + { + DualArrayManager_DataSequence(state, + /*initial_context=*/Context::HOST, + /*initial_touch=*/false, + /*call_context=*/Context::HOST, + /*call_touch=*/false); + } + + BENCHMARK(DualArrayManager_AfterHostRead_DataHostRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); + + static void DualArrayManager_AfterHostWrite_DataHostRead(benchmark::State& state) + { + DualArrayManager_DataSequence(state, + /*initial_context=*/Context::HOST, + /*initial_touch=*/true, + /*call_context=*/Context::HOST, + /*call_touch=*/false); + } + + BENCHMARK(DualArrayManager_AfterHostWrite_DataHostRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); + + static void DualArrayManager_AfterHostRead_DataDeviceRead(benchmark::State& state) + { + DualArrayManager_DataSequence(state, + /*initial_context=*/Context::HOST, + /*initial_touch=*/false, + /*call_context=*/Context::DEVICE, + /*call_touch=*/false); + } + + BENCHMARK(DualArrayManager_AfterHostRead_DataDeviceRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); + + static void DualArrayManager_AfterHostWrite_DataDeviceRead(benchmark::State& state) + { + DualArrayManager_DataSequence(state, + /*initial_context=*/Context::HOST, + /*initial_touch=*/true, + /*call_context=*/Context::DEVICE, + /*call_touch=*/false); + } + + BENCHMARK(DualArrayManager_AfterHostWrite_DataDeviceRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); + + static void DualArrayManager_AfterDeviceRead_DataHostRead(benchmark::State& state) + { + DualArrayManager_DataSequence(state, + /*initial_context=*/Context::DEVICE, + /*initial_touch=*/false, + /*call_context=*/Context::HOST, + /*call_touch=*/false); + } + + BENCHMARK(DualArrayManager_AfterDeviceRead_DataHostRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); + + static void DualArrayManager_AfterDeviceWrite_DataHostRead(benchmark::State& state) + { + DualArrayManager_DataSequence(state, + /*initial_context=*/Context::DEVICE, + /*initial_touch=*/true, + /*call_context=*/Context::HOST, + /*call_touch=*/false); + } + + BENCHMARK(DualArrayManager_AfterDeviceWrite_DataHostRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); + + static void DualArrayManager_AfterDeviceRead_DataDeviceRead(benchmark::State& state) + { + DualArrayManager_DataSequence(state, + /*initial_context=*/Context::DEVICE, + /*initial_touch=*/false, + /*call_context=*/Context::DEVICE, + /*call_touch=*/false); + } + + BENCHMARK(DualArrayManager_AfterDeviceRead_DataDeviceRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); + + static void DualArrayManager_AfterDeviceWrite_DataDeviceRead(benchmark::State& state) + { + DualArrayManager_DataSequence(state, + /*initial_context=*/Context::DEVICE, + /*initial_touch=*/true, + /*call_context=*/Context::DEVICE, + /*call_touch=*/false); + } + + BENCHMARK(DualArrayManager_AfterDeviceWrite_DataDeviceRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); +} // namespace + +BENCHMARK_MAIN(); diff --git a/benchmarks/expt/UnifiedArrayManagerBenchmarks.cpp b/benchmarks/expt/UnifiedArrayManagerBenchmarks.cpp new file mode 100644 index 00000000..48fce048 --- /dev/null +++ b/benchmarks/expt/UnifiedArrayManagerBenchmarks.cpp @@ -0,0 +1,206 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#include "benchmark/benchmark.h" + +#include + +#include "chai/expt/ContextGuard.hpp" +#include "chai/expt/UnifiedArrayManager.hpp" + +namespace { + using ::chai::expt::Context; + using ::chai::expt::ContextGuard; + using ::chai::expt::ContextManager; + using ::chai::expt::UnifiedArrayManager; + + static void UnifiedArrayManager_DataSequence(benchmark::State& state, + Context initial_context, + bool initial_touch, + Context call_context, + bool call_touch) + { + const auto size = static_cast(state.range(0)); + + for (auto _ : state) + { + state.PauseTiming(); + + auto& contextManager = ContextManager::getInstance(); + contextManager.reset(); + + UnifiedArrayManager manager{size}; + { + ContextGuard guard{initial_context}; + int* initial_data = manager.data(/*touch=*/initial_touch); + benchmark::DoNotOptimize(initial_data); + } + + { + ContextGuard guard{call_context}; + state.ResumeTiming(); // measure only the data() call + int* data = manager.data(/*touch=*/call_touch); + benchmark::DoNotOptimize(data); + state.PauseTiming(); // exclude guard destruction + } + } + + state.SetItemsProcessed(state.iterations()); + state.SetBytesProcessed(state.iterations() * size * sizeof(int)); + } + + static void UnifiedArrayManager_DefaultConstruct(benchmark::State& state) + { + for (auto _ : state) + { + UnifiedArrayManager manager{}; + benchmark::DoNotOptimize(manager); + } + } + + BENCHMARK(UnifiedArrayManager_DefaultConstruct); + + static void UnifiedArrayManager_SizeConstruct(benchmark::State& state) + { + const auto size = static_cast(state.range(0)); + + for (auto _ : state) + { + UnifiedArrayManager manager{size}; + benchmark::DoNotOptimize(manager); + } + + state.SetBytesProcessed(state.iterations() * size * sizeof(int)); + } + + BENCHMARK(UnifiedArrayManager_SizeConstruct) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20); + + static void UnifiedArrayManager_AfterHostRead_DataHostRead(benchmark::State& state) + { + UnifiedArrayManager_DataSequence(state, + /*initial_context=*/Context::HOST, + /*initial_touch=*/false, + /*call_context=*/Context::HOST, + /*call_touch=*/false); + } + + BENCHMARK(UnifiedArrayManager_AfterHostRead_DataHostRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); + + static void UnifiedArrayManager_AfterHostWrite_DataHostRead(benchmark::State& state) + { + UnifiedArrayManager_DataSequence(state, + /*initial_context=*/Context::HOST, + /*initial_touch=*/true, + /*call_context=*/Context::HOST, + /*call_touch=*/false); + } + + BENCHMARK(UnifiedArrayManager_AfterHostWrite_DataHostRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); + + static void UnifiedArrayManager_AfterHostRead_DataDeviceRead(benchmark::State& state) + { + UnifiedArrayManager_DataSequence(state, + /*initial_context=*/Context::HOST, + /*initial_touch=*/false, + /*call_context=*/Context::DEVICE, + /*call_touch=*/false); + } + + BENCHMARK(UnifiedArrayManager_AfterHostRead_DataDeviceRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); + + static void UnifiedArrayManager_AfterHostWrite_DataDeviceRead(benchmark::State& state) + { + UnifiedArrayManager_DataSequence(state, + /*initial_context=*/Context::HOST, + /*initial_touch=*/true, + /*call_context=*/Context::DEVICE, + /*call_touch=*/false); + } + + BENCHMARK(UnifiedArrayManager_AfterHostWrite_DataDeviceRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); + + static void UnifiedArrayManager_AfterDeviceRead_DataHostRead(benchmark::State& state) + { + UnifiedArrayManager_DataSequence(state, + /*initial_context=*/Context::DEVICE, + /*initial_touch=*/false, + /*call_context=*/Context::HOST, + /*call_touch=*/false); + } + + BENCHMARK(UnifiedArrayManager_AfterDeviceRead_DataHostRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); + + static void UnifiedArrayManager_AfterDeviceWrite_DataHostRead(benchmark::State& state) + { + UnifiedArrayManager_DataSequence(state, + /*initial_context=*/Context::DEVICE, + /*initial_touch=*/true, + /*call_context=*/Context::HOST, + /*call_touch=*/false); + } + + BENCHMARK(UnifiedArrayManager_AfterDeviceWrite_DataHostRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); + + static void UnifiedArrayManager_AfterDeviceRead_DataDeviceRead(benchmark::State& state) + { + UnifiedArrayManager_DataSequence(state, + /*initial_context=*/Context::DEVICE, + /*initial_touch=*/false, + /*call_context=*/Context::DEVICE, + /*call_touch=*/false); + } + + BENCHMARK(UnifiedArrayManager_AfterDeviceRead_DataDeviceRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); + + static void UnifiedArrayManager_AfterDeviceWrite_DataDeviceRead(benchmark::State& state) + { + UnifiedArrayManager_DataSequence(state, + /*initial_context=*/Context::DEVICE, + /*initial_touch=*/true, + /*call_context=*/Context::DEVICE, + /*call_touch=*/false); + } + + BENCHMARK(UnifiedArrayManager_AfterDeviceWrite_DataDeviceRead) + ->Arg(0) + ->RangeMultiplier(8) + ->Range(1, 1 << 20) + ->Unit(benchmark::kNanosecond); +} // namespace + +BENCHMARK_MAIN(); diff --git a/blt b/blt index e783e30f..f08f95e0 160000 --- a/blt +++ b/blt @@ -1 +1 @@ -Subproject commit e783e30f2823ee1a208f7f90741b41c1f5a08063 +Subproject commit f08f95e0f49b1d53db8be2dd577d1cdbfd9e9f90 diff --git a/cmake/ChaiBasics.cmake b/cmake/ChaiBasics.cmake index 9b5b587d..76873b4b 100644 --- a/cmake/ChaiBasics.cmake +++ b/cmake/ChaiBasics.cmake @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/cmake/SetupChaiOptions.cmake b/cmake/SetupChaiOptions.cmake index 2b895c7d..63e3d4b0 100644 --- a/cmake/SetupChaiOptions.cmake +++ b/cmake/SetupChaiOptions.cmake @@ -1,6 +1,6 @@ ############################################################################ -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################ @@ -16,6 +16,7 @@ option(CHAI_ENABLE_UM "Use CUDA unified (managed) memory" Off) option(CHAI_THIN_GPU_ALLOCATE "Single memory space model" Off) option(CHAI_ENABLE_PINNED "Use pinned host memory" Off) option(CHAI_ENABLE_RAJA_PLUGIN "Build plugin to set RAJA execution spaces" On) +option(CHAI_ENABLE_EXPERIMENTAL_RAJA_PLUGIN "Build experimental plugin to integrate CHAI context with RAJA" Off) option(CHAI_ENABLE_GPU_ERROR_CHECKING "Enable GPU error checking" On) option(CHAI_ENABLE_MANAGED_PTR "Enable managed_ptr" On) option(CHAI_DEBUG "Enable Debug Logging." Off) diff --git a/cmake/chai-config.cmake.in b/cmake/chai-config.cmake.in index a1bde19b..addf136a 100644 --- a/cmake/chai-config.cmake.in +++ b/cmake/chai-config.cmake.in @@ -1,6 +1,6 @@ ############################################################################ -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################ @@ -14,7 +14,7 @@ include(CMakeFindDependencyMacro) include("${CMAKE_CURRENT_LIST_DIR}/BLTSetupTargets.cmake") -if (NOT TARGET umpire) +if (NOT TARGET umpire::umpire AND NOT TARGET umpire) find_dependency(umpire CONFIG NO_DEFAULT_PATH PATHS ${umpire_DIR} @umpire_DIR@ diff --git a/cmake/thirdparty/SetupChaiThirdparty.cmake b/cmake/thirdparty/SetupChaiThirdparty.cmake index bab76abc..62b65f8f 100644 --- a/cmake/thirdparty/SetupChaiThirdparty.cmake +++ b/cmake/thirdparty/SetupChaiThirdparty.cmake @@ -1,11 +1,11 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## -if (NOT TARGET umpire) +if (NOT TARGET umpire::umpire AND NOT TARGET umpire) if (DEFINED umpire_DIR OR DEFINED UMPIRE_DIR) message(STATUS "[CHAI] Using external Umpire") find_package(umpire CONFIG REQUIRED NO_DEFAULT_PATH PATHS ${umpire_DIR} ${UMPIRE_DIR}) @@ -28,6 +28,14 @@ if (NOT TARGET umpire) endif () endif () +if (TARGET umpire::umpire) + set(CHAI_UMPIRE_TARGET umpire::umpire) +elseif (TARGET umpire) + set(CHAI_UMPIRE_TARGET umpire) +else () + message(FATAL_ERROR "[CHAI] Umpire target not found. Expected target umpire::umpire or umpire.") +endif () + if (CHAI_ENABLE_RAJA_PLUGIN) if (NOT TARGET RAJA) if (DEFINED raja_DIR OR DEFINED RAJA_DIR) diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 88201048..15ee67ec 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/docs/doxygen/CMakeLists.txt b/docs/doxygen/CMakeLists.txt index 3ab80929..06c986dd 100644 --- a/docs/doxygen/CMakeLists.txt +++ b/docs/doxygen/CMakeLists.txt @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/docs/doxygen/Doxyfile.in b/docs/doxygen/Doxyfile.in index 4bb1ca62..eb6feede 100644 --- a/docs/doxygen/Doxyfile.in +++ b/docs/doxygen/Doxyfile.in @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/docs/sphinx/CMakeLists.txt b/docs/sphinx/CMakeLists.txt index c5708f45..8a785f23 100644 --- a/docs/sphinx/CMakeLists.txt +++ b/docs/sphinx/CMakeLists.txt @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/docs/sphinx/advanced_configuration.rst b/docs/sphinx/advanced_configuration.rst index e7eb3b58..d8370b6a 100644 --- a/docs/sphinx/advanced_configuration.rst +++ b/docs/sphinx/advanced_configuration.rst @@ -1,6 +1,6 @@ .. - # Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI - # project contributors. See the CHAI LICENSE file for details. + # Copyright (c) Lawrence Livermore National Security, LLC and other CHAI + # contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause diff --git a/docs/sphinx/code_documentation.rst b/docs/sphinx/code_documentation.rst index 60754e9c..7abd58c0 100644 --- a/docs/sphinx/code_documentation.rst +++ b/docs/sphinx/code_documentation.rst @@ -1,6 +1,6 @@ .. - # Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI - # project contributors. See the CHAI LICENSE file for details. + # Copyright (c) Lawrence Livermore National Security, LLC and other CHAI + # contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause diff --git a/docs/sphinx/conf.py b/docs/sphinx/conf.py index 93f2d7c7..2316d095 100644 --- a/docs/sphinx/conf.py +++ b/docs/sphinx/conf.py @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## @@ -53,7 +53,7 @@ # General information about the project. project = u'CHAI' -copyright = u'2016-2018, Lawrence Livermore National Security, LLC.' +copyright = u'Copyright (c) 2016-2026, Lawrence Livermore National Security, LLC and other CHAI contributors.' author = u'' # The version info for the project you're documenting, acts as replacement for @@ -61,9 +61,9 @@ # built documents. # # The short X.Y version. -version = u'2025.12' +version = u'2026.07' # The full version, including alpha/beta/rc tags. -release = u'2025.12.0' +release = u'2026.07.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/sphinx/conf.py.in b/docs/sphinx/conf.py.in index 01e2b9a0..7089b3f6 100644 --- a/docs/sphinx/conf.py.in +++ b/docs/sphinx/conf.py.in @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## @@ -52,7 +52,7 @@ master_doc = 'index' # General information about the project. project = u'CHAI' -copyright = u'2016-2018, Lawrence Livermore National Security, LLC.' +copyright = u'Copyright (c) 2016-2026, Lawrence Livermore National Security, LLC and other CHAI contributors.' author = u'' # The version info for the project you're documenting, acts as replacement for @@ -60,9 +60,9 @@ author = u'' # built documents. # # The short X.Y version. -version = u'2025.12' +version = u'2026.07' # The full version, including alpha/beta/rc tags. -release = u'2025.12.0' +release = u'2026.07.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/sphinx/contribution_guide.rst b/docs/sphinx/contribution_guide.rst index 2c7b8be6..ee1efee4 100644 --- a/docs/sphinx/contribution_guide.rst +++ b/docs/sphinx/contribution_guide.rst @@ -1,6 +1,6 @@ .. - # Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI - # project contributors. See the CHAI LICENSE file for details. + # Copyright (c) Lawrence Livermore National Security, LLC and other CHAI + # contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause diff --git a/docs/sphinx/developer/ci.rst b/docs/sphinx/developer/ci.rst index 0c50e99f..239f6c97 100644 --- a/docs/sphinx/developer/ci.rst +++ b/docs/sphinx/developer/ci.rst @@ -1,6 +1,6 @@ .. - # Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI - # project contributors. See the CHAI LICENSE file for details. + # Copyright (c) Lawrence Livermore National Security, LLC and other CHAI + # contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause diff --git a/docs/sphinx/developer/uberenv.rst b/docs/sphinx/developer/uberenv.rst index 525f5339..94a24f76 100644 --- a/docs/sphinx/developer/uberenv.rst +++ b/docs/sphinx/developer/uberenv.rst @@ -1,6 +1,6 @@ .. - # Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI - # project contributors. See the CHAI LICENSE file for details. + # Copyright (c) Lawrence Livermore National Security, LLC and other CHAI + # contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause diff --git a/docs/sphinx/developer_guide.rst b/docs/sphinx/developer_guide.rst index b034efc6..f574d5ef 100644 --- a/docs/sphinx/developer_guide.rst +++ b/docs/sphinx/developer_guide.rst @@ -1,6 +1,6 @@ .. - # Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI - # project contributors. See the CHAI LICENSE file for details. + # Copyright (c) Lawrence Livermore National Security, LLC and other CHAI + # contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause diff --git a/docs/sphinx/expt/design.rst b/docs/sphinx/expt/design.rst new file mode 100644 index 00000000..9dc589f5 --- /dev/null +++ b/docs/sphinx/expt/design.rst @@ -0,0 +1,373 @@ +.. + # Copyright (c) Lawrence Livermore National Security, LLC and other CHAI + # contributors. See the CHAI LICENSE and COPYRIGHT files for details. + # + # SPDX-License-Identifier: BSD-3-Clause + +.. _experimental_design: + +******************* +Experimental Design +******************* + +CHAI provides data structures that implicitly manage coherence across multiple execution contexts. + +------- +Context +------- + +Currently, there are two execution contexts that are handled by CHAI. These are represented in the `Context` enum class. +The `HOST` enum value represents synchronous execution on a CPU. The `DEVICE` enum value represents asynchronous execution on a GPU. +Both NVIDIA and AMD GPUs are supported. + +-------------- +ContextManager +-------------- + +Implicitly managing data coherence requires managing some global state. This is handled by a singleton called `ContextManager`. +When an application enters an execution context, it uses `ContextManager` to set the current context. `ContextManager` also +tracks which contexts may need synchronization. CHAI data structures can query `ContextManager` to update data coherence and +inform `ContextManager` of needed synchronization or synchronization that has been performed. + +Note: It is much faster for `ContextManager` to track synchronization than to repeatedly call `cudaDeviceSynchronize()` or `hipDeviceSynchronize()`. + +.. code-block:: cpp + + #include "chai/expt/ContextManager.hpp" + + ::chai::expt::ContextManager& contextManager = ::chai::expt::ContextManager::getInstance(); + + contextManager.setContext(::chai::expt::Context::HOST); + // Use CHAI data structures in the HOST context... + contextManager.setContext(::chai::expt::Context::NONE); + + contextManager.setContext(::chai::expt::Context::DEVICE); + // Use CHAI data structures in the DEVICE context... + contextManager.setContext(::chai::expt::Context::NONE); + +------------ +ContextGuard +------------ + +It is easy to forget to reset the current context or even to forget the current context +when writing code. Similar to `std::lock_guard`, CHAI provides `ContextGuard` that sets +the active context and then resets it upon destruction. This is the recommended approach. + +.. code-block:: cpp + + #include "chai/expt/ContextGuard.hpp" + + { + ::chai::expt::ContextGuard contextGuard{::chai::expt::Context::HOST}; + // Use CHAI data structures in the HOST context... + } + + { + ::chai::expt::ContextGuard contextGuard{::chai::expt::Context::DEVICE}; + // Use CHAI data structures in the DEVICE context... + } + +----------------- +ContextRAJAPlugin +----------------- + +In an application that also uses RAJA, CHAI provides a RAJA plugin, `ContextRAJAPlugin`, +that implicitly manages the context in calls to RAJA. To enable this plugin, configure with +`-DCHAI_ENABLE_EXPERIMENTAL_RAJA_PLUGIN=ON` and register the plugin. In the future, registration +may be handled by CHAI. + +.. code-block:: cpp + + #include "chai/expt/ContextRAJAPlugin.hpp" + #include "RAJA/RAJA.hpp" + + static ::RAJA::util::PluginRegistry::add P( + "CHAIContextPlugin", + "Plugin that integrates CHAI context management with RAJA."); + + ::RAJA::forall<::RAJA::seq_exec>(::RAJA::TypedRangeSegment(0, N), [=] (int i) { + // Use CHAI data structures in the HOST context... + }); + + constexpr int BLOCK_SIZE = 256; + + ::RAJA::forall<::RAJA::cuda_exec_async>(::RAJA::TypedRangeSegment(0, N), [=] __device__ (int i) { + // Use CHAI data structures in the DEVICE context... + }); + +------------------- +ManagedArrayPointer +------------------- + +This class provides a uniform interface for working with different types of memory +across multiple backends. It has pointer semantics, meaning that copies are shallow, +which allows this object to be passed by value to a CUDA or HIP kernel. When copy +constructed, it queries the array manager to update the cached size and pointer +from the array manager. The array must be explicitly freed from only one of the +shallow copies. + +.. code-block:: cpp + + #include "chai/expt/ContextRAJAPlugin.hpp" + #include "chai/expt/ManagedArrayPointer.hpp" + #include "RAJA/RAJA.hpp" + + static ::RAJA::util::PluginRegistry::add P( + "CHAIContextPlugin", + "Plugin that integrates CHAI context management with RAJA."); + + // It's recommended to use an alias so that it is easy to swap out the array manager. + template + using ManagedArrayPointer = ::chai::expt::ManagedArrayPointer; + + const std::size_t N = 1000000; + ManagedArrayPointer a; + a.resize(N); + + ::RAJA::forall<::RAJA::seq_exec>(::RAJA::TypedRangeSegment(0, N), [=] (int i) { + a[i] = i; // Use CHAI data structures in the HOST context... + }); + + constexpr int BLOCK_SIZE = 256; + + ::RAJA::forall<::RAJA::cuda_exec_async>(::RAJA::TypedRangeSegment(0, N), [=] __device__ (int i) { + a[i] -= 1; // Use CHAI data structures in the DEVICE context... + }); + + a.free(); + +------------------------- +ManagedArraySharedPointer +------------------------- + +This class provides a uniform interface for working with different types of memory +across multiple backends. It has shared pointer semantics, meaning that copies are +shallow, which allows this object to be passed by value to a CUDA or HIP kernel. +When copy constructed, it queries the array manager to update the cached size and +pointer from the array manager. Similar to std::shared_ptr, all host copies have +shared ownership such that when the last host copy is destroyed, it will trigger +clean up of the underlying resources. Note that device copies are not reference +counted since clean up cannot be triggered from the device. + +.. code-block:: cpp + + #include "chai/expt/ContextRAJAPlugin.hpp" + #include "chai/expt/ManagedArraySharedPointer.hpp" + #include "RAJA/RAJA.hpp" + + static ::RAJA::util::PluginRegistry::add P( + "CHAIContextPlugin", + "Plugin that integrates CHAI context management with RAJA."); + + // It's recommended to use an alias so that it is easy to swap out the array manager. + template + using ManagedArraySharedPointer = ::chai::expt::ManagedArraySharedPointer; + + const std::size_t N = 1000000; + ManagedArraySharedPointer a; + a.resize(N); + + ::RAJA::forall<::RAJA::seq_exec>(::RAJA::TypedRangeSegment(0, N), [=] (int i) { + a[i] = i; // Use CHAI data structures in the HOST context... + }); + + constexpr int BLOCK_SIZE = 256; + + ::RAJA::forall<::RAJA::cuda_exec_async>(::RAJA::TypedRangeSegment(0, N), [=] __device__ (int i) { + a[i] -= 1; // Use CHAI data structures in the DEVICE context... + }); + +---------------- +ManagedArrayView +---------------- + +This class provides a uniform interface for viewing different types of memory +across multiple backends. It has shallow-copy semantics, which allows it to be +passed by value to a CUDA or HIP kernel. When copy constructed, it queries the +array manager to update the cached size and pointer from the array manager. +Unlike ``ManagedArrayPointer``, this class is non-owning: it cannot allocate, +resize, or free the underlying data, and the referenced manager must outlive +the view. + +.. code-block:: cpp + + #include "chai/expt/ContextRAJAPlugin.hpp" + #include "chai/expt/ManagedArrayView.hpp" + #include "chai/expt/UnifiedArrayManager.hpp" + #include "RAJA/RAJA.hpp" + + static ::RAJA::util::PluginRegistry::add P( + "CHAIContextPlugin", + "Plugin that integrates CHAI context management with RAJA."); + + // It's recommended to use an alias so that it is easy to swap out the array manager. + template + using UnifiedArrayManager = ::chai::expt::UnifiedArrayManager; + + template + using ManagedArrayView = ::chai::expt::ManagedArrayView>; + + const std::size_t N = 1000000; + UnifiedArrayManager manager{N}; + ManagedArrayView a{manager}; + + ::RAJA::forall<::RAJA::seq_exec>(::RAJA::TypedRangeSegment(0, N), [=] (int i) { + a[i] = i; // Use CHAI data structures in the HOST context... + }); + + constexpr int BLOCK_SIZE = 256; + + ::RAJA::forall<::RAJA::cuda_exec_async>(::RAJA::TypedRangeSegment(0, N), [=] __device__ (int i) { + a[i] -= 1; // Use CHAI data structures in the DEVICE context... + }); + +---------------- +HostArrayManager +---------------- + +This class manages a host array. It is designed for use with ManagedArrayPointer. + +HostArrayManager performs value initialization of each array element. +That is to say, numeric types will be initialized to zero and nontrivial +types will be default constructed. In the future, this behavior may +change to default initialization for performance reasons, such that +numeric types will be left in an indeterminate state and nontrivial +types will be default constructed. + +HostArrayManager does not rely on ContextManager, so it will behave +differently than other array managers. The major difference is that +when used with ManagedArrayPointer, the ManagedArrayPointer does not +need the update method called or to be copy constructed before it can +be used on the host. Since it will not respect the current Context, +be extra careful to avoid using it on the device. + +.. code-block:: cpp + + #include "chai/expt/HostArrayManager.hpp" + #include "chai/expt/ManagedArrayPointer.hpp" + + // It's recommended to use an alias so that it is easy to swap out the array manager. + template + using HostArrayManager = ::chai::expt::HostArrayManager; + + template + using ManagedArrayPointer = ::chai::expt::ManagedArrayPointer>; + + const std::size_t N = 1000000; + ManagedArrayPointer a{HostArrayManager(N)}; + + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } + +------------------ +UnifiedArrayManager +------------------ + +``UnifiedArrayManager`` manages a single contiguous array allocated from Umpire's +unified (managed) memory allocator (``UM``). Since unified memory is accessible +from both CPU and GPU, CHAI can provide a single pointer value that is valid in +both the ``HOST`` and ``DEVICE`` contexts. + +``UnifiedArrayManager`` relies on :ref:`ContextManager ` to +avoid unnecessary full device synchronizations and to ensure correctness when +switching between contexts: + +- ``data(touch=false)`` returns a pointer suitable for read access in the current + context and synchronizes with the most recent modifying context (if needed). +- ``data(touch=true)`` indicates the caller will modify the array in the current + context; it performs any required synchronization first, then records the + current context as the most recently modified context. + +Like ``HostArrayManager``, ``UnifiedArrayManager`` performs value initialization +of each element on the host (numeric types are initialized to zero). + +.. code-block:: cpp + + #include "chai/expt/Context.hpp" + #include "chai/expt/ContextGuard.hpp" + #include "chai/expt/UnifiedArrayManager.hpp" + + const std::size_t N = 1000000; + ::chai::expt::UnifiedArrayManager a{N}; + + { + ::chai::expt::ContextGuard guard{::chai::expt::Context::HOST}; + int* p = a.data(true); + for (std::size_t i = 0; i < N; ++i) { + p[i] = static_cast(i); + } + } + + { + ::chai::expt::ContextGuard guard{::chai::expt::Context::DEVICE}; + int* p = a.data(true); + // Launch a CUDA/HIP kernel that writes through p... + } + + { + ::chai::expt::ContextGuard guard{::chai::expt::Context::HOST}; + // If the most recent modification was on DEVICE, this call synchronizes first. + const int* p = a.data(false); + // Read through p... + } + +---------------- +DualArrayManager +---------------- + +``DualArrayManager`` manages separate host and device allocations and keeps them +coherent explicitly. Unlike ``UnifiedArrayManager``, it does not rely on a +single unified-memory pointer that is valid in both contexts. Instead, it +allocates storage lazily in the requested context and copies data between the +two allocations when the authoritative copy lives in the other context. + +``DualArrayManager`` relies on :ref:`ContextManager ` in +the same way as ``UnifiedArrayManager``: + +- ``data(touch=false)`` returns a pointer suitable for read access in the + current context and synchronizes with the most recent modifying context when + needed. +- ``data(touch=true)`` indicates the caller will modify the array in the current + context; it performs any required synchronization first, then records the + current context as authoritative. + +``DualArrayManager`` also performs value initialization of each element when a +new allocation is created. Since it uses raw host/device allocations and +byte-wise copies between them, it is intended for trivially copyable element +types. + +This manager is useful when an application wants explicit mirrored allocations +in host and device memory rather than unified memory. + +.. code-block:: cpp + + #include "chai/expt/Context.hpp" + #include "chai/expt/ContextGuard.hpp" + #include "chai/expt/DualArrayManager.hpp" + + const std::size_t N = 1000000; + ::chai::expt::DualArrayManager a{N}; + + { + ::chai::expt::ContextGuard guard{::chai::expt::Context::HOST}; + int* p = a.data(true); + for (std::size_t i = 0; i < N; ++i) { + p[i] = static_cast(i); + } + } + + { + ::chai::expt::ContextGuard guard{::chai::expt::Context::DEVICE}; + int* p = a.data(true); + // If the most recent modification was on HOST, this call copies to DEVICE first. + // Launch a CUDA/HIP kernel that writes through p... + } + + { + ::chai::expt::ContextGuard guard{::chai::expt::Context::HOST}; + // If the most recent modification was on DEVICE, this call synchronizes and copies first. + const int* p = a.data(false); + // Read through p... + } diff --git a/docs/sphinx/getting_started.rst b/docs/sphinx/getting_started.rst index 37131192..fb892d60 100644 --- a/docs/sphinx/getting_started.rst +++ b/docs/sphinx/getting_started.rst @@ -1,6 +1,6 @@ .. - # Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI - # project contributors. See the CHAI LICENSE file for details. + # Copyright (c) Lawrence Livermore National Security, LLC and other CHAI + # contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause diff --git a/docs/sphinx/index.rst b/docs/sphinx/index.rst index 225f83b4..16411dd7 100644 --- a/docs/sphinx/index.rst +++ b/docs/sphinx/index.rst @@ -1,6 +1,6 @@ .. - # Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI - # project contributors. See the CHAI LICENSE file for details. + # Copyright (c) Lawrence Livermore National Security, LLC and other CHAI + # contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause diff --git a/docs/sphinx/tutorial.rst b/docs/sphinx/tutorial.rst index 74a182de..2a2da144 100644 --- a/docs/sphinx/tutorial.rst +++ b/docs/sphinx/tutorial.rst @@ -1,6 +1,6 @@ .. - # Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI - # project contributors. See the CHAI LICENSE file for details. + # Copyright (c) Lawrence Livermore National Security, LLC and other CHAI + # contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause diff --git a/docs/sphinx/user_guide.rst b/docs/sphinx/user_guide.rst index 95ecf16f..d60a6d5f 100644 --- a/docs/sphinx/user_guide.rst +++ b/docs/sphinx/user_guide.rst @@ -1,6 +1,6 @@ .. - # Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI - # project contributors. See the CHAI LICENSE file for details. + # Copyright (c) Lawrence Livermore National Security, LLC and other CHAI + # contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause @@ -150,16 +150,16 @@ OK, so we didn't do all the work for you, but we definitely gave you a leg up. W class MyBaseClass { public: - CARE_HOST_DEVICE MyBaseClass() {} - CARE_HOST_DEVICE virtual ~MyBaseClass() {} - CARE_HOST_DEVICE virtual int getValue() const = 0; + CHAI_HOST_DEVICE MyBaseClass() {} + CHAI_HOST_DEVICE virtual ~MyBaseClass() {} + CHAI_HOST_DEVICE virtual int getValue() const = 0; }; class MyDerivedClass : public MyBaseClass { public: - CARE_HOST_DEVICE MyDerivedClass(int value) : MyBaseClass(), m_value(value) {} - CARE_HOST_DEVICE ~MyDerivedClass() {} - CARE_HOST_DEVICE int getValue() const { return m_value; } + CHAI_HOST_DEVICE MyDerivedClass(int value) : MyBaseClass(), m_value(value) {} + CHAI_HOST_DEVICE ~MyDerivedClass() {} + CHAI_HOST_DEVICE int getValue() const { return m_value; } private: int m_value; @@ -171,19 +171,19 @@ Now you may rightfully ask, what happens when this class contains raw pointers? class MyBaseClass { public: - CARE_HOST_DEVICE MyBaseClass() {} - CARE_HOST_DEVICE virtual ~MyBaseClass() {} - CARE_HOST_DEVICE virtual int getScalarValue() const = 0; - CARE_HOST_DEVICE virtual int getArrayValue(int index) const = 0; + CHAI_HOST_DEVICE MyBaseClass() {} + CHAI_HOST_DEVICE virtual ~MyBaseClass() {} + CHAI_HOST_DEVICE virtual int getScalarValue() const = 0; + CHAI_HOST_DEVICE virtual int getArrayValue(int index) const = 0; }; class MyDerivedClass : public MyBaseClass { public: - CARE_HOST_DEVICE MyDerivedClass(int scalarValue, int* arrayValue) + CHAI_HOST_DEVICE MyDerivedClass(int scalarValue, int* arrayValue) : MyBaseClass(), m_scalarValue(scalarValue), m_arrayValue(arrayValue) {} - CARE_HOST_DEVICE ~MyDerivedClass() {} - CARE_HOST_DEVICE int getScalarValue() const { return m_scalarValue; } - CARE_HOST_DEVICE int getArrayValue() const { return m_arrayValue; } + CHAI_HOST_DEVICE ~MyDerivedClass() {} + CHAI_HOST_DEVICE int getScalarValue() const { return m_scalarValue; } + CHAI_HOST_DEVICE int getArrayValue() const { return m_arrayValue; } private: int m_scalarValue; diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index fd7ef705..f33693f0 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/examples/chai-umpire-allocators.cpp b/examples/chai-umpire-allocators.cpp index a67e2b9e..8021d4c1 100644 --- a/examples/chai-umpire-allocators.cpp +++ b/examples/chai-umpire-allocators.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/examples/ex1.cpp b/examples/ex1.cpp index 10811cb1..1549ffad 100644 --- a/examples/ex1.cpp +++ b/examples/ex1.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/examples/example.cpp b/examples/example.cpp index 355368f7..f4802b79 100644 --- a/examples/example.cpp +++ b/examples/example.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/examples/managed_ptr_example.cpp b/examples/managed_ptr_example.cpp index afee1eed..b09e039c 100644 --- a/examples/managed_ptr_example.cpp +++ b/examples/managed_ptr_example.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/examples/pinned.cpp b/examples/pinned.cpp index 7fbc2dc8..2051a0b8 100644 --- a/examples/pinned.cpp +++ b/examples/pinned.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/host-configs/lc/toss_4_x86_64_ib/clang.cmake b/host-configs/lc/toss_4_x86_64_ib/clang.cmake index 2d97d400..6140a638 100644 --- a/host-configs/lc/toss_4_x86_64_ib/clang.cmake +++ b/host-configs/lc/toss_4_x86_64_ib/clang.cmake @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/host-configs/lc/toss_4_x86_64_ib/gcc.cmake b/host-configs/lc/toss_4_x86_64_ib/gcc.cmake index ba871f54..259c5596 100644 --- a/host-configs/lc/toss_4_x86_64_ib/gcc.cmake +++ b/host-configs/lc/toss_4_x86_64_ib/gcc.cmake @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/host-configs/lc/toss_4_x86_64_ib/intel.cmake b/host-configs/lc/toss_4_x86_64_ib/intel.cmake index 73c78fa9..ed58659b 100644 --- a/host-configs/lc/toss_4_x86_64_ib/intel.cmake +++ b/host-configs/lc/toss_4_x86_64_ib/intel.cmake @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/host-configs/lc/toss_4_x86_64_ib/nvcc_clang.cmake b/host-configs/lc/toss_4_x86_64_ib/nvcc_clang.cmake new file mode 100644 index 00000000..1f651f75 --- /dev/null +++ b/host-configs/lc/toss_4_x86_64_ib/nvcc_clang.cmake @@ -0,0 +1,35 @@ +############################################################################## +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +############################################################################## + +# Use gcc std libraries +set(GCC_VER "13.3.1" CACHE STRING "") +set(GCC_DIR "/usr/tce/packages/gcc/gcc-${GCC_VER}-magic" CACHE PATH "") + +# Use clang toolchain for host code compilers +set(CLANG_VER "19.1.3" CACHE STRING "") +set(CLANG_DIR "/usr/tce/packages/clang/clang-${CLANG_VER}-magic" CACHE PATH "") + +set(CMAKE_C_COMPILER "${CLANG_DIR}/bin/clang" CACHE PATH "") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --gcc-toolchain=${GCC_DIR}" CACHE STRING "") + +set(CMAKE_CXX_COMPILER "${CLANG_DIR}/bin/clang++" CACHE PATH "") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --gcc-toolchain=${GCC_DIR}" CACHE STRING "") + +# Use nvcc as the device code compiler +set(ENABLE_CUDA ON CACHE BOOL "") +set(CUDA_VER "12.9.1" CACHE STRING "") +set(CUDA_TOOLKIT_ROOT_DIR "/usr/tce/packages/cuda/cuda-${CUDA_VER}" CACHE PATH "") +set(CMAKE_CUDA_COMPILER "${CUDA_TOOLKIT_ROOT_DIR}/bin/nvcc" CACHE PATH "") +set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler=--gcc-toolchain=${GCC_DIR} --expt-relaxed-constexpr" CACHE STRING "") +set(CMAKE_CUDA_HOST_COMPILER "${CMAKE_CXX_COMPILER}" CACHE PATH "") +set(CMAKE_CUDA_ARCHITECTURES "90" CACHE STRING "") + +# Prevent incorrect implicit libraries from being linked in (if needed) +set(BLT_CMAKE_IMPLICIT_LINK_DIRECTORIES_EXCLUDE "" CACHE STRING "") + +# The header only version of fmt in umpire has issues with nvcc +set(UMPIRE_FMT_TARGET "fmt::fmt" CACHE STRING "") diff --git a/host-configs/lc/toss_4_x86_64_ib_cray/amdclang-xnack.cmake b/host-configs/lc/toss_4_x86_64_ib_cray/amdclang-xnack.cmake index cba57505..74289c1f 100644 --- a/host-configs/lc/toss_4_x86_64_ib_cray/amdclang-xnack.cmake +++ b/host-configs/lc/toss_4_x86_64_ib_cray/amdclang-xnack.cmake @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/host-configs/lc/toss_4_x86_64_ib_cray/amdclang.cmake b/host-configs/lc/toss_4_x86_64_ib_cray/amdclang.cmake index db1dafbd..fefc7bbd 100644 --- a/host-configs/lc/toss_4_x86_64_ib_cray/amdclang.cmake +++ b/host-configs/lc/toss_4_x86_64_ib_cray/amdclang.cmake @@ -1,13 +1,13 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## # Set up software versions -set(ROCM_VERSION "6.2.0" CACHE PATH "") -set(GCC_VERSION "12.2.1" CACHE PATH "") +set(ROCM_VERSION "6.4.3" CACHE PATH "") +set(GCC_VERSION "13.3.1" CACHE PATH "") # Set up compilers set(COMPILER_BASE "/usr/tce/packages/rocmcc/rocmcc-${ROCM_VERSION}-magic" CACHE PATH "") diff --git a/reproducers/CMakeLists.txt b/reproducers/CMakeLists.txt index d8d31c30..1a4b0cae 100644 --- a/reproducers/CMakeLists.txt +++ b/reproducers/CMakeLists.txt @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/reproducers/managed_ptr_multiple_inheritance_reproducer.cpp b/reproducers/managed_ptr_multiple_inheritance_reproducer.cpp index 5a357cf0..945dd61b 100644 --- a/reproducers/managed_ptr_multiple_inheritance_reproducer.cpp +++ b/reproducers/managed_ptr_multiple_inheritance_reproducer.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/reproducers/managed_ptr_reproducer.cpp b/reproducers/managed_ptr_reproducer.cpp index 8a4df2b3..72efac66 100644 --- a/reproducers/managed_ptr_reproducer.cpp +++ b/reproducers/managed_ptr_reproducer.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/reproducers/virtual_function_complex_reproducer.cpp b/reproducers/virtual_function_complex_reproducer.cpp index 31fd924f..4cfe76ff 100644 --- a/reproducers/virtual_function_complex_reproducer.cpp +++ b/reproducers/virtual_function_complex_reproducer.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/reproducers/virtual_function_simple_reproducer.cpp b/reproducers/virtual_function_simple_reproducer.cpp index ab2fea4a..a86cc397 100644 --- a/reproducers/virtual_function_simple_reproducer.cpp +++ b/reproducers/virtual_function_simple_reproducer.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/scripts/apply-license-info.sh b/scripts/apply-license-info.sh index 73e738b0..52087c13 100755 --- a/scripts/apply-license-info.sh +++ b/scripts/apply-license-info.sh @@ -1,35 +1,44 @@ #!/usr/bin/env zsh + ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## +# This is used for the ~*tpl* line to ignore files in bundled tpls setopt extended_glob +autoload colors + RED="\033[1;31m" GREEN="\033[1;32m" NOCOLOR="\033[0m" LIC_CMD=$(which lic) if [ ! $LIC_CMD ]; then - echo "${RED} [!] This script requires the lic command." + echo "${RED} [!] This script requires the lic command.${NOCOLOR}" exit 255 fi echo "Applying licenses to files" -files_no_license=$(grep -L 'This file is part of Umpire.' \ - benchmarks/**/*(^/) \ - cmake/**/*(^/) \ - docs/**/*~*rst(^/)\ - examples/**/*(^/) \ - scripts/**/*(^/) \ - src/**/*~*tpl*(^/) \ - tests/**/*(^/) \ - CMakeLists.txt) +files_no_license=$(grep -rL "SPDX-License-Identifier: BSD-3-Clause" . \ + --exclude-dir=.git \ + --exclude-dir=blt \ + --exclude-dir=umpire \ + --exclude-dir=raja \ + --exclude-dir=radiuss-spack-configs \ + --exclude-dir=uberenv \ + --exclude=.gitmodules \ + --exclude=.mailmap \ + --exclude=LICENSE \ + --exclude=COPYRIGHT \ + --exclude=NOTICE \ + --exclude=license.txt \ + --exclude=*.json) echo $files_no_license | xargs $LIC_CMD -f scripts/license.txt -echo "${GREEN} [Ok] License text applied. ${NOCOLOR}" +echo "${GREEN} [Ok] License text applied.${NOCOLOR}" diff --git a/scripts/check-license-info.sh b/scripts/check-license-info.sh index d5668e12..e804c3e5 100755 --- a/scripts/check-license-info.sh +++ b/scripts/check-license-info.sh @@ -1,9 +1,10 @@ #!/usr/bin/env zsh + ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # -# SPDX-License-Identifier: (MIT) +# SPDX-License-Identifier: BSD-3-Clause ############################################################################## # This is used for the ~*tpl* line to ignore files in bundled tpls @@ -15,13 +16,20 @@ RED="\033[1;31m" GREEN="\033[1;32m" NOCOLOR="\033[0m" -files_no_license=$(grep -rL "the CHAI LICENSE file" . \ +files_no_license=$(grep -rL "SPDX-License-Identifier: BSD-3-Clause" . \ --exclude-dir=.git \ --exclude-dir=blt \ --exclude-dir=umpire \ --exclude-dir=raja \ --exclude-dir=radiuss-spack-configs \ - --exclude-dir=uberenv) + --exclude-dir=uberenv \ + --exclude=.gitmodules \ + --exclude=.mailmap \ + --exclude=LICENSE \ + --exclude=COPYRIGHT \ + --exclude=NOTICE \ + --exclude=license.txt \ + --exclude=*.json) if [ $files_no_license ]; then print "${RED} [!] Some files are missing license text: ${NOCOLOR}" diff --git a/scripts/format-source.sh b/scripts/format-source.sh index 1f534590..78e66da7 100755 --- a/scripts/format-source.sh +++ b/scripts/format-source.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/scripts/gitlab/build_and_test.sh b/scripts/gitlab/build_and_test.sh index a9720405..023a12db 100755 --- a/scripts/gitlab/build_and_test.sh +++ b/scripts/gitlab/build_and_test.sh @@ -7,15 +7,31 @@ then fi ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## +# Navigation: +# - VARIABLES +# - HELPER FUNCTIONS +# - SETUP +# - BUILD DEPENDENCIES +# - HOST CONFIG / CMAKE CACHE FILES +# - BUILD PROJECT +# - TEST PROJECT +# - CLEANUP + +############################################################################### +# VARIABLES +############################################################################### + set -o errexit set -o nounset +exec 2>&1 + option=${1:-""} hostname="$(hostname)" truehostname=${hostname//[0-9]/} @@ -37,24 +53,167 @@ ci_registry_image=${CI_REGISTRY_IMAGE:-"czregistry.llnl.gov:5050/radiuss/chai"} export ci_registry_user=${CI_REGISTRY_USER:-"${USER}"} export ci_registry_token=${CI_JOB_TOKEN:-"${registry_token}"} -timed_message () +raja_version=${UPDATE_RAJA:-""} +umpire_version=${UPDATE_UMPIRE:-""} + +############################################################################### +# HELPER FUNCTIONS +############################################################################### + +# Helper function to print errors in red +print_error () { - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - echo "~ $(date --rfc-3339=seconds) ~ ${1}" - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + local error_msg="${1}" + echo -e "\e[31m[Error]: ${error_msg}\e[0m" } -raja_version=${UPDATE_RAJA:-""} -umpire_version=${UPDATE_UMPIRE:-""} +# Helper function to print warnings in gray +print_warning () +{ + local warning_msg="${1}" + echo -e "\e[1;30m[Warning]: ${warning_msg}\e[0m" +} + +# Helper function to print information +print_info () +{ + local info_msg="${1}" + echo -e "[Information]: ${info_msg}" +} + +# Portable UTC timestamp formatter for epoch seconds. +format_utc_timestamp () +{ + local timestamp="${1}" + # BSD/macOS date supports epoch conversion via: date -r + if date -u -r "${timestamp}" "+%Y-%m-%d %H:%M:%S UTC" >/dev/null 2>&1 + then + date -u -r "${timestamp}" "+%Y-%m-%d %H:%M:%S UTC" + else + # GNU date supports epoch conversion via: date -d "@" + date -u -d "@${timestamp}" "+%Y-%m-%d %H:%M:%S UTC" + fi +} + +# Portable elapsed time formatter (HH:MM:SS). +format_elapsed_hms () +{ + local elapsed="${1}" + printf '%02d:%02d:%02d' $((elapsed / 3600)) $(((elapsed % 3600) / 60)) $((elapsed % 60)) +} + +# Track script start time for elapsed time calculations +script_start_time=$(date +%s) + +# Storage for section start times (supports nesting) +declare -A section_start_times + +# Section stack for tracking nested sections +section_id_stack=() +section_counter=0 +section_indent="" + +# GitLab CI collapsible section helpers with nesting support +section_start () +{ + local section_name="${1}" + local section_title="${2}" + local section_state="${3:-""}" + + local collapsed="false" + if [[ "${section_state}" == "collapsed" ]] + then + collapsed="true" + fi + + # Generate unique section ID + section_counter=$((section_counter + 1)) + local section_id="${section_name}_${section_counter}" + + local timestamp=$(date +%s) + local current_time=$(format_utc_timestamp "${timestamp}") + local total_elapsed=$((timestamp - script_start_time)) + local total_elapsed_formatted=$(format_elapsed_hms "${total_elapsed}") + + # Store section start time for later calculation + section_start_times[${section_id}]=${timestamp} + + # Push section ID onto stack + section_id_stack+=("${section_id}") + + echo -e "\e[1;30m${section_indent}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[0m" + echo -e "\e[1;30m${section_indent}~ TIME | TOTAL | SECTION \e[0m" + echo -e "\e[1;30m${section_indent}~ ${current_time} | ${total_elapsed_formatted} | ${section_title}\e[0m" + echo -e "\e[0Ksection_start:${timestamp}:${section_id}[collapsed=${collapsed}]\r\e[0K${section_indent}~ ${section_title}" + + # Increase indentation for nested sections + section_indent="${section_indent} " +} + +section_end () +{ + # Pop section ID from stack + if [[ ${#section_id_stack[@]} -eq 0 ]]; then + print_warning "section_end called with empty stack" + return 1 + fi + + # Decrease indentation before displaying + section_indent="${section_indent% }" + + local stack_index=$((${#section_id_stack[@]} - 1)) + local section_id="${section_id_stack[$stack_index]}" + unset section_id_stack[$stack_index] + + local timestamp=$(date +%s) + local current_time=$(format_utc_timestamp "${timestamp}") + local total_elapsed=$((timestamp - script_start_time)) + local total_elapsed_formatted=$(format_elapsed_hms "${total_elapsed}") + + # Calculate section elapsed time + local section_start=${section_start_times[${section_id}]:-${timestamp}} + local section_elapsed=$((timestamp - section_start)) + local section_elapsed_formatted=$(format_elapsed_hms "${section_elapsed}") + + echo -e "\e[0Ksection_end:${timestamp}:${section_id}\r\e[0K\e[0m" + echo -e "\e[1;30m${section_indent}~ ${current_time} | ${total_elapsed_formatted} | ${section_elapsed_formatted}\e[0m" + echo -e "\e[1;30m${section_indent}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\e[0m" + + # Clean up stored time + unset section_start_times[${section_id}] +} + +# For convenience, a helper function to run a command within a section and handle errors +run_section () +{ + local id="$1" + local title="$2" + local collapsed="$3" + local err_msg="$4" + local status=0 + shift 4 + + section_start "$id" "$title" "$collapsed" + if "$@"; then + section_end + else + status=$? + section_end + print_error "$err_msg" + exit $status + fi +} + +############################################################################### +# SETUP +############################################################################### if [[ ${debug_mode} == true ]] then - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - echo "~~~~~ Debug mode:" - echo "~~~~~ - Spack debug mode." - echo "~~~~~ - Deactivated shared memory." - echo "~~~~~ - Do not push to buildcache." - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + print_info "Debug mode:" + print_info "- Spack debug mode." + print_info "- Deactivated shared memory." + print_info "- Do not push to buildcache." use_dev_shm=false spack_debug=true push_to_registry=false @@ -62,7 +221,7 @@ fi if [[ -n ${module_list} ]] then - timed_message "Modules to load: ${module_list}" + print_info "Loading modules: ${module_list}" module load ${module_list} fi @@ -85,28 +244,30 @@ else prefix="${project_dir}/../spack-and-build-root" fi -echo "Creating directory ${prefix}" -echo "project_dir: ${project_dir}" +print_info "Creating directory ${prefix}" +print_info "project_dir: ${project_dir}" mkdir -p ${prefix} spack_cmd="${prefix}/spack/bin/spack" spack_env_path="${prefix}/spack_env" -uberenv_cmd="./scripts/uberenv/uberenv.py" +uberenv_cmd="${project_dir}/scripts/uberenv/uberenv.py" if [[ ${spack_debug} == true ]] then spack_cmd="${spack_cmd} --debug --stacktrace" uberenv_cmd="${uberenv_cmd} --spack-debug" fi -# Dependencies +############################################################################### +# BUILD DEPENDENCIES +############################################################################### if [[ "${option}" != "--build-only" && "${option}" != "--test-only" ]] then - timed_message "Building dependencies" + section_start "dependencies" "Building Dependencies" if [[ -z ${spec} ]] then - echo "[Error]: SPEC is undefined, aborting..." + section_end ; print_error "SPEC is undefined, aborting..." exit 1 fi @@ -116,12 +277,12 @@ then if [[ -n ${raja_version} ]] then extra_variants="${extra_variants} +raja" - extra_deps="${extra_deps} ^raja@${raja_version}" + extra_deps="${extra_deps} ^raja@git.${raja_version}=develop" fi if [[ -n ${umpire_version} ]] then - extra_deps="${extra_deps} ^umpire@${umpire_version}" + extra_deps="${extra_deps} ^umpire@git.${umpire_version}=develop" fi [[ -n ${extra_variants} ]] && spec="${spec} ${extra_variants}" @@ -138,45 +299,51 @@ then mkdir -p ${spack_user_cache} # generate cmake cache file with uberenv and radiuss spack package - timed_message "Spack setup and environment" - ${uberenv_cmd} --setup-and-env-only --spec="${spec}" ${prefix_opt} + run_section "spack_setup" "Spack setup and environment" "collapsed" \ + "Spack environment setup failed (Uberenv)" \ + ${uberenv_cmd} --setup-and-env-only --spec="${spec}" ${prefix_opt} if [[ -n ${ci_registry_token} ]] then - timed_message "GitLab registry as Spack Buildcache" - ${spack_cmd} -D ${spack_env_path} mirror add --unsigned --oci-username-variable ci_registry_user --oci-password-variable ci_registry_token gitlab_ci oci://${ci_registry_image} + run_section "registry_setup" "GitLab registry as Spack Buildcache" "collapsed" \ + "Adding gitlab registry to spack environment failed" \ + ${spack_cmd} -D ${spack_env_path} mirror add --unsigned --oci-username-variable ci_registry_user --oci-password-variable ci_registry_token gitlab_ci oci://${ci_registry_image} fi - timed_message "Spack build of dependencies" - ${uberenv_cmd} --skip-setup-and-env --spec="${spec}" ${prefix_opt} + run_section "spack_build" "Spack build of dependencies" "collapsed" \ + "Spack build of dependencies failed (Uberenv)" \ + ${uberenv_cmd} --skip-setup-and-env --spec="${spec}" ${prefix_opt} if [[ -n ${ci_registry_token} && ${push_to_registry} == true ]] then - timed_message "Push dependencies to buildcache" - ${spack_cmd} -D ${spack_env_path} buildcache push --only dependencies gitlab_ci + run_section "buildcache_push" "Push dependencies to buildcache" "collapsed" \ + "Pushing dependencies to gitlab registry failed" \ + ${spack_cmd} -D ${spack_env_path} buildcache push --only dependencies gitlab_ci fi - timed_message "Dependencies built" + section_end fi -# Find cmake cache file (hostconfig) +############################################################################### +# HOST CONFIG / CMAKE CACHE FILE +############################################################################### if [[ -z ${hostconfig} ]] then # If no host config file was provided, we assume it was generated. # This means we are looking of a unique one in project dir. - hostconfigs=( $( ls "${project_dir}/"*.cmake ) ) + shopt -s nullglob; hostconfigs=( "${project_dir}"/*.cmake ); shopt -u nullglob if [[ ${#hostconfigs[@]} == 1 ]] then hostconfig_path=${hostconfigs[0]} elif [[ ${#hostconfigs[@]} == 0 ]] then - echo "[Error]: No result for: ${project_dir}/*.cmake" - echo "[Error]: Spack generated host-config not found." + print_error "No result for: ${project_dir}/*.cmake" + print_error "Spack generated host-config not found." exit 1 else - echo "[Error]: More than one result for: ${project_dir}/*.cmake" - echo "[Error]: ${hostconfigs[@]}" - echo "[Error]: Please specify one with HOST_CONFIG variable" + print_error "More than one result for: ${project_dir}/*.cmake" + print_error "${hostconfigs[@]}" + print_error "Please specify one with HOST_CONFIG variable" exit 1 fi else @@ -185,8 +352,11 @@ else fi hostconfig=$(basename ${hostconfig_path}) -echo "[Information]: Found hostconfig ${hostconfig_path}" +print_info "Found hostconfig ${hostconfig_path}" +############################################################################### +# BUILD PROJECT +############################################################################### # Build Directory # When using /dev/shm, we use prefix for both spack builds and source build, unless BUILD_ROOT was defined build_root=${BUILD_ROOT:-"${prefix}"} @@ -194,23 +364,20 @@ build_root=${BUILD_ROOT:-"${prefix}"} build_dir="${build_root}/build_${hostconfig//.cmake/}" install_dir="${build_root}/install_${hostconfig//.cmake/}" -cmake_exe=`grep 'CMake executable' ${hostconfig_path} | cut -d ':' -f 2 | xargs` +cmake_exe=$(grep 'CMake executable' ${hostconfig_path} | cut -d ':' -f 2 | xargs 2>/dev/null) -# Build if [[ "${option}" != "--deps-only" && "${option}" != "--test-only" ]] then - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - echo "~~~~~ Prefix: ${prefix}" - echo "~~~~~ Host-config: ${hostconfig_path}" - echo "~~~~~ Build Dir: ${build_dir}" - echo "~~~~~ Project Dir: ${project_dir}" - echo "~~~~~ Install Dir: ${install_dir}" - echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" - echo "" - timed_message "Cleaning working directory" + print_info "Prefix ${prefix}" + print_info "Host-config ${hostconfig_path}" + print_info "Build Dir ${build_dir}" + print_info "Project Dir ${project_dir}" + print_info "Install Dir ${install_dir}" + + section_start "clean" "Cleaning working directory" "collapsed" # Map CPU core allocations - declare -A core_counts=(["lassen"]=40 ["poodle"]=28 ["dane"]=28 ["matrix"]=28 ["corona"]=32 ["rzansel"]=48 ["tioga"]=32 ["tuolumne"]=48) + declare -A core_counts=(["dane"]=28 ["matrix"]=28 ["corona"]=32 ["tioga"]=32 ["tuolumne"]=48) # If building, then delete everything first # NOTE: 'cmake --build . -j core_counts' attempts to reduce individual build resources. @@ -218,8 +385,8 @@ then # use max cores. rm -rf ${build_dir} 2>/dev/null mkdir -p ${build_dir} && cd ${build_dir} + section_end - timed_message "Building CHAI" # We set the MPI tests command to allow overlapping. # Shared allocation: Allows build_and_test.sh to run within a sub-allocation (see CI config). # Use /dev/shm: Prevent MPI tests from running on a node where the build dir doesn't exist. @@ -229,78 +396,126 @@ then cmake_options="-DBLT_MPI_COMMAND_APPEND:STRING=--overlap" fi - $cmake_exe \ + section_start "cmake_config" "CMake Configuration" "collapsed" + if $cmake_exe \ -C ${hostconfig_path} \ ${cmake_options} \ -DCMAKE_INSTALL_PREFIX=${install_dir} \ ${project_dir} - if ! $cmake_exe --build . -j ${core_counts[$truehostname]} then - echo "[Error]: Compilation failed, building with verbose output..." - timed_message "Re-building with --verbose" - $cmake_exe --build . --verbose -j 1 + section_end + else + status=$? + section_end ; print_error "CMake configuration failed, dumping output..." + + $cmake_exe \ + -C ${hostconfig_path} \ + ${cmake_options} \ + -DCMAKE_INSTALL_PREFIX=${install_dir} \ + ${project_dir} --debug-output --trace-expand + + exit ${status} + fi + + section_start "build" "Building CHAI" "collapsed" + if $cmake_exe --build . -j ${core_counts[$truehostname]} + then + section_end else - timed_message "Installing" - $cmake_exe --install . + status=$? + section_end ; print_error "Compilation failed, building with verbose output..." + + section_start "build_verbose" "Verbose Rebuild" + $cmake_exe --build . --verbose -j 1 + section_end + + exit ${status} fi - timed_message "CHAI built and installed" + run_section "install" "Installing CHAI" "collapsed" \ + "Installation failed" \ + $cmake_exe --install . fi -# Test +############################################################################### +# TEST PROJECT +############################################################################### if [[ "${option}" != "--build-only" ]] && grep -q -i "ENABLE_TESTS.*ON" ${hostconfig_path} then if [[ ! -d ${build_dir} ]] then - echo "[Error]: Build directory not found : ${build_dir}" && exit 1 + print_error "Build directory not found : ${build_dir}" + exit 1 fi cd ${build_dir} - timed_message "Testing CHAI" + section_start "tests" "Running Tests" "collapsed" ctest --output-on-failure --no-compress-output -T test -VV 2>&1 | tee tests_output.txt + ctest_status=${PIPESTATUS[0]} no_test_str="No tests were found!!!" if [[ "$(tail -n 1 tests_output.txt)" == "${no_test_str}" ]] then - echo "[Error]: No tests were found" && exit 1 + section_end ; print_error "No tests were found (ctest status: ${ctest_status})" + exit 1 fi - timed_message "Preparing tests xml reports for export" tree Testing xsltproc -o junit.xml ${project_dir}/scripts/radiuss-spack-configs/utilities/ctest-to-junit.xsl Testing/*/Test.xml mv junit.xml ${project_dir}/junit.xml if grep -q "Errors while running CTest" ./tests_output.txt then - echo "[Error]: Failure(s) while running CTest" && exit 1 + section_end ; print_error "Failure(s) while running CTest (ctest status: ${ctest_status})" + exit 1 fi + section_end + + section_start "install_test" "Testing Installed Examples" "collapsed" if grep -q -i "ENABLE_HIP.*ON" ${hostconfig_path} then - echo "[Warning]: Not testing install with HIP" + section_end ; print_warning "Not testing install with HIP" else if [[ ! -d ${install_dir} ]] then - echo "[Error]: Install directory not found : ${install_dir}" && exit 1 + section_end ; print_error "Install directory not found : ${install_dir}" + exit 1 fi cd ${install_dir}/examples/chai/using-with-cmake mkdir build && cd build - if ! $cmake_exe -C ../host-config.cmake ..; then - echo "[Error]: Running $cmake_exe for using-with-cmake test" && exit 1 + if ! $cmake_exe -C ../host-config.cmake .. + then + section_end ; print_error "Running $cmake_exe for using-with-cmake test" + exit 1 fi - if ! make; then - echo "[Error]: Running make for using-with-cmake test" && exit 1 + if ! make + then + section_end ; print_error "Running make for using-with-cmake test" + exit 1 fi + section_end fi - - timed_message "CHAI tests completed" fi -timed_message "Cleaning up" -make clean +############################################################################### +# CLEANUP +############################################################################### + +section_start "cleanup" "Cleaning up" "collapsed" +if make clean +then + section_end +else + status=$? + section_end ; print_error "Cleanup failed" + exit ${status} +fi -timed_message "Build and test completed" +echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" +echo "~ Build and test completed" +echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" diff --git a/scripts/license.txt b/scripts/license.txt index a686e913..f1f3d995 100644 --- a/scripts/license.txt +++ b/scripts/license.txt @@ -1,10 +1,4 @@ -############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. -# -# SPDX-License-Identifier: BSD-3-Clause -############################################################################## -Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -project contributors. See the CHAI LICENSE file for details. +Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +contributors. See the CHAI LICENSE and COPYRIGHT files for details. SPDX-License-Identifier: BSD-3-Clause diff --git a/scripts/make_release_tarball.sh b/scripts/make_release_tarball.sh index b099f96c..1e72a0e0 100755 --- a/scripts/make_release_tarball.sh +++ b/scripts/make_release_tarball.sh @@ -1,8 +1,8 @@ #!/bin/bash ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/scripts/radiuss-spack-configs b/scripts/radiuss-spack-configs index fddc4f16..5a73b91c 160000 --- a/scripts/radiuss-spack-configs +++ b/scripts/radiuss-spack-configs @@ -1 +1 @@ -Subproject commit fddc4f16ee987abc9c1c61879eaf8a2d6a8253d9 +Subproject commit 5a73b91c06724ff089c13db1a3d197b5ea9d5c0c diff --git a/scripts/travis/build_and_test.sh b/scripts/travis/build_and_test.sh index 06a6fb88..f4ec4f54 100755 --- a/scripts/travis/build_and_test.sh +++ b/scripts/travis/build_and_test.sh @@ -1,7 +1,7 @@ #!/bin/bash ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/scripts/travis/install_llvm.sh b/scripts/travis/install_llvm.sh index f0d142ed..1581fd74 100755 --- a/scripts/travis/install_llvm.sh +++ b/scripts/travis/install_llvm.sh @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/scripts/uberenv b/scripts/uberenv index bec05e20..bf2f438f 160000 --- a/scripts/uberenv +++ b/scripts/uberenv @@ -1 +1 @@ -Subproject commit bec05e20bf2a1634d97ead358a9072c36f1fdcac +Subproject commit bf2f438fc1fe97bb8290a11e5d4f2d56085b4ee3 diff --git a/scripts/update-copyright.sh b/scripts/update-copyright.sh index 48c611b6..532c1804 100755 --- a/scripts/update-copyright.sh +++ b/scripts/update-copyright.sh @@ -1,68 +1,18 @@ #!/usr/bin/env bash ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # -# SPDX-License-Identifier: (MIT) +# SPDX-License-Identifier: BSD-3-Clause ############################################################################## -#============================================================================= -# Change the copyright date in all files that contain the text -# "the CHAI LICENSE file", which is part of the copyright statement at the -# top of each CHAI file. We use this to distinguish CHAI files from ones -# that we do not own (e.g., other repos included as submodules), which we -# do not want to modify. Note that this file and *.git files are omitted -# as well. -# -# IMPORTANT: Since this file is not modified (it is running the shell -# script commands), you must EDIT THE COPYRIGHT DATES IN THE HEADER ABOVE -# MANUALLY. -# -# Edit the 'grep' command below to change the set of files that will be -# modified. -# -# Change the 'sed' command below to change the content that is changed -# in each file and what it is changed to. Typically, this would only be -# modifying the end year in the copyright date. -# -#============================================================================= -# -# If you need to modify this script, you may want to run each of these -# commands individually from the command line to make sure things are doing -# what you think they should be doing. This is why they are separated into -# steps here. -# -#============================================================================= +set -euo pipefail -#============================================================================= -# First find all the files we want to modify -#============================================================================= -grep -rl "the CHAI LICENSE file" . --exclude-dir=.git --exclude-dir=blt --exclude-dir=umpire --exclude-dir=raja --exclude-dir=radiuss-spack-configs --exclude-dir=uberenv --exclude=update-copyright.sh > files2change +NEW_END_YEAR="2026" +echo "Updating copyright end year to ${NEW_END_YEAR}:" -#============================================================================= -# Replace the old copyright dates with new dates -#============================================================================= -for i in `cat files2change` -do - echo $i - cp $i $i.sed.bak - sed "s/Copyright (c) \([0-9]\{4\}\)-[0-9]\{2\},/Copyright (c) 2016-25,/" $i.sed.bak > $i +for file in "LICENSE" "docs/sphinx/conf.py" "docs/sphinx/conf.py.in" "README.md"; do + echo " $file" + sed -i "s/\([0-9]\{4\}\)-[0-9]\{4\}/\1-${NEW_END_YEAR}/g" "$file" done - -echo LICENSE -cp LICENSE LICENSE.sed.bak -sed "s/Copyright (c) \([0-9]\{4\}\)-[0-9]\{4\}/Copyright (c) 2016-25/" LICENSE.sed.bak > LICENSE - -for i in README.md CONTRIBUTING.md -do - echo $i - cp $i $i.sed.bak - sed "s/\([0-9]\{4\}\)-[0-9]\{2\}/2016-25/" $i.sed.bak > $i -done - -#============================================================================= -# Remove temporary files created in the process -#============================================================================= -find . -name \*.sed.bak -exec rm {} \; -rm files2change diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e42b7391..aa453bd5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## diff --git a/src/chai/ArrayManager.cpp b/src/chai/ArrayManager.cpp index b918baa5..6b43a772 100644 --- a/src/chai/ArrayManager.cpp +++ b/src/chai/ArrayManager.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/ArrayManager.hpp b/src/chai/ArrayManager.hpp index 08355d4b..67752f24 100644 --- a/src/chai/ArrayManager.hpp +++ b/src/chai/ArrayManager.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/ArrayManager.inl b/src/chai/ArrayManager.inl index f7811271..d8f6e0af 100644 --- a/src/chai/ArrayManager.inl +++ b/src/chai/ArrayManager.inl @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/CMakeLists.txt b/src/chai/CMakeLists.txt index cd8d5d8a..bb63a357 100644 --- a/src/chai/CMakeLists.txt +++ b/src/chai/CMakeLists.txt @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## @@ -23,33 +23,41 @@ set (chai_headers PointerRecord.hpp Types.hpp) +set (chai_sources + ArrayManager.cpp) + +if(CHAI_DISABLE_RM) + set(chai_headers + ${chai_headers} + ManagedArray_thin.inl) +endif () + if(CHAI_ENABLE_EXPERIMENTAL) set(chai_headers ${chai_headers} + expt/Context.hpp + expt/ContextGuard.hpp + expt/ContextManager.hpp + expt/DualArrayManager.hpp + expt/HostArrayManager.hpp + expt/HostSharedPointer.hpp + expt/ManagedArrayPointer.hpp + expt/ManagedArraySharedPointer.hpp + expt/ManagedArrayView.hpp + expt/UnifiedArrayManager.hpp ManagedSharedPtr.hpp SharedPtrCounter.hpp SharedPtrManager.hpp SharedPtrManager.inl SharedPointerRecord.hpp) -endif() -if(CHAI_DISABLE_RM) - set(chai_headers - ${chai_headers} - ManagedArray_thin.inl) -endif () - -set (chai_sources - ArrayManager.cpp) - -if(CHAI_ENABLE_EXPERIMENTAL) set (chai_sources ${chai_sources} SharedPtrManager.cpp) -endif () +endif() set (chai_depends - umpire) + ${CHAI_UMPIRE_TARGET}) if (CHAI_ENABLE_CUDA) set (chai_depends @@ -84,6 +92,16 @@ if (CHAI_ENABLE_RAJA_PLUGIN) endif () endif () +if (CHAI_ENABLE_EXPERIMENTAL_RAJA_PLUGIN) + set (chai_headers + ${chai_headers} + expt/ContextRAJAPlugin.hpp) + + set (chai_sources + ${chai_sources} + expt/ContextRAJAPlugin.cpp) +endif() + blt_add_library( NAME chai SOURCES ${chai_sources} diff --git a/src/chai/ChaiMacros.hpp b/src/chai/ChaiMacros.hpp index a1ec03aa..4ba6e980 100644 --- a/src/chai/ChaiMacros.hpp +++ b/src/chai/ChaiMacros.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/DeviceHelpers.hpp b/src/chai/DeviceHelpers.hpp index e9e63346..98ff6c05 100644 --- a/src/chai/DeviceHelpers.hpp +++ b/src/chai/DeviceHelpers.hpp @@ -1,3 +1,10 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + #ifndef CHAI_DEVICE_HELPERS_HPP #define CHAI_DEVICE_HELPERS_HPP diff --git a/src/chai/ExecutionSpaces.hpp b/src/chai/ExecutionSpaces.hpp index ed8ef960..1d6e61ce 100644 --- a/src/chai/ExecutionSpaces.hpp +++ b/src/chai/ExecutionSpaces.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/ManagedArray.hpp b/src/chai/ManagedArray.hpp index d88e24b0..b445a075 100644 --- a/src/chai/ManagedArray.hpp +++ b/src/chai/ManagedArray.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// @@ -15,6 +15,7 @@ #include "umpire/Allocator.hpp" +#include #include namespace chai @@ -76,6 +77,13 @@ template class ManagedArray : public CHAICopyable { public: + using size_type = size_t; + using value_type = T; + using reference = T&; + using const_reference = const T&; + using pointer = T*; + using const_pointer = const T*; + using T_non_const = typename std::remove_const::type; CHAI_HOST_DEVICE ManagedArray(); @@ -98,7 +106,9 @@ class ManagedArray : public CHAICopyable * \param elems Number of elements in the array. * \param space Execution space in which to allocate the array. */ - CHAI_HOST_DEVICE ManagedArray(size_t elems, ExecutionSpace space = get_default_space()); + CHAI_HOST_DEVICE explicit ManagedArray( + size_t elems, + ExecutionSpace space = get_default_space()); ManagedArray( size_t elems, @@ -126,14 +136,25 @@ class ManagedArray : public CHAICopyable /*! * \brief Construct a ManagedArray from a nullptr. + * + * \note The constraint prevents overload ambiguity between this + * constructor and the size_t constructor when constructing + * with the integer literal 0. Additionally, the constraint + * is a workaround for a nvcc bug where overload resolution + * can incorrectly report an ambiguity between this constructor + * and the size_t constructor. + * + * \todo Consider removing this constructor. */ - CHAI_HOST_DEVICE ManagedArray(std::nullptr_t other); + CHAI_HOST_DEVICE ManagedArray(std::same_as auto) : ManagedArray() {} CHAI_HOST ManagedArray(PointerRecord* record, ExecutionSpace space); /*! * \brief Allocate data for the ManagedArray in the specified space. * + * Once a ManagedArray is allocated, it will have a valid resource manager. + * * \param elems Number of elements to allocate. * \param space Execution space in which to allocate data. * \param cback User defined callback for memory events (alloc, free, move) @@ -289,6 +310,7 @@ class ManagedArray : public CHAICopyable * \brief Return the value of element i in the ManagedArray. * ExecutionSpace space to the current one * + * \pre ManagedArray must be allocated * \param index The index of the element to be fetched * \param space The index of the element to be fetched * \return The value of the i-th element in the ManagedArray. @@ -299,6 +321,7 @@ class ManagedArray : public CHAICopyable /*! * \brief Set the value of element i in the ManagedArray to be val. * + * \pre ManagedArray must be allocated * \param index The index of the element to be set * \param val Source location of the value * \tparam T The type of data value in ManagedArray. diff --git a/src/chai/ManagedArray.inl b/src/chai/ManagedArray.inl index b829ae68..d2a9b75a 100644 --- a/src/chai/ManagedArray.inl +++ b/src/chai/ManagedArray.inl @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// @@ -25,7 +25,6 @@ CHAI_HOST_DEVICE ManagedArray::ManagedArray(): m_is_slice(false) { #if !defined(CHAI_DEVICE_COMPILE) - m_resource_manager = ArrayManager::getInstance(); m_pointer_record = &ArrayManager::s_null_record; #endif } @@ -37,6 +36,7 @@ ManagedArray::ManagedArray( std::initializer_list allocators): ManagedArray() { + m_resource_manager = ArrayManager::getInstance(); m_pointer_record = new PointerRecord(); int i = 0; for (int s = CPU; s < NUM_EXECUTION_SPACES; ++s) { @@ -74,13 +74,6 @@ ManagedArray::ManagedArray( this->allocate(elems, space); } -template -CHAI_INLINE -CHAI_HOST_DEVICE ManagedArray::ManagedArray(std::nullptr_t) : - ManagedArray() -{ -} - template CHAI_INLINE CHAI_HOST ManagedArray::ManagedArray(PointerRecord* record, ExecutionSpace space): @@ -169,6 +162,9 @@ CHAI_HOST void ManagedArray::allocate( const UserCallback& cback) { if(!m_is_slice) { + if (m_resource_manager == nullptr) { + m_resource_manager = ArrayManager::getInstance(); + } if (elems > 0) { CHAI_LOG(Debug, "Allocating array of size " << elems << " in space " << space); @@ -300,6 +296,9 @@ template CHAI_INLINE CHAI_HOST void ManagedArray::reset() { + if (m_resource_manager == nullptr) { + return; + } m_resource_manager->resetTouch(m_pointer_record); } @@ -312,6 +311,9 @@ CHAI_HOST_DEVICE size_t ManagedArray::size() const { template CHAI_INLINE CHAI_HOST void ManagedArray::registerTouch(ExecutionSpace space) { + if (m_resource_manager == nullptr) { + return; + } if (m_active_pointer && (m_pointer_record == nullptr || m_pointer_record == &ArrayManager::s_null_record)) { CHAI_LOG(Warning,"registerTouch called on ManagedArray with nullptr pointer record."); m_pointer_record = m_resource_manager->makeManaged((void *)m_active_base_pointer,m_size,space,true); @@ -556,7 +558,7 @@ ManagedArray::operator= (std::nullptr_t) { m_offset = 0; #if !defined(CHAI_DEVICE_COMPILE) m_pointer_record = &ArrayManager::s_null_record; - m_resource_manager = ArrayManager::getInstance(); + m_resource_manager = nullptr; #else m_pointer_record = nullptr; m_resource_manager = nullptr; diff --git a/src/chai/ManagedArrayView.hpp b/src/chai/ManagedArrayView.hpp index e253fec5..1287ff9c 100644 --- a/src/chai/ManagedArrayView.hpp +++ b/src/chai/ManagedArrayView.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/ManagedArray_thin.inl b/src/chai/ManagedArray_thin.inl index 3bac948c..3de171eb 100644 --- a/src/chai/ManagedArray_thin.inl +++ b/src/chai/ManagedArray_thin.inl @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// @@ -69,21 +69,6 @@ CHAI_HOST_DEVICE ManagedArray::ManagedArray(size_t elems, ExecutionSpace spac #endif } - -template -CHAI_INLINE CHAI_HOST_DEVICE ManagedArray::ManagedArray(std::nullptr_t) - : m_active_pointer(nullptr), - m_active_base_pointer(nullptr), - m_resource_manager(nullptr), - m_size(0), - m_offset(0), - m_pointer_record(nullptr), - m_allocator_id(-1), - m_is_slice(false) -{ -} - - template CHAI_INLINE CHAI_HOST ManagedArray::ManagedArray(PointerRecord* record, ExecutionSpace space): diff --git a/src/chai/ManagedSharedPtr.hpp b/src/chai/ManagedSharedPtr.hpp index 9f2e9015..f1e5c73f 100644 --- a/src/chai/ManagedSharedPtr.hpp +++ b/src/chai/ManagedSharedPtr.hpp @@ -1,3 +1,10 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + #ifndef CHAI_MANAGED_SHARED_PTR #define CHAI_MANAGED_SHARED_PTR diff --git a/src/chai/PointerRecord.hpp b/src/chai/PointerRecord.hpp index 5510ff94..d7b89b85 100644 --- a/src/chai/PointerRecord.hpp +++ b/src/chai/PointerRecord.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/RajaExecutionSpacePlugin.cpp b/src/chai/RajaExecutionSpacePlugin.cpp index 20eb6aa2..930ef0f4 100644 --- a/src/chai/RajaExecutionSpacePlugin.cpp +++ b/src/chai/RajaExecutionSpacePlugin.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/RajaExecutionSpacePlugin.hpp b/src/chai/RajaExecutionSpacePlugin.hpp index 304bed6b..fe3b6647 100644 --- a/src/chai/RajaExecutionSpacePlugin.hpp +++ b/src/chai/RajaExecutionSpacePlugin.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/SharedPointerRecord.hpp b/src/chai/SharedPointerRecord.hpp index f714ac92..9ab11b23 100644 --- a/src/chai/SharedPointerRecord.hpp +++ b/src/chai/SharedPointerRecord.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-24, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/SharedPtrCounter.hpp b/src/chai/SharedPtrCounter.hpp index e37a7eba..a82f5ba1 100644 --- a/src/chai/SharedPtrCounter.hpp +++ b/src/chai/SharedPtrCounter.hpp @@ -1,7 +1,7 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-24, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/SharedPtrManager.cpp b/src/chai/SharedPtrManager.cpp index 78ce0dbc..9a392b1a 100644 --- a/src/chai/SharedPtrManager.cpp +++ b/src/chai/SharedPtrManager.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-24, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/SharedPtrManager.hpp b/src/chai/SharedPtrManager.hpp index 18d72a7b..1e3dc3fc 100644 --- a/src/chai/SharedPtrManager.hpp +++ b/src/chai/SharedPtrManager.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-24, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/SharedPtrManager.inl b/src/chai/SharedPtrManager.inl index 94cb7050..eca100b1 100644 --- a/src/chai/SharedPtrManager.inl +++ b/src/chai/SharedPtrManager.inl @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-24, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/Types.hpp b/src/chai/Types.hpp index 5894a562..ad2a5b85 100644 --- a/src/chai/Types.hpp +++ b/src/chai/Types.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/config.hpp.in b/src/chai/config.hpp.in index c2e016e7..e8b1f847 100644 --- a/src/chai/config.hpp.in +++ b/src/chai/config.hpp.in @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/expt/Context.hpp b/src/chai/expt/Context.hpp new file mode 100644 index 00000000..a0ff8b02 --- /dev/null +++ b/src/chai/expt/Context.hpp @@ -0,0 +1,24 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#ifndef CHAI_CONTEXT_HPP +#define CHAI_CONTEXT_HPP + +namespace chai::expt +{ + /*! + * \brief Execution context identifier. + */ + enum class Context + { + NONE = 0, /*!< No context. */ + HOST = 1, /*!< Host (CPU) context. */ + DEVICE = 2 /*!< Device (GPU/accelerator) context. */ + }; // enum class Context +} // namespace chai::expt + +#endif // CHAI_CONTEXT_HPP diff --git a/src/chai/expt/ContextGuard.hpp b/src/chai/expt/ContextGuard.hpp new file mode 100644 index 00000000..e735bdf4 --- /dev/null +++ b/src/chai/expt/ContextGuard.hpp @@ -0,0 +1,49 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#ifndef CHAI_CONTEXT_GUARD_HPP +#define CHAI_CONTEXT_GUARD_HPP + +#include "chai/expt/Context.hpp" +#include "chai/expt/ContextManager.hpp" + +namespace chai::expt { + /*! + * \brief RAII guard that temporarily sets the active Context and restores the + * previously active Context upon destruction. + */ + class ContextGuard { + public: + /*! + * \brief Sets the active Context for the lifetime of this guard. + * \param context The Context to set as active. + */ + explicit ContextGuard(Context context) { + m_context_manager.setContext(context); + } + + /*! + * \brief Restores the Context that was active when this guard was created. + */ + ~ContextGuard() { + m_context_manager.setContext(m_saved_context); + } + + private: + /*! + * \brief Reference to the global ContextManager instance. + */ + ContextManager& m_context_manager{ContextManager::getInstance()}; + + /*! + * Context that was active at guard construction time. + */ + Context m_saved_context{m_context_manager.getContext()}; + }; // class ContextGuard +} // namespace chai::expt + +#endif // CHAI_CONTEXT_GUARD_HPP diff --git a/src/chai/expt/ContextManager.hpp b/src/chai/expt/ContextManager.hpp new file mode 100644 index 00000000..45a1cdb3 --- /dev/null +++ b/src/chai/expt/ContextManager.hpp @@ -0,0 +1,141 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#ifndef CHAI_CONTEXT_MANAGER_HPP +#define CHAI_CONTEXT_MANAGER_HPP + +#include "chai/config.hpp" +#include "chai/expt/Context.hpp" +#include "camp/helpers.hpp" + +#if defined(CHAI_ENABLE_CUDA) +#include +#elif defined(CHAI_ENABLE_HIP) +#include +#endif + +namespace chai::expt { + /*! + * \brief Singleton class for managing the current context + * and context synchronization across the application. + */ + class ContextManager + { + public: + /*! + * \brief Get the singleton instance. + */ + static ContextManager& getInstance() + { + static ContextManager s_instance; + return s_instance; + } + + /*! + * \brief Disable copy construction. + * + * ContextManager is a singleton and must not be copied. + */ + ContextManager(const ContextManager&) = delete; + + /*! + * \brief Disable copy assignment. + * + * ContextManager is a singleton and must not be assigned. + */ + ContextManager& operator=(const ContextManager&) = delete; + + /*! + * \brief Get the current context. + */ + Context getContext() const + { + return m_context; + } + + /*! + * \brief Set the current context. + * + * Setting the context to DEVICE marks the device as not synchronized. + */ + void setContext(Context context) + { + m_context = context; + + if (context == Context::DEVICE) + { + m_device_synchronized = false; + } + } + + /*! + * \brief Synchronize the requested context (no-op if already synchronized). + */ + void synchronize(Context context) + { + if (context == Context::DEVICE && !m_device_synchronized) + { +#if defined(CHAI_ENABLE_CUDA) + CAMP_CUDA_API_INVOKE_AND_CHECK(cudaDeviceSynchronize); +#elif defined(CHAI_ENABLE_HIP) + CAMP_HIP_API_INVOKE_AND_CHECK(hipDeviceSynchronize); +#endif + m_device_synchronized = true; + } + } + + /*! + * \brief Query whether the requested context is synchronized. + */ + bool isSynchronized(Context context) const + { + return context == Context::DEVICE ? m_device_synchronized : true; + } + + /*! + * \brief Explicitly set the synchronization state for the DEVICE context. + */ + void setDeviceSynchronized(bool synchronized) + { + m_device_synchronized = synchronized; + } + + /*! + * \brief Reset manager state to defaults. + */ + void reset() + { + m_context = Context::NONE; + m_device_synchronized = true; + } + + private: + /*! + * \brief Default constructor. + * + * Private to enforce singleton access via getInstance(). + */ + ContextManager() = default; + + /*! + * \brief Current context for the application. + * + * Defaults to NONE until explicitly set. + */ + Context m_context{Context::NONE}; + + /*! + * \brief Device synchronization state. + * + * True if the device context has been synchronized since the last time the + * context was set to DEVICE. + */ + bool m_device_synchronized{true}; + }; // class ContextManager +} // namespace chai::expt + +#endif // CHAI_CONTEXT_MANAGER_HPP diff --git a/src/chai/expt/ContextRAJAPlugin.cpp b/src/chai/expt/ContextRAJAPlugin.cpp new file mode 100644 index 00000000..a35938dd --- /dev/null +++ b/src/chai/expt/ContextRAJAPlugin.cpp @@ -0,0 +1,42 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#include "chai/config.hpp" +#include "chai/expt/Context.hpp" +#include "chai/expt/ContextManager.hpp" +#include "chai/expt/ContextRAJAPlugin.hpp" + +namespace chai::expt { + void ContextRAJAPlugin::preCapture(const ::RAJA::util::PluginContext& p) { + Context context = Context::NONE; + + switch (p.platform) { + case ::RAJA::Platform::host: + context = Context::HOST; + break; +#if defined(CHAI_ENABLE_CUDA) + case ::RAJA::Platform::cuda: + context = Context::DEVICE; + break; +#endif +#if defined(CHAI_ENABLE_HIP) + case ::RAJA::Platform::hip: + context = Context::DEVICE; + break; +#endif + default: + context = Context::NONE; + break; + } + + ContextManager::getInstance().setContext(context); + } + + void ContextRAJAPlugin::postCapture(const ::RAJA::util::PluginContext&) { + ContextManager::getInstance().setContext(Context::NONE); + } +} // namespace chai::expt diff --git a/src/chai/expt/ContextRAJAPlugin.hpp b/src/chai/expt/ContextRAJAPlugin.hpp new file mode 100644 index 00000000..64690bf1 --- /dev/null +++ b/src/chai/expt/ContextRAJAPlugin.hpp @@ -0,0 +1,45 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#ifndef CHAI_CONTEXT_RAJA_PLUGIN_HPP +#define CHAI_CONTEXT_RAJA_PLUGIN_HPP + +#include "RAJA/util/PluginStrategy.hpp" + +namespace chai::expt { + /*! + * \brief Plugin that integrates CHAI context management with RAJA. + * + * CHAI data structures rely on being copy constructed in the correct context. + * Their typical usage is to capture them by copy into a lambda expression that + * is passed to RAJA. The lambda capture happens before the context is set, so + * RAJA calls the `preCapture` method, which sets the current execution context. + * Then RAJA copies the lambda, which triggers the copy constructors of the CHAI + * data structures, making their data coherent in the current execution context. + * Then RAJA calls the `postCapture` method, which unsets the current execution + * context so that the CHAI data structures do not update data coherence in an + * unexpected or unnecessary way. Finally, RAJA executes the lambda. + */ + class ContextRAJAPlugin : + public ::RAJA::util::PluginStrategy + { + public: + /*! + * \brief Sets the current context to match the RAJA execution context. + * \param p RAJA plugin context. + */ + void preCapture(const ::RAJA::util::PluginContext& p) override; + + /*! + * \brief Resets the current context. + * \param p RAJA plugin context for the capture. + */ + void postCapture(const ::RAJA::util::PluginContext& p) override; + }; // class ContextRAJAPlugin +} // namespace chai::expt + +#endif // CHAI_CONTEXT_RAJA_PLUGIN_HPP diff --git a/src/chai/expt/DualArrayManager.hpp b/src/chai/expt/DualArrayManager.hpp new file mode 100644 index 00000000..24513c0b --- /dev/null +++ b/src/chai/expt/DualArrayManager.hpp @@ -0,0 +1,511 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#ifndef CHAI_DUAL_ARRAY_MANAGER_HPP +#define CHAI_DUAL_ARRAY_MANAGER_HPP + +#include "chai/expt/Context.hpp" +#include "chai/expt/ContextManager.hpp" +#include "umpire/Allocator.hpp" +#include "umpire/ResourceManager.hpp" + +#include +#include +#include +#include + +namespace chai::expt +{ + /*! + * \brief This class manages mirrored host/device arrays with explicit + * synchronization between the two copies. + * + * \tparam ElementType The type of elements contained in this array. + * + * \note DualArrayManager uses raw host/device allocations and byte-wise copies + * between them. As a result, ElementType must be trivially copyable, + * default constructible, and trivially destructible. + */ + template + class DualArrayManager { + static_assert(std::is_trivially_copyable_v, + "DualArrayManager requires trivially copyable element types."); + static_assert(std::is_default_constructible_v, + "DualArrayManager requires default-constructible element types."); + static_assert(std::is_trivially_destructible_v, + "DualArrayManager requires trivially destructible element types."); + + public: + /*! + * \brief Default-constructs a DualArrayManager with zero elements + * and default host/device allocators. + */ + DualArrayManager() = default; + + /*! + * \brief Constructs a DualArrayManager with zero elements using the + * provided host and device allocators. + * + * \param host_allocator Allocator used for host memory allocations. + * \param device_allocator Allocator used for device memory allocations. + */ + DualArrayManager(const umpire::Allocator& host_allocator, + const umpire::Allocator& device_allocator) + : m_host_allocator{host_allocator}, + m_device_allocator{device_allocator} + { + } + + /*! + * \brief Constructs a DualArrayManager with \p size elements using + * default host/device allocators. + * + * \param size Number of elements to allocate when the data is first touched. + */ + explicit DualArrayManager(std::size_t size) + : m_size{size} + { + } + + /*! + * \brief Constructs a DualArrayManager with \p size elements using the + * provided host and device allocators. + * + * \param size Number of elements to allocate when the data is first touched. + * \param host_allocator Allocator used for host memory allocations. + * \param device_allocator Allocator used for device memory allocations. + */ + DualArrayManager(std::size_t size, + const umpire::Allocator& host_allocator, + const umpire::Allocator& device_allocator) + : m_size{size}, + m_host_allocator{host_allocator}, + m_device_allocator{device_allocator} + { + } + + /*! + * \brief Copy-constructs a DualArrayManager, duplicating any allocated + * host/device buffers. + * + * \param other Manager to copy from. + */ + DualArrayManager(const DualArrayManager& other) + : m_size{other.m_size}, + m_modified{other.m_modified}, + m_host_allocator{other.m_host_allocator}, + m_device_allocator{other.m_device_allocator} + { + clone(other); + } + + /*! + * \brief Copy-assigns a DualArrayManager, duplicating any allocated + * host/device buffers. + * + * \param other Manager to copy from. + * + * \return Reference to this manager. + */ + DualArrayManager& operator=(const DualArrayManager& other) + { + if (&other != this) + { + clear(); + + m_size = other.m_size; + m_modified = other.m_modified; + m_host_allocator = other.m_host_allocator; + m_device_allocator = other.m_device_allocator; + + clone(other); + } + + return *this; + } + + /*! + * \brief Move-constructs a DualArrayManager, transferring ownership of + * any allocated host/device buffers. + * + * \param other Manager to move from. + */ + DualArrayManager(DualArrayManager&& other) + : m_host_data{other.m_host_data}, + m_device_data{other.m_device_data}, + m_size{other.m_size}, + m_modified{other.m_modified}, + m_host_allocator{other.m_host_allocator}, + m_device_allocator{other.m_device_allocator} + { + other.m_host_data = nullptr; + other.m_device_data = nullptr; + other.m_size = 0; + other.m_modified = Context::NONE; + } + + /*! + * \brief Move-assigns a DualArrayManager, transferring ownership of any + * allocated host/device buffers. + * + * \param other Manager to move from. + * + * \return Reference to this manager. + */ + DualArrayManager& operator=(DualArrayManager&& other) + { + if (&other != this) + { + clear(); + + m_host_data = other.m_host_data; + m_device_data = other.m_device_data; + m_size = other.m_size; + m_modified = other.m_modified; + m_host_allocator = other.m_host_allocator; + m_device_allocator = other.m_device_allocator; + + other.m_host_data = nullptr; + other.m_device_data = nullptr; + other.m_size = 0; + other.m_modified = Context::NONE; + } + + return *this; + } + + /*! + * \brief Destructor. + * + * Deallocates any host/device buffers owned by this manager. + */ + ~DualArrayManager() + { + clear(); + } + + /*! + * \brief Resizes the managed allocation to \p new_size elements. + * + * Existing contents are preserved up to \c min(old_size, new_size). If + * storage has already been allocated, the resize happens in the most + * authoritative space and the opposite copy is discarded. + * + * \param new_size New number of elements. + */ + void resize(std::size_t new_size) + { + if (new_size == m_size) + { + return; + } + + if (new_size == 0) + { + clear(); + return; + } + + if (m_host_data == nullptr && m_device_data == nullptr) + { + m_size = new_size; + m_modified = Context::NONE; + return; + } + + const Context resize_context = choose_resize_context(); + const std::size_t old_size_bytes = m_size * sizeof(ElementType); + const std::size_t new_size_bytes = new_size * sizeof(ElementType); + + ElementType*& data = pointer(resize_context); + umpire::Allocator& allocator = getAllocator(resize_context); + + ElementType* new_data = static_cast(allocator.allocate(new_size_bytes)); + valueInitialize(new_data, new_size); + ::umpire::ResourceManager::getInstance().copy( + new_data, + data, + std::min(old_size_bytes, new_size_bytes)); + + deallocate(data, allocator); + data = new_data; + + if (resize_context == Context::HOST) + { + deallocate(m_device_data, m_device_allocator); + } + else + { + deallocate(m_host_data, m_host_allocator); + } + + m_size = new_size; + m_modified = resize_context; + } + + /*! + * \brief Returns the number of elements currently managed. + * + * \return Number of managed elements. + */ + std::size_t size() const + { + return m_size; + } + + /*! + * \brief Returns a pointer to the managed data in the current context. + * + * \param touch Whether the caller intends to modify the returned data. + * + * \return Pointer to the managed data, or nullptr if the current context + * is Context::NONE or the array is empty. + */ + ElementType* data(bool touch) + { + return data(ContextManager::getInstance().getContext(), touch); + } + + private: + /*! + * \brief Pointer to data in the HOST context. + */ + ElementType* m_host_data{nullptr}; + + /*! + * \brief Pointer to data in the DEVICE context. + */ + ElementType* m_device_data{nullptr}; + + /*! + * \brief Number of elements currently managed. + */ + std::size_t m_size{0}; + + /*! + * \brief Context that holds the most recently modified copy. + */ + Context m_modified{Context::NONE}; + + /*! + * \brief Allocator used for host memory allocations. + */ + umpire::Allocator m_host_allocator{::umpire::ResourceManager::getInstance().getAllocator("HOST")}; + + /*! + * \brief Allocator used for device memory allocations. + */ + umpire::Allocator m_device_allocator{ +#if defined(CHAI_ENABLE_CUDA) || defined(CHAI_ENABLE_HIP) + ::umpire::ResourceManager::getInstance().getAllocator("DEVICE") +#else + ::umpire::ResourceManager::getInstance().getAllocator("HOST") +#endif + }; + + /*! + * \brief Deep-copies any allocated buffers from \p other. + * + * \param other Manager to copy from. + */ + void clone(const DualArrayManager& other) + { + const std::size_t size_bytes = other.m_size * sizeof(ElementType); + + if (size_bytes == 0) + { + return; + } + + ContextManager::getInstance().synchronize(other.m_modified); + + if (other.m_host_data != nullptr) + { + m_host_data = static_cast(m_host_allocator.allocate(size_bytes)); + ::umpire::ResourceManager::getInstance().copy(m_host_data, other.m_host_data, size_bytes); + } + + if (other.m_device_data != nullptr) + { + m_device_data = static_cast(m_device_allocator.allocate(size_bytes)); + ::umpire::ResourceManager::getInstance().copy(m_device_data, other.m_device_data, size_bytes); + } + } + + /*! + * \brief Releases both host and device storage and resets the state. + */ + void clear() + { + deallocate(m_host_data, m_host_allocator); + deallocate(m_device_data, m_device_allocator); + m_size = 0; + m_modified = Context::NONE; + } + + /*! + * \brief Deallocates \p data when it is non-null. + * + * \param data Pointer to deallocate. + * \param allocator Allocator that owns \p data. + */ + static void deallocate(ElementType*& data, umpire::Allocator& allocator) + { + if (data != nullptr) + { + allocator.deallocate(data); + data = nullptr; + } + } + + /*! + * \brief Returns the allocator for \p context. + * + * \param context Desired context. + * + * \return Allocator for \p context. + */ + umpire::Allocator& getAllocator(Context context) + { + return context == Context::DEVICE ? m_device_allocator : m_host_allocator; + } + + /*! + * \brief Returns the storage pointer for \p context. + * + * \param context Desired context. + * + * \return Pointer reference for \p context. + */ + ElementType*& pointer(Context context) + { + return context == Context::DEVICE ? m_device_data : m_host_data; + } + + /*! + * \brief Returns the storage pointer for \p context. + * + * \param context Desired context. + * + * \return Pointer for \p context. + */ + ElementType* pointer(Context context) const + { + return context == Context::DEVICE ? m_device_data : m_host_data; + } + + /*! + * \brief Returns the opposite context for \p context. + * + * \param context Context whose opposite is requested. + * + * \return HOST for DEVICE, DEVICE for HOST. + */ + static Context otherContext(Context context) + { + return context == Context::DEVICE ? Context::HOST : Context::DEVICE; + } + + /*! + * \brief Chooses the context whose allocation should be preserved during + * resize. + * + * \return Context to resize in. + */ + Context choose_resize_context() const + { + if (m_modified != Context::NONE) + { + return m_modified; + } + + if (m_host_data != nullptr && m_device_data == nullptr) + { + return Context::HOST; + } + + if (m_device_data != nullptr && m_host_data == nullptr) + { + return Context::DEVICE; + } + + return ContextManager::getInstance().getContext() == Context::DEVICE + ? Context::DEVICE + : Context::HOST; + } + + /*! + * \brief Fills \p destination with value-initialized elements by staging + * from a temporary host buffer. + * + * \param destination Allocation to initialize. + * \param count Number of elements to initialize. + */ + static void valueInitialize(ElementType* destination, std::size_t count) + { + if (destination == nullptr || count == 0) + { + return; + } + + std::unique_ptr initialized{new ElementType[count]()}; + ::umpire::ResourceManager::getInstance().copy( + destination, + initialized.get(), + count * sizeof(ElementType)); + } + + /*! + * \brief Returns a pointer to the managed data in \p context, allocating + * and synchronizing as needed. + * + * \param context Desired context. + * \param touch Whether the caller intends to modify the returned data. + * + * \return Pointer to data in \p context, or nullptr if \p context is + * Context::NONE or the array is empty. + */ + ElementType* data(Context context, bool touch = true) + { + if (context == Context::NONE || m_size == 0) + { + return nullptr; + } + + ElementType*& destination = pointer(context); + ElementType* source = pointer(otherContext(context)); + const bool destination_was_missing = destination == nullptr; + const std::size_t size_bytes = m_size * sizeof(ElementType); + + if (destination_was_missing) + { + destination = static_cast(getAllocator(context).allocate(size_bytes)); + valueInitialize(destination, m_size); + } + + if (source != nullptr && + (destination_was_missing || m_modified == otherContext(context))) + { + ContextManager::getInstance().synchronize(m_modified); + ::umpire::ResourceManager::getInstance().copy(destination, source, size_bytes); + } + + if (touch) + { + m_modified = context; + } + else + { + m_modified = Context::NONE; + } + + return destination; + } + }; // class DualArrayManager +} // namespace chai::expt + +#endif // CHAI_DUAL_ARRAY_MANAGER_HPP diff --git a/src/chai/expt/HostArrayManager.hpp b/src/chai/expt/HostArrayManager.hpp new file mode 100644 index 00000000..d1593791 --- /dev/null +++ b/src/chai/expt/HostArrayManager.hpp @@ -0,0 +1,130 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// +#ifndef CHAI_HOST_ARRAY_MANAGER_HPP +#define CHAI_HOST_ARRAY_MANAGER_HPP + +#include "umpire/ResourceManager.hpp" +#include "umpire/TypedAllocator.hpp" +#include +#include + +namespace chai::expt +{ + /*! + * \brief This class manages a host array. It is designed for use with + * ManagedArrayPointer. + * + * \tparam ElementType The type of elements contained in this array. + * + * \note HostArrayManager performs value initialization of each array element. + * That is to say, numeric types will be initialized to zero and nontrivial + * types will be default constructed. In the future, this behavior may + * change to default initialization for performance reasons, such that + * numeric types will be left in an indeterminate state and nontrivial + * types will be default constructed. + * + * \note HostArrayManager does not rely on ContextManager, so it will behave + * differently than other array managers. The major difference is that + * when used with ManagedArrayPointer, the ManagedArrayPointer does not + * need the update method called or to be copy constructed before it can + * be used on the host. Since it will not respect the current Context, + * be extra careful to avoid using it on the device. + */ + template + class HostArrayManager { + private: + /*! + * \brief Allocator used by the managed host storage. + */ + using AllocatorType = ::umpire::TypedAllocator; + + /*! + * \brief Underlying contiguous host storage type for managed elements. + */ + using StorageType = std::vector; + + public: + /*! + * \brief Default-constructs a HostArrayManager with zero elements + * and a default allocator for host memory allocations. + */ + HostArrayManager() = default; + + /*! + * \brief Constructs a HostArrayManager with zero elements + * and \p allocator for host memory allocations. + * + * \param allocator Allocator used for host memory allocations. + */ + explicit HostArrayManager(const umpire::Allocator& allocator) + : m_storage{StorageType(AllocatorType(allocator))} + { + } + + /*! + * \brief Constructs a HostArrayManager with \p size elements + * using the default allocator for host memory allocations. + * + * \param size Number of elements to allocate. + */ + explicit HostArrayManager(std::size_t size) + : m_storage{StorageType(size, AllocatorType(::umpire::ResourceManager::getInstance().getAllocator("HOST")))} + { + } + + /*! + * \brief Constructs a HostArrayManager with \p size elements + * using \p allocator for host memory allocations. + * + * \param size Number of elements to allocate. + * \param allocator Allocator used for host memory allocations. + */ + HostArrayManager(std::size_t size, + const umpire::Allocator& allocator) + : m_storage{StorageType(size, AllocatorType(allocator))} + { + } + + /*! + * \brief Resizes the managed storage to \p new_size elements. + * + * \param new_size New number of elements. + */ + void resize(std::size_t new_size) + { + m_storage.resize(new_size); + } + + /*! + * \brief Returns the number of elements currently managed. + * + * \return Number of elements in the managed storage. + */ + std::size_t size() const + { + return m_storage.size(); + } + + /*! + * \brief Returns a pointer to the underlying contiguous storage. + * + * \return Pointer to the first element, or nullptr if the storage is empty. + */ + ElementType* data() + { + return m_storage.empty() ? nullptr : m_storage.data(); + } + + private: + /*! + * \brief Underlying host storage for the managed elements. + */ + StorageType m_storage{AllocatorType(::umpire::ResourceManager::getInstance().getAllocator("HOST"))}; + }; // class HostArrayManager +} // namespace chai::expt + +#endif // CHAI_HOST_ARRAY_MANAGER_HPP diff --git a/src/chai/expt/HostSharedPointer.hpp b/src/chai/expt/HostSharedPointer.hpp new file mode 100644 index 00000000..78d0e0b0 --- /dev/null +++ b/src/chai/expt/HostSharedPointer.hpp @@ -0,0 +1,164 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#ifndef CHAI_HOST_SHARED_POINTER_HPP +#define CHAI_HOST_SHARED_POINTER_HPP + +#include "chai/config.hpp" +#include "chai/ChaiMacros.hpp" +#include +#include +#include + +namespace chai::expt +{ + /*! + * \brief HostSharedPointer is a wrapper around std::shared_ptr that acts + * like std::shared_ptr on the host but has no effect on the device. + * + * \tparam T The type of object contained. + */ + template + class HostSharedPointer + { + private: + using SharedPointer = std::shared_ptr; + + public: + constexpr HostSharedPointer() noexcept + { + ::new (static_cast(std::addressof(m_storage))) SharedPointer(); + } + + constexpr HostSharedPointer(std::nullptr_t) noexcept + { + ::new (static_cast(std::addressof(m_storage))) SharedPointer(nullptr); + } + + template + explicit HostSharedPointer(U* ptr) + { + ::new (static_cast(std::addressof(m_storage))) SharedPointer(ptr); + } + + template + HostSharedPointer(const HostSharedPointer& other) noexcept + { + ::new (static_cast(std::addressof(m_storage))) SharedPointer(other); + } + + CHAI_HOST_DEVICE HostSharedPointer(const HostSharedPointer& other) noexcept + { +#if !defined(CHAI_DEVICE_COMPILE) + ::new (static_cast(std::addressof(m_storage))) SharedPointer(other.shared_ptr()); +#endif + } + + HostSharedPointer(HostSharedPointer&& other) noexcept + { + ::new (static_cast(std::addressof(m_storage))) SharedPointer(std::move(other.shared_ptr())); + } + + template + HostSharedPointer(HostSharedPointer&& other) noexcept + { + ::new (static_cast(std::addressof(m_storage))) SharedPointer(std::move(other.shared_ptr())); + } + + CHAI_HOST_DEVICE ~HostSharedPointer() + { +#if !defined(CHAI_DEVICE_COMPILE) + shared_ptr().~SharedPointer(); +#endif + } + + HostSharedPointer& operator=(const HostSharedPointer& other) noexcept + { + shared_ptr() = other.shared_ptr(); + return *this; + } + + template + HostSharedPointer& operator=(const HostSharedPointer& other) noexcept + { + shared_ptr() = other.shared_ptr(); + return *this; + } + + HostSharedPointer& operator=(HostSharedPointer&& other) noexcept + { + shared_ptr() = other.shared_ptr(); + return *this; + } + + template + HostSharedPointer& operator=(HostSharedPointer&& other) noexcept + { + shared_ptr() = other.shared_ptr(); + return *this; + } + + T* get() const noexcept + { + return shared_ptr().get(); + } + + T& operator*() const noexcept + { + return *get(); + } + + T* operator->() const noexcept + { + return get(); + } + + explicit operator bool() const noexcept + { + return get() != nullptr; + } + + private: + /*! + * \brief Raw, properly-aligned storage for the underlying std::shared_ptr. + * + * The shared_ptr is constructed/destructed in-place via placement new to avoid + * device-side effects when copy constructed or destroyed on the device. + */ + alignas(SharedPointer) std::byte m_storage[sizeof(SharedPointer)]; + + /*! + * \brief Access the underlying std::shared_ptr instance. + * + * \note The std::shared_ptr is stored in raw aligned storage and constructed + * in-place via placement new. std::launder is used to obtain a valid + * pointer to the active object. + * + * \return A mutable reference to the contained std::shared_ptr. + */ + SharedPointer& shared_ptr() + { + return *std::launder(reinterpret_cast(std::addressof(m_storage))); + } + + /*! + * \brief Access the underlying std::shared_ptr instance (const). + * + * \note The std::shared_ptr is stored in raw aligned storage and constructed + * in-place via placement new. std::launder is used to obtain a valid + * pointer to the active object. + * + * \return A const reference to the contained std::shared_ptr. + */ + const SharedPointer& shared_ptr() const + { + return *std::launder(reinterpret_cast(std::addressof(m_storage))); + } + }; // class HostSharedPointer +} // namespace chai::expt + +#endif // CHAI_HOST_SHARED_POINTER_HPP diff --git a/src/chai/expt/ManagedArrayPointer.hpp b/src/chai/expt/ManagedArrayPointer.hpp new file mode 100644 index 00000000..89b56931 --- /dev/null +++ b/src/chai/expt/ManagedArrayPointer.hpp @@ -0,0 +1,268 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#ifndef CHAI_MANAGED_ARRAY_POINTER_HPP +#define CHAI_MANAGED_ARRAY_POINTER_HPP + +#include "chai/config.hpp" +#include "chai/ChaiMacros.hpp" +#include +#include + +namespace chai::expt +{ + /*! + * \brief This class provides a uniform interface for working with different types of memory + * across multiple backends. It has pointer semantics, meaning that copies are shallow, + * which allows this object to be passed by value to a CUDA or HIP kernel. When copy + * constructed, it queries the array manager to update the cached size and pointer. + * from the array manager. The array must be explicitly freed from only one of the + * shallow copies. + * + * \tparam ElementType The type of elements contained in this array. + * \tparam ManagerType Manages the underlying memory. + */ + template + class ManagedArrayPointer + { + public: + /** + * \brief Factory that constructs a ManagerType then wraps it in a ManagedArrayPointer. + * + * \tparam Args Argument types used to construct ManagerType. + * \param args Arguments forwarded to ManagerType's constructor. + * \return A ManagedArrayPointer owning a newly constructed ManagerType. + */ + template + static ManagedArrayPointer make(Args&&... args) + { + return ManagedArrayPointer{ + ManagerType{std::forward(args)...} + }; + } + + /*! + * \brief Constructs a default ManagedArrayPointer. + * + * \details Creates a null pointer with size zero and no associated manager. + */ + ManagedArrayPointer() = default; + + /*! + * \brief Constructs an ManagedArrayPointer from an existing manager. + * + * \param manager An object that owns/manages the underlying array. + * + * \note Deep copies of the ManagerType object can and should be avoided + * by passing a temporary or an rvalue reference to this constructor. + */ + explicit ManagedArrayPointer(ManagerType manager) + : m_data{manager.data()}, + m_size{manager.size()}, + m_manager{new ManagerType(std::move(manager))} + { + } + + /*! + * \brief Copy-constructs an ManagedArrayPointer from another ManagedArrayPointer. + * + * \param other The ManagedArrayPointer to copy. + * + * \details Copies the cached pointer, size, and manager pointer. Ownership + * semantics are preserved (the manager pointer is shared). The internal + * cached pointer/size are synchronized by calling update(). + */ + CHAI_HOST_DEVICE ManagedArrayPointer(const ManagedArrayPointer& other) + : m_data{other.m_data}, + m_size{other.m_size}, + m_manager{other.m_manager} + { + update(); + } + + /*! + * \brief Converting copy-constructor from a non-const ManagedArrayPointer to a const ManagedArrayPointer. + * + * \tparam OtherElementType The source element type; must be non-const, and this + * ManagedArrayPointer's ElementType must be const-qualified version of it. + * + * \param other The source ManagedArrayPointer to copy from. + * + * \details This constructor is enabled only when converting from + * ManagedArrayPointer to ManagedArrayPointer. The manager + * pointer is shared (ownership semantics are preserved). + */ + template && + std::is_same_v>>> + CHAI_HOST_DEVICE ManagedArrayPointer(const ManagedArrayPointer& other) + : m_data{other.m_data}, + m_size{other.m_size}, + m_manager{other.m_manager} + { + } + + /*! + * \brief Copy-assigns from another ManagedArrayPointer. + * + * \param other The ManagedArrayPointer to copy from. + * + * \return Reference to this ManagedArrayPointer. + * + * \details Copies the cached pointer, size, and manager pointer. Ownership + * semantics are preserved (the manager pointer is shared). + */ + ManagedArrayPointer& operator=(const ManagedArrayPointer& other) = default; + + /*! + * \brief Resizes the underlying managed array. + * + * \param new_size New number of elements. + * + * \details If no manager is associated with this ManagedArrayPointer, a new manager is + * default-constructed. The cached pointer and size are invalidated (set to nullptr + * and zero, respectively), and the resize request is forwarded to the manager. + */ + void resize(std::size_t new_size) + { + if (m_manager == nullptr) + { + m_manager = new ManagerType(); + } + + m_manager->resize(new_size); + m_data = m_manager->data(); + m_size = new_size; + } + + /*! + * \brief Frees the owned manager and resets this ManagedArrayPointer to null/empty. + * + * \details Sets the cached data pointer to nullptr, size to 0, deletes the + * associated manager (if any), and clears the manager pointer. After calling + * free(), this ManagedArrayPointer is equivalent to default-constructed. + */ + void free() + { + m_data = nullptr; + m_size = 0; + delete m_manager; + m_manager = nullptr; + } + + /*! + * \brief Returns the number of elements in the underlying managed array. + * + * \return The number of elements. + * + * \details On host builds, synchronizes the cached size from the manager (if present). + * On device builds (CHAI_DEVICE_COMPILE), returns the last cached size. + */ + CHAI_HOST_DEVICE std::size_t size() const + { +#if !defined(CHAI_DEVICE_COMPILE) + if (m_manager) + { + m_size = m_manager->size(); + } +#endif + return m_size; + } + + /*! + * \brief Returns the cached pointer to the managed array's data. + * + * \return Pointer to the first element of the underlying managed array, or nullptr. + * + * \details On host builds, if a manager is present and provides a non-null data pointer, + * refreshes the cached pointer `m_data` from `m_manager->data()`. On device builds + * (CHAI_DEVICE_COMPILE), returns the cached pointer without querying the manager. + */ + CHAI_HOST_DEVICE ElementType* data() const + { +#if !defined(CHAI_DEVICE_COMPILE) + if (m_manager) + { + if (ElementType* data = static_cast(m_manager->data()); data) + { + m_data = data; + } + } +#endif + return m_data; + } + + /*! + * \brief Synchronizes the cached pointer and size from the manager. + * + * \details On host builds, if a manager is present, refreshes `m_data` from + * `m_manager->data()` (when non-null) and updates `m_size` from + * `m_manager->size()`. On device builds (CHAI_DEVICE_COMPILE), this function + * is a no-op and the cached values are returned as-is. + */ + CHAI_HOST_DEVICE void update() const + { +#if !defined(CHAI_DEVICE_COMPILE) + if (m_manager) + { + if (ElementType* data = static_cast(m_manager->data()); data) + { + m_data = data; + } + + m_size = m_manager->size(); + } +#endif + } + + /*! + * \brief Unchecked element access. + * + * \param i Element index. + * + * \return Reference to element i in the cached data pointer. + * + * \note No bounds checking is performed. + * \note Uses the cached pointer `m_data` and does not call update(). + */ + CHAI_HOST_DEVICE ElementType& operator[](std::size_t i) const + { + return m_data[i]; + } + + private: + /*! + * \brief Cached pointer to the managed array. + * + * \details This value is synchronized from the manager by update()/cupdate(). + * It is marked mutable to allow cache refresh in const member functions. + */ + mutable ElementType* m_data{nullptr}; + + /*! + * \brief Cached number of elements in the managed array. + * + * \details This value is synchronized from the manager by size()/update()/cupdate(). + * It is marked mutable to allow cache refresh in const member functions. + */ + mutable std::size_t m_size{0}; + + /*! + * \brief Pointer to the manager that owns/manages the underlying array. + * + * \details Ownership semantics are raw-pointer based: copies share this pointer, + * and free() may delete it. + */ + ManagerType* m_manager{nullptr}; + + /// Needed for the converting constructor + template + friend class ManagedArrayPointer; + }; // class ManagedArrayPointer +} // namespace chai::expt + +#endif // CHAI_MANAGED_ARRAY_POINTER_HPP diff --git a/src/chai/expt/ManagedArraySharedPointer.hpp b/src/chai/expt/ManagedArraySharedPointer.hpp new file mode 100644 index 00000000..9882274e --- /dev/null +++ b/src/chai/expt/ManagedArraySharedPointer.hpp @@ -0,0 +1,253 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#ifndef CHAI_MANAGED_ARRAY_SHARED_POINTER_HPP +#define CHAI_MANAGED_ARRAY_SHARED_POINTER_HPP + +#include "chai/config.hpp" +#include "chai/ChaiMacros.hpp" +#include "chai/expt/HostSharedPointer.hpp" +#include +#include + +namespace chai::expt +{ + /*! + * \brief This class provides a uniform interface for working with different types of memory + * across multiple backends. It has shared pointer semantics, meaning that copies are + * shallow, which allows this object to be passed by value to a CUDA or HIP kernel. + * When copy constructed, it queries the array manager to update the cached size and + * pointer from the array manager. Similar to std::shared_ptr, all host copies have + * shared ownership such that when the last host copy is destroyed, it will trigger + * clean up of the underlying resources. Note that device copies are not reference + * counted since clean up cannot be triggered from the device. + * + * \tparam ElementType The type of elements contained in this array. + * \tparam ManagerType Manages the underlying memory. + */ + template + class ManagedArraySharedPointer + { + public: + /** + * \brief Factory that constructs a ManagerType then wraps it in a ManagedArraySharedPointer. + * + * \tparam Args Argument types used to construct ManagerType. + * \param args Arguments forwarded to ManagerType's constructor. + * \return A ManagedArraySharedPointer owning a newly constructed ManagerType. + */ + template + static ManagedArraySharedPointer make(Args&&... args) + { + return ManagedArraySharedPointer{ + ManagerType{std::forward(args)...} + }; + } + + /*! + * \brief Constructs a default ManagedArraySharedPointer. + * + * \details Creates a null pointer with size zero and no associated manager. + */ + ManagedArraySharedPointer() = default; + + /*! + * \brief Constructs an ManagedArraySharedPointer from an existing manager. + * + * \param manager An object that owns/manages the underlying array. + * + * \note Deep copies of the ManagerType object can and should be avoided + * by passing a temporary or an rvalue reference to this constructor. + */ + explicit ManagedArraySharedPointer(ManagerType manager) + : m_data{manager.data()}, + m_size{manager.size()}, + m_manager{new ManagerType{std::move(manager)}} + { + } + + /*! + * \brief Copy-constructs an ManagedArraySharedPointer from another ManagedArraySharedPointer. + * + * \param other The ManagedArraySharedPointer to copy. + * + * \details Copies the cached pointer, size, and manager pointer. Ownership + * semantics are preserved (the manager pointer is shared). The internal + * cached pointer/size are synchronized by calling update(). + */ + CHAI_HOST_DEVICE ManagedArraySharedPointer(const ManagedArraySharedPointer& other) + : m_data{other.m_data}, + m_size{other.m_size}, + m_manager{other.m_manager} + { + update(); + } + + /*! + * \brief Converting copy-constructor from a non-const ManagedArraySharedPointer to a const ManagedArraySharedPointer. + * + * \tparam OtherElementType The source element type; must be non-const, and this + * ManagedArraySharedPointer's ElementType must be const-qualified version of it. + * + * \param other The source ManagedArraySharedPointer to copy from. + * + * \details This constructor is enabled only when converting from + * ManagedArraySharedPointer to ManagedArraySharedPointer. The manager + * pointer is shared (ownership semantics are preserved). + */ + template && + std::is_same_v>>> + CHAI_HOST_DEVICE ManagedArraySharedPointer(const ManagedArraySharedPointer& other) + : m_data{other.m_data}, + m_size{other.m_size}, + m_manager{other.m_manager} + { + } + + /*! + * \brief Copy-assigns from another ManagedArraySharedPointer. + * + * \param other The ManagedArraySharedPointer to copy from. + * + * \return Reference to this ManagedArraySharedPointer. + * + * \details Copies the cached pointer, size, and manager pointer. Ownership + * semantics are preserved (the manager pointer is shared). + */ + ManagedArraySharedPointer& operator=(const ManagedArraySharedPointer& other) = default; + + /*! + * \brief Resizes the underlying managed array. + * + * \param new_size New number of elements. + * + * \details If no manager is associated with this ManagedArraySharedPointer, a new manager is + * default-constructed. The cached pointer and size are invalidated (set to nullptr + * and zero, respectively), and the resize request is forwarded to the manager. + */ + void resize(std::size_t new_size) + { + if (!m_manager) + { + m_manager = HostSharedPointer{new ManagerType{}}; + } + + m_manager->resize(new_size); + m_data = m_manager->data(); + m_size = new_size; + } + + /*! + * \brief Returns the number of elements in the underlying managed array. + * + * \return The number of elements. + * + * \details On host builds, synchronizes the cached size from the manager (if present). + * On device builds (CHAI_DEVICE_COMPILE), returns the last cached size. + */ + CHAI_HOST_DEVICE std::size_t size() const + { +#if !defined(CHAI_DEVICE_COMPILE) + if (m_manager) + { + m_size = m_manager->size(); + } +#endif + return m_size; + } + + /*! + * \brief Returns the cached pointer to the managed array's data. + * + * \return Pointer to the first element of the underlying managed array, or nullptr. + * + * \details On host builds, if a manager is present and provides a non-null data pointer, + * refreshes the cached pointer `m_data` from `m_manager->data()`. On device builds + * (CHAI_DEVICE_COMPILE), returns the cached pointer without querying the manager. + */ + CHAI_HOST_DEVICE ElementType* data() const + { +#if !defined(CHAI_DEVICE_COMPILE) + if (m_manager) + { + if (ElementType* data = m_manager->data(); data) + { + m_data = data; + } + } +#endif + return m_data; + } + + /*! + * \brief Synchronizes the cached pointer and size from the manager. + * + * \details On host builds, if a manager is present, refreshes `m_data` from + * `m_manager->data()` (when non-null) and updates `m_size` from + * `m_manager->size()`. On device builds (CHAI_DEVICE_COMPILE), this function + * is a no-op and the cached values are returned as-is. + */ + CHAI_HOST_DEVICE void update() const + { +#if !defined(CHAI_DEVICE_COMPILE) + if (m_manager) + { + if (ElementType* data = m_manager->data(); data) + { + m_data = data; + } + + m_size = m_manager->size(); + } +#endif + } + + /*! + * \brief Unchecked element access. + * + * \param i Element index. + * + * \return Reference to element i in the cached data pointer. + * + * \note No bounds checking is performed. + * \note Uses the cached pointer `m_data` and does not call update(). + */ + CHAI_HOST_DEVICE ElementType& operator[](std::size_t i) const + { + return m_data[i]; + } + + private: + /*! + * \brief Cached pointer to the managed array. + * + * \details This value is synchronized from the manager by data()/update(). + * It is marked mutable to allow cache refresh in const member functions. + */ + mutable ElementType* m_data{nullptr}; + + /*! + * \brief Cached number of elements in the managed array. + * + * \details This value is synchronized from the manager by size()/update(). + * It is marked mutable to allow cache refresh in const member functions. + */ + mutable std::size_t m_size{0}; + + /*! + * \brief Manager that owns/manages the underlying array. + */ + HostSharedPointer m_manager{}; + + /// Needed for the converting constructor + template + friend class ManagedArraySharedPointer; + }; // class ManagedArraySharedPointer +} // namespace chai::expt + +#endif // CHAI_MANAGED_ARRAY_SHARED_POINTER_HPP diff --git a/src/chai/expt/ManagedArrayView.hpp b/src/chai/expt/ManagedArrayView.hpp new file mode 100644 index 00000000..bc1612b2 --- /dev/null +++ b/src/chai/expt/ManagedArrayView.hpp @@ -0,0 +1,187 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#ifndef CHAI_EXPT_MANAGED_ARRAY_VIEW_HPP +#define CHAI_EXPT_MANAGED_ARRAY_VIEW_HPP + +#include "chai/config.hpp" +#include "chai/ChaiMacros.hpp" + +#include +#include +namespace chai::expt +{ + /*! + * \brief This class provides a uniform interface for viewing different types + * of managed array memory across multiple backends. + * + * \details This class has shallow-copy semantics, which allows it to be + * passed by value to a CUDA or HIP kernel. When copy constructed, + * it queries the array manager to update the cached size and pointer + * from the array manager. This acts as a non-owning view and cannot + * allocate, free, or resize the underlying data. + * + * \tparam ElementType The type of elements contained in this array. + * \tparam ManagerType Manages the underlying memory. + */ + template + class ManagedArrayView + { + public: + /*! + * \brief Constructs a default ManagedArrayView. + * + * \details Creates a null pointer with size zero and no associated manager. + */ + ManagedArrayView() = default; + + /*! + * \brief Constructs a ManagedArrayView from an existing manager. + * + * \param manager An object that owns/manages the underlying array. + * + * \note The manager is not copied or owned. The caller must ensure the + * manager outlives the view. + */ + explicit ManagedArrayView(ManagerType& manager) + : m_data{manager.data()}, + m_size{manager.size()}, + m_manager{&manager} + { + } + + /*! + * \brief Copy-constructs a ManagedArrayView from another ManagedArrayView. + * + * \param other The ManagedArrayView to copy. + * + * \details Copies the cached pointer, size, and manager pointer. The + * cached pointer/size are synchronized by calling update(). + */ + CHAI_HOST_DEVICE ManagedArrayView(const ManagedArrayView& other) + : m_data{other.m_data}, + m_size{other.m_size}, + m_manager{other.m_manager} + { + update(); + } + + /*! + * \brief Converting copy-constructor from a non-const ManagedArrayView to a const ManagedArrayView. + * + * \tparam OtherElementType The source element type; must be non-const, and this + * ManagedArrayView's ElementType must be const-qualified version of it. + * + * \param other The source ManagedArrayView to copy from. + */ + template && + std::is_same_v>>> + CHAI_HOST_DEVICE ManagedArrayView(const ManagedArrayView& other) + : m_data{other.m_data}, + m_size{other.m_size}, + m_manager{other.m_manager} + { + } + + /*! + * \brief Copy-assigns from another ManagedArrayView. + * + * \param other The ManagedArrayView to copy from. + * + * \return Reference to this ManagedArrayView. + */ + ManagedArrayView& operator=(const ManagedArrayView& other) = default; + + /*! + * \brief Returns the number of elements in the underlying managed array. + * + * \return The number of elements. + */ + CHAI_HOST_DEVICE std::size_t size() const + { +#if !defined(CHAI_DEVICE_COMPILE) + if (m_manager) + { + m_size = m_manager->size(); + } +#endif + return m_size; + } + + /*! + * \brief Returns the cached pointer to the managed array's data. + * + * \return Pointer to the first element of the underlying managed array, or nullptr. + */ + CHAI_HOST_DEVICE ElementType* data() const + { +#if !defined(CHAI_DEVICE_COMPILE) + if (m_manager) + { + if (ElementType* data = static_cast(m_manager->data()); data) + { + m_data = data; + } + } +#endif + return m_data; + } + + /*! + * \brief Synchronizes the cached pointer and size from the manager. + */ + CHAI_HOST_DEVICE void update() const + { +#if !defined(CHAI_DEVICE_COMPILE) + if (m_manager) + { + if (ElementType* data = static_cast(m_manager->data()); data) + { + m_data = data; + } + + m_size = m_manager->size(); + } +#endif + } + + /*! + * \brief Unchecked element access. + * + * \param i Element index. + * + * \return Reference to element i in the cached data pointer. + */ + CHAI_HOST_DEVICE ElementType& operator[](std::size_t i) const + { + return m_data[i]; + } + + private: + /*! + * \brief Cached pointer to the managed array. + */ + mutable ElementType* m_data{nullptr}; + + /*! + * \brief Cached number of elements in the managed array. + */ + mutable std::size_t m_size{0}; + + /*! + * \brief Pointer to the manager that owns/manages the underlying array. + */ + ManagerType* m_manager{nullptr}; + + /// Needed for the converting constructor + template + friend class ManagedArrayView; + }; // class ManagedArrayView +} // namespace chai::expt + +#endif // CHAI_EXPT_MANAGED_ARRAY_VIEW_HPP diff --git a/src/chai/expt/UnifiedArrayManager.hpp b/src/chai/expt/UnifiedArrayManager.hpp new file mode 100644 index 00000000..56845298 --- /dev/null +++ b/src/chai/expt/UnifiedArrayManager.hpp @@ -0,0 +1,160 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#ifndef CHAI_UNIFIED_ARRAY_MANAGER_HPP +#define CHAI_UNIFIED_ARRAY_MANAGER_HPP + +#include "chai/expt/Context.hpp" +#include "chai/expt/ContextManager.hpp" +#include "umpire/ResourceManager.hpp" +#include "umpire/TypedAllocator.hpp" +#include +#include + +namespace chai::expt +{ + /*! + * \brief This class manages a unified memory array. It is designed for use + * with ManagedArrayPointer. + * + * \tparam ElementType The type of elements contained in this array. + * + * \note UnifiedArrayManager performs value initialization of each array element. + * That is to say, numeric types will be initialized to zero and nontrivial + * types will be default constructed. This initialization occurs on the host. + * In the future, this behavior may change to default initialization for + * performance reasons, such that numeric types will be left in an + * indeterminate state and nontrivial types will be default constructed. + */ + template + class UnifiedArrayManager { + private: + /*! + * \brief Allocator used by the managed unified memory storage. + */ + using AllocatorType = ::umpire::TypedAllocator; + + /*! + * \brief Underlying contiguous unified memory storage type for managed elements. + */ + using StorageType = std::vector; + + public: + /*! + * \brief Default-constructs a UnifiedArrayManager with zero elements + * and a default allocator for unified memory allocations. + */ + UnifiedArrayManager() = default; + + /*! + * \brief Constructs a UnifiedArrayManager with zero elements + * and \p allocator for unified memory allocations. + * + * \param allocator Allocator used for unified memory allocations. + */ + explicit UnifiedArrayManager(const umpire::Allocator& allocator) + : m_storage{StorageType(AllocatorType(allocator))} + { + } + + /*! + * \brief Constructs a UnifiedArrayManager with \p size elements + * using the default allocator for unified memory allocations. + * + * \param size Number of elements to allocate. + */ + explicit UnifiedArrayManager(std::size_t size) + : m_storage{StorageType(size, AllocatorType(::umpire::ResourceManager::getInstance().getAllocator("UM")))} + { + } + + /*! + * \brief Constructs a UnifiedArrayManager with \p size elements + * using \p allocator for unified memory allocations. + * + * \param size Number of elements to allocate. + * \param allocator Allocator used for unified memory allocations. + */ + UnifiedArrayManager(std::size_t size, + const umpire::Allocator& allocator) + : m_storage{StorageType(size, AllocatorType(allocator))} + { + } + + /*! + * \brief Resizes the managed storage to \p new_size elements. + * + * \param new_size New number of elements. + */ + void resize(std::size_t new_size) + { + // TODO: Investigate resize in the last modified space. + Context context = Context::HOST; + + if (context != m_modified) + { + ContextManager::getInstance().synchronize(m_modified); + } + + m_storage.resize(new_size); + m_modified = context; + } + + /*! + * \brief Returns the number of elements currently managed. + * + * \return Number of elements in the managed storage. + */ + std::size_t size() const + { + return m_storage.size(); + } + + /*! + * \brief Returns a pointer to the underlying contiguous storage. + * + * \return Pointer to the first element, or nullptr if the storage is empty. + */ + ElementType* data(bool touch) + { + ContextManager& contextManager = ContextManager::getInstance(); + Context context = contextManager.getContext(); + + if (context != m_modified) + { + contextManager.synchronize(m_modified); + } + + if (touch) + { + m_modified = context; + } + else + { + m_modified = Context::NONE; + } + + return m_storage.empty() ? nullptr : m_storage.data(); + } + + private: + /*! + * \brief Underlying unified memory storage for the managed elements. + */ + StorageType m_storage{AllocatorType(::umpire::ResourceManager::getInstance().getAllocator("UM"))}; + + /*! + * \brief Context in which the managed storage was most recently modified. + * + * \note Used to determine when synchronization is required before accessing + * the underlying storage from the current context. + */ + Context m_modified{Context::NONE}; + }; // class UnifiedArrayManager +} // namespace chai::expt + +#endif // CHAI_UNIFIED_ARRAY_MANAGER_HPP diff --git a/src/chai/managed_array.hpp b/src/chai/managed_array.hpp index 3094e07f..f8b20c59 100644 --- a/src/chai/managed_array.hpp +++ b/src/chai/managed_array.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/managed_ptr.hpp b/src/chai/managed_ptr.hpp index ff612537..0bed0a19 100644 --- a/src/chai/managed_ptr.hpp +++ b/src/chai/managed_ptr.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/chai/pluginLinker.hpp b/src/chai/pluginLinker.hpp index 1b336093..68056b2a 100644 --- a/src/chai/pluginLinker.hpp +++ b/src/chai/pluginLinker.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/src/tpl/raja b/src/tpl/raja index e827035c..80d218eb 160000 --- a/src/tpl/raja +++ b/src/tpl/raja @@ -1 +1 @@ -Subproject commit e827035c630e71a9358e2f21c2f3cf6fd5fb6605 +Subproject commit 80d218eba514a6d51bfd99ab6ebd6fbf83a74ca9 diff --git a/src/tpl/umpire b/src/tpl/umpire index 0372fbd6..5639f6c1 160000 --- a/src/tpl/umpire +++ b/src/tpl/umpire @@ -1 +1 @@ -Subproject commit 0372fbd6e1f17d7e6dd72693f8b857f3ec7559e9 +Subproject commit 5639f6c1fd4ca1fed7f0f1f48dcbbfbd00899484 diff --git a/src/util/forall.hpp b/src/util/forall.hpp index b0b60bdd..a609c2d2 100644 --- a/src/util/forall.hpp +++ b/src/util/forall.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 58c759df..aae3a3eb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,6 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## @@ -8,3 +8,7 @@ add_subdirectory(install) add_subdirectory(unit) add_subdirectory(integration) + +if(CHAI_ENABLE_EXPERIMENTAL) + add_subdirectory(expt) +endif() diff --git a/tests/expt/CMakeLists.txt b/tests/expt/CMakeLists.txt new file mode 100644 index 00000000..14b30afb --- /dev/null +++ b/tests/expt/CMakeLists.txt @@ -0,0 +1,139 @@ +############################################################################## +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +############################################################################## + +set(chai_expt_test_headers + TestHelpers.hpp) + +set(chai_expt_test_depends + chai + gtest) + +if(ENABLE_CUDA) + set(chai_expt_test_depends + ${chai_expt_test_depends} + cuda) +endif() + +if(ENABLE_HIP) + set(chai_expt_test_depends + ${chai_expt_test_depends} + blt::hip) +endif() + +blt_add_executable( + NAME ContextManagerTests + SOURCES ContextManagerTests.cpp + HEADERS ${chai_expt_test_headers} + INCLUDES ${PROJECT_BINARY_DIR}/include + DEPENDS_ON ${chai_expt_test_depends}) + +blt_add_test( + NAME ContextManagerTests + COMMAND ContextManagerTests) + +blt_add_executable( + NAME ContextGuardTests + SOURCES ContextGuardTests.cpp + HEADERS ${chai_expt_test_headers} + INCLUDES ${PROJECT_BINARY_DIR}/include + DEPENDS_ON ${chai_expt_test_depends}) + +blt_add_test( + NAME ContextGuardTests + COMMAND ContextGuardTests) + +if(CHAI_ENABLE_EXPERIMENTAL_RAJA_PLUGIN) + blt_add_executable( + NAME ContextRAJAPluginTests + SOURCES ContextRAJAPluginTests.cpp + HEADERS ${chai_expt_test_headers} + INCLUDES ${PROJECT_BINARY_DIR}/include + DEPENDS_ON ${chai_expt_test_depends}) + + blt_add_test( + NAME ContextRAJAPluginTests + COMMAND ContextRAJAPluginTests) +endif() + +blt_add_executable( + NAME ManagedArrayPointerTests + SOURCES ManagedArrayPointerTests.cpp + HEADERS ${chai_expt_test_headers} + INCLUDES ${PROJECT_BINARY_DIR}/include + DEPENDS_ON ${chai_expt_test_depends}) + +blt_add_test( + NAME ManagedArrayPointerTests + COMMAND ManagedArrayPointerTests) + +blt_add_executable( + NAME ManagedArrayViewTests + SOURCES ManagedArrayViewTests.cpp + HEADERS ${chai_expt_test_headers} + INCLUDES ${PROJECT_BINARY_DIR}/include + DEPENDS_ON ${chai_expt_test_depends}) + +blt_add_test( + NAME ManagedArrayViewTests + COMMAND ManagedArrayViewTests) + +blt_add_executable( + NAME HostArrayPointerTests + SOURCES HostArrayPointerTests.cpp + HEADERS ${chai_expt_test_headers} + INCLUDES ${PROJECT_BINARY_DIR}/include + DEPENDS_ON ${chai_expt_test_depends}) + +blt_add_test( + NAME HostArrayPointerTests + COMMAND HostArrayPointerTests) + +blt_add_executable( + NAME HostArrayViewTests + SOURCES HostArrayViewTests.cpp + HEADERS ${chai_expt_test_headers} + INCLUDES ${PROJECT_BINARY_DIR}/include + DEPENDS_ON ${chai_expt_test_depends}) + +blt_add_test( + NAME HostArrayViewTests + COMMAND HostArrayViewTests) + +blt_add_executable( + NAME HostArraySharedPointerTests + SOURCES HostArraySharedPointerTests.cpp + HEADERS ${chai_expt_test_headers} + INCLUDES ${PROJECT_BINARY_DIR}/include + DEPENDS_ON ${chai_expt_test_depends}) + +blt_add_test( + NAME HostArraySharedPointerTests + COMMAND HostArraySharedPointerTests) + +if(ENABLE_CUDA OR ENABLE_HIP) + blt_add_executable( + NAME DualArrayManagerTests + SOURCES DualArrayManagerTests.cpp + HEADERS ${chai_expt_test_headers} + INCLUDES ${PROJECT_BINARY_DIR}/include + DEPENDS_ON ${chai_expt_test_depends}) + + blt_add_test( + NAME DualArrayManagerTests + COMMAND DualArrayManagerTests) + + blt_add_executable( + NAME UnifiedArrayManagerTests + SOURCES UnifiedArrayManagerTests.cpp + HEADERS ${chai_expt_test_headers} + INCLUDES ${PROJECT_BINARY_DIR}/include + DEPENDS_ON ${chai_expt_test_depends}) + + blt_add_test( + NAME UnifiedArrayManagerTests + COMMAND UnifiedArrayManagerTests) +endif() diff --git a/tests/expt/ContextGuardTests.cpp b/tests/expt/ContextGuardTests.cpp new file mode 100644 index 00000000..72eb2d74 --- /dev/null +++ b/tests/expt/ContextGuardTests.cpp @@ -0,0 +1,39 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#include "chai/expt/ContextGuard.hpp" +#include "gtest/gtest.h" + +// Test that ContextGuard updates the current context in scope +// and restores the previous context on destruction. +TEST(ContextGuard, HOST) { + ::chai::expt::ContextManager& contextManager = ::chai::expt::ContextManager::getInstance(); + ::chai::expt::Context context = contextManager.getContext(); + + { + ::chai::expt::Context tempContext = ::chai::expt::Context::HOST; + ::chai::expt::ContextGuard contextGuard(tempContext); + EXPECT_EQ(contextManager.getContext(), tempContext); + } + + EXPECT_EQ(contextManager.getContext(), context); +} + +// Test that ContextGuard updates the current context in scope +// and restores the previous context on destruction. +TEST(ContextGuard, DEVICE) { + ::chai::expt::ContextManager& contextManager = ::chai::expt::ContextManager::getInstance(); + ::chai::expt::Context context = contextManager.getContext(); + + { + ::chai::expt::Context tempContext = ::chai::expt::Context::DEVICE; + ::chai::expt::ContextGuard contextGuard(tempContext); + EXPECT_EQ(contextManager.getContext(), tempContext); + } + + EXPECT_EQ(contextManager.getContext(), context); +} diff --git a/tests/expt/ContextManagerTests.cpp b/tests/expt/ContextManagerTests.cpp new file mode 100644 index 00000000..1e7b3233 --- /dev/null +++ b/tests/expt/ContextManagerTests.cpp @@ -0,0 +1,45 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#include "chai/config.hpp" +#include "chai/expt/ContextManager.hpp" +#include "gtest/gtest.h" + +// Test that getInstance returns the same object at the same place in memory +TEST(ContextManager, SingletonInstance) { + ::chai::expt::ContextManager& contextManager1 = ::chai::expt::ContextManager::getInstance(); + ::chai::expt::ContextManager& contextManager2 = ::chai::expt::ContextManager::getInstance(); + EXPECT_EQ(&contextManager1, &contextManager2); +} + +// Test that the default context is NONE +TEST(ContextManager, DefaultContext) { + ::chai::expt::ContextManager& contextManager = ::chai::expt::ContextManager::getInstance(); + EXPECT_EQ(contextManager.getContext(), ::chai::expt::Context::NONE); +} + +// Test setting the HOST context +TEST(ContextManager, HOST) { + ::chai::expt::ContextManager& contextManager = ::chai::expt::ContextManager::getInstance(); + ::chai::expt::Context context = ::chai::expt::Context::HOST; + contextManager.setContext(context); + EXPECT_EQ(contextManager.getContext(), context); + EXPECT_EQ(contextManager.isSynchronized(context), true); + contextManager.setContext(::chai::expt::Context::NONE); +} + +// Test setting the DEVICE context +TEST(ContextManager, DEVICE) { + ::chai::expt::ContextManager& contextManager = ::chai::expt::ContextManager::getInstance(); + ::chai::expt::Context context = ::chai::expt::Context::DEVICE; + contextManager.setContext(context); + EXPECT_EQ(contextManager.getContext(), context); + EXPECT_EQ(contextManager.isSynchronized(context), false); + contextManager.setDeviceSynchronized(true); + EXPECT_EQ(contextManager.isSynchronized(context), true); + contextManager.setContext(::chai::expt::Context::NONE); +} diff --git a/tests/expt/ContextRAJAPluginTests.cpp b/tests/expt/ContextRAJAPluginTests.cpp new file mode 100644 index 00000000..04e8a319 --- /dev/null +++ b/tests/expt/ContextRAJAPluginTests.cpp @@ -0,0 +1,119 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#include "chai/config.hpp" +#include "chai/ChaiMacros.hpp" +#include "chai/expt/Context.hpp" +#include "chai/expt/ContextManager.hpp" +#include "chai/expt/ContextRAJAPlugin.hpp" +#include "RAJA/RAJA.hpp" +#include "gtest/gtest.h" +#include "TestHelpers.hpp" + +// Pre-main registration of plugin with RAJA +static ::RAJA::util::PluginRegistry::add<::chai::expt::ContextRAJAPlugin> P( + "CHAIContextPlugin", + "Plugin that integrates CHAI context management with RAJA."); + +/*! + * \brief Tests whether the plugin was actually called. + */ +class ContextRAJAPluginTester { + public: + /*! + * @brief Construct a tester with an initial context of NONE. + */ + ContextRAJAPluginTester() = default; + + /*! + * @brief Copy-construct and capture the current ContextManager context. + */ + CHAI_HOST_DEVICE ContextRAJAPluginTester(const ContextRAJAPluginTester& other) + : m_context{other.m_context} + { +#if !defined(CHAI_DEVICE_COMPILE) + ::chai::expt::Context context = ::chai::expt::ContextManager::getInstance().getContext(); + + if (context != ::chai::expt::Context::NONE) { + m_context = context; + } +#endif + } + + /*! + * @brief Get the stored context. + * + * @return The stored ::chai::expt::Context value. + */ + CHAI_HOST_DEVICE ::chai::expt::Context getContext() const { + return m_context; + } + + private: + /*! + * @brief Stored context value. + */ + ::chai::expt::Context m_context{::chai::expt::Context::NONE}; +}; + +// Test that the tester object got the updated context and that the current context +// is NONE inside the loop. +TEST(ContextRAJAPlugin, HOST) { + ContextRAJAPluginTester tester{}; + EXPECT_EQ(tester.getContext(), ::chai::expt::Context::NONE); + + ::RAJA::forall<::RAJA::seq_exec>(::RAJA::TypedRangeSegment(0, 1), [=] (int) { + EXPECT_EQ(tester.getContext(), ::chai::expt::Context::HOST); + EXPECT_EQ(::chai::expt::ContextManager::getInstance().getContext(), ::chai::expt::Context::NONE); + }); + + EXPECT_EQ(tester.getContext(), ::chai::expt::Context::NONE); +} + +#if defined(CHAI_ENABLE_CUDA) +// Test that the tester object got the updated context. +CUDA_TEST(ContextRAJAPlugin, CUDA) { + ContextRAJAPluginTester tester{}; + EXPECT_EQ(tester.getContext(), ::chai::expt::Context::NONE); + + ::chai::expt::Context* result = nullptr; + CAMP_CUDA_API_INVOKE_AND_CHECK(cudaMallocManaged, (void**)&result, sizeof(::chai::expt::Context)); + + ::RAJA::forall<::RAJA::cuda_exec_async<256>>(::RAJA::TypedRangeSegment(0, 1), [=] __device__ (int) { + *result = tester.getContext(); + }); + + CAMP_CUDA_API_INVOKE_AND_CHECK(cudaDeviceSynchronize); + + EXPECT_EQ(*result, ::chai::expt::Context::DEVICE); + EXPECT_EQ(tester.getContext(), ::chai::expt::Context::NONE); + + CAMP_CUDA_API_INVOKE_AND_CHECK(cudaFree, (void*) result); +} +#endif + +#if defined(CHAI_ENABLE_HIP) +// Test that the tester object got the updated context. +TEST(ContextRAJAPlugin, HIP) { + ContextRAJAPluginTester tester{}; + EXPECT_EQ(tester.getContext(), ::chai::expt::Context::NONE); + + ::chai::expt::Context* result = nullptr; + CAMP_HIP_API_INVOKE_AND_CHECK(hipMallocManaged, (void**)&result, sizeof(::chai::expt::Context)); + + ::RAJA::forall<::RAJA::hip_exec_async<256>>(::RAJA::TypedRangeSegment(0, 1), [=] __device__ (int) { + *result = tester.getContext(); + }); + + CAMP_HIP_API_INVOKE_AND_CHECK(hipDeviceSynchronize); + + EXPECT_EQ(*result, ::chai::expt::Context::DEVICE); + EXPECT_EQ(tester.getContext(), ::chai::expt::Context::NONE); + + CAMP_HIP_API_INVOKE_AND_CHECK(hipFree, (void*) result); +} +#endif diff --git a/tests/expt/DualArrayManagerTests.cpp b/tests/expt/DualArrayManagerTests.cpp new file mode 100644 index 00000000..018caf9d --- /dev/null +++ b/tests/expt/DualArrayManagerTests.cpp @@ -0,0 +1,574 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#include "chai/config.hpp" +#include "chai/expt/Context.hpp" +#include "chai/expt/ContextGuard.hpp" +#include "chai/expt/ContextManager.hpp" +#include "chai/expt/DualArrayManager.hpp" +#include "camp/helpers.hpp" +#include "gtest/gtest.h" + +#include + +#if defined(CHAI_ENABLE_CUDA) +#include +#endif + +#if defined(CHAI_ENABLE_HIP) +#include +#endif + +namespace { + using ::chai::expt::Context; + using ::chai::expt::ContextGuard; + using ::chai::expt::ContextManager; + using ::chai::expt::DualArrayManager; + + template + T* malloc_managed(std::size_t count) + { + T* ptr = nullptr; + +#if defined(CHAI_ENABLE_CUDA) + CAMP_CUDA_API_INVOKE_AND_CHECK(cudaMallocManaged, (void**)&ptr, sizeof(T) * count); +#elif defined(CHAI_ENABLE_HIP) + CAMP_HIP_API_INVOKE_AND_CHECK(hipMallocManaged, (void**)&ptr, sizeof(T) * count); +#else + static_cast(count); +#endif + + return ptr; + } + + inline void free_managed(void* ptr) + { +#if defined(CHAI_ENABLE_CUDA) + CAMP_CUDA_API_INVOKE_AND_CHECK(cudaFree, ptr); +#elif defined(CHAI_ENABLE_HIP) + CAMP_HIP_API_INVOKE_AND_CHECK(hipFree, ptr); +#else + static_cast(ptr); +#endif + } + +#if defined(CHAI_ENABLE_CUDA) || defined(CHAI_ENABLE_HIP) + __global__ void increment_kernel(int* data, std::size_t size) + { + const std::size_t i = static_cast(blockIdx.x) * blockDim.x + threadIdx.x; + if (i < size) + { + data[i] += 1; + } + } + + __global__ void copy_kernel(const int* in, int* out, std::size_t size) + { + const std::size_t i = static_cast(blockIdx.x) * blockDim.x + threadIdx.x; + if (i < size) + { + out[i] = in[i]; + } + } + + inline void device_synchronize_raw() + { +#if defined(CHAI_ENABLE_CUDA) + CAMP_CUDA_API_INVOKE_AND_CHECK(cudaDeviceSynchronize); +#elif defined(CHAI_ENABLE_HIP) + CAMP_HIP_API_INVOKE_AND_CHECK(hipDeviceSynchronize); +#endif + } + + inline void launch_increment(int* data, std::size_t size) + { + constexpr int BLOCK_SIZE = 256; + const int grid_size = static_cast((size + BLOCK_SIZE - 1) / BLOCK_SIZE); + +#if defined(CHAI_ENABLE_CUDA) + increment_kernel<<>>(data, size); + CAMP_CUDA_API_INVOKE_AND_CHECK(cudaGetLastError); +#elif defined(CHAI_ENABLE_HIP) + hipLaunchKernelGGL(increment_kernel, + dim3(grid_size), + dim3(BLOCK_SIZE), + 0, + 0, + data, + size); + CAMP_HIP_API_INVOKE_AND_CHECK(hipGetLastError); +#endif + } + + inline void launch_copy(const int* in, int* out, std::size_t size) + { + constexpr int BLOCK_SIZE = 256; + const int grid_size = static_cast((size + BLOCK_SIZE - 1) / BLOCK_SIZE); + +#if defined(CHAI_ENABLE_CUDA) + copy_kernel<<>>(in, out, size); + CAMP_CUDA_API_INVOKE_AND_CHECK(cudaGetLastError); +#elif defined(CHAI_ENABLE_HIP) + hipLaunchKernelGGL(copy_kernel, + dim3(grid_size), + dim3(BLOCK_SIZE), + 0, + 0, + in, + out, + size); + CAMP_HIP_API_INVOKE_AND_CHECK(hipGetLastError); +#endif + } +#endif + + class DualArrayManagerTest : public ::testing::Test + { + protected: + void SetUp() override + { + ContextManager::getInstance().reset(); + } + + void TearDown() override + { + ContextManager::getInstance().reset(); + } + }; +} // namespace + +TEST_F(DualArrayManagerTest, DefaultConstructor) +{ + DualArrayManager manager{}; + EXPECT_EQ(manager.size(), 0); + + { + ContextGuard guard{Context::HOST}; + EXPECT_EQ(manager.data(false), nullptr); + EXPECT_EQ(manager.data(true), nullptr); + } +} + +TEST_F(DualArrayManagerTest, AllocatorConstructor) +{ + constexpr std::size_t N = 32; + auto& rm = ::umpire::ResourceManager::getInstance(); + umpire::Allocator host_allocator = rm.getAllocator("HOST"); + umpire::Allocator device_allocator = rm.getAllocator("DEVICE"); + + DualArrayManager manager{N, host_allocator, device_allocator}; + EXPECT_EQ(manager.size(), N); + + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(true); + ASSERT_NE(data, nullptr); + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], 0); + data[i] = static_cast(i * 2); + } + } + + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(false); + ASSERT_NE(data, nullptr); + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], static_cast(i * 2)); + } + } +} + +TEST_F(DualArrayManagerTest, ResizeToZero) +{ + DualArrayManager manager{10}; + EXPECT_EQ(manager.size(), 10); + + { + ContextGuard guard{Context::HOST}; + EXPECT_NE(manager.data(false), nullptr); + } + + manager.resize(0); + EXPECT_EQ(manager.size(), 0); + + { + ContextGuard guard{Context::HOST}; + EXPECT_EQ(manager.data(false), nullptr); + EXPECT_EQ(manager.data(true), nullptr); + } +} + +TEST_F(DualArrayManagerTest, ResizeSmaller) +{ + constexpr std::size_t N0 = 16; + constexpr std::size_t N1 = 6; + + DualArrayManager manager{N0}; + + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(true); + ASSERT_NE(data, nullptr); + for (std::size_t i = 0; i < N0; ++i) + { + data[i] = static_cast(i); + } + } + + manager.resize(N1); + EXPECT_EQ(manager.size(), N1); + + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(false); + ASSERT_NE(data, nullptr); + for (std::size_t i = 0; i < N1; ++i) + { + EXPECT_EQ(data[i], static_cast(i)); + } + } +} + +TEST_F(DualArrayManagerTest, ResizeLarger) +{ + constexpr std::size_t N0 = 8; + constexpr std::size_t N1 = 16; + + DualArrayManager manager{N0}; + + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(true); + ASSERT_NE(data, nullptr); + for (std::size_t i = 0; i < N0; ++i) + { + data[i] = static_cast(i + 10); + } + } + + manager.resize(N1); + EXPECT_EQ(manager.size(), N1); + + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(false); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N0; ++i) + { + EXPECT_EQ(data[i], static_cast(i + 10)); + } + + for (std::size_t i = N0; i < N1; ++i) + { + EXPECT_EQ(data[i], 0); + } + } +} + +TEST_F(DualArrayManagerTest, HostReadThenHostRead) +{ + // Set up + constexpr std::size_t N = 128; + DualArrayManager manager{N}; + + // Host read + { + ContextGuard guard{Context::HOST}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], 0); + } + } + + // Host read + { + ContextGuard guard{Context::HOST}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], 0); + } + } +} + +TEST_F(DualArrayManagerTest, HostWriteThenHostRead) +{ + // Set up + constexpr std::size_t N = 128; + DualArrayManager manager{N}; + + // Host write + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(true); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + data[i] = static_cast(i); + } + } + + // Host read + { + ContextGuard guard{Context::HOST}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], static_cast(i)); + } + } +} + +TEST_F(DualArrayManagerTest, HostReadThenDeviceRead) +{ + // Set up + constexpr std::size_t N = 256; + DualArrayManager manager{N}; + + // Host read + { + ContextGuard guard{Context::HOST}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], 0); + } + } + + // Set up + int* out = malloc_managed(N); + ASSERT_NE(out, nullptr); + + // Device read + { + ContextGuard guard{Context::DEVICE}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + launch_copy(data, out, N); + } + + // Synchronize + device_synchronize_raw(); + + // Check result + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(out[i], 0); + } + + // Clean up + free_managed(out); +} + +TEST_F(DualArrayManagerTest, HostWriteThenDeviceRead) +{ + // Set up + constexpr std::size_t N = 256; + DualArrayManager manager{N}; + + // Host write + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(true); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + data[i] = static_cast(i); + } + } + + // Set up + int* out = malloc_managed(N); + ASSERT_NE(out, nullptr); + + // Device read + { + ContextGuard guard{Context::DEVICE}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + launch_copy(data, out, N); + } + + // Synchronize + device_synchronize_raw(); + + // Check result + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(out[i], static_cast(i)); + } + + // Clean up + free_managed(out); +} + +TEST_F(DualArrayManagerTest, DeviceReadThenHostRead) +{ + // Set up + constexpr std::size_t N = 256; + DualArrayManager manager{N}; + + int* out = malloc_managed(N); + ASSERT_NE(out, nullptr); + + // Device read + { + ContextGuard guard{Context::DEVICE}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + launch_copy(data, out, N); + } + + // Host read + { + ContextGuard guard{Context::HOST}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], 0); + } + } + + // Synchronize + // Note: The host read should have caused a synchronize, but the following + // checks should independent of whether than part works. + device_synchronize_raw(); + + // Checks + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(out[i], 0); + } + + // Clean up + free_managed(out); +} + +TEST_F(DualArrayManagerTest, DeviceWriteThenHostRead) +{ + // Set up + constexpr std::size_t N = 256; + DualArrayManager manager{N}; + + // Device write + { + ContextGuard guard{Context::DEVICE}; + int* data = manager.data(true); + ASSERT_NE(data, nullptr); + launch_increment(data, N); + } + + // Host read + { + ContextGuard guard{Context::HOST}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], 1); + } + } +} + +TEST_F(DualArrayManagerTest, DeviceReadThenDeviceRead) +{ + // Set up + constexpr std::size_t N = 256; + DualArrayManager manager{N}; + + int* out0 = malloc_managed(N); + int* out1 = malloc_managed(N); + ASSERT_NE(out0, nullptr); + ASSERT_NE(out1, nullptr); + + // Device read + { + ContextGuard guard{Context::DEVICE}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + launch_copy(data, out0, N); + } + + // Device read + { + ContextGuard guard{Context::DEVICE}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + launch_copy(data, out1, N); + } + + // Synchronize + device_synchronize_raw(); + + // Checks + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(out0[i], 0); + EXPECT_EQ(out1[i], 0); + } + + // Clean up + free_managed(out0); + free_managed(out1); +} + +TEST_F(DualArrayManagerTest, DeviceWriteThenDeviceRead) +{ + // Set up + constexpr std::size_t N = 256; + DualArrayManager manager{N}; + + // Device write + { + ContextGuard guard{Context::DEVICE}; + int* data = manager.data(true); + ASSERT_NE(data, nullptr); + launch_increment(data, N); + } + + // Set up + int* out = malloc_managed(N); + ASSERT_NE(out, nullptr); + + // Device read + { + ContextGuard guard{Context::DEVICE}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + launch_copy(data, out, N); + } + + // Synchronize + device_synchronize_raw(); + + // Checks + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(out[i], 1); + } + + // Clean up + free_managed(out); +} diff --git a/tests/expt/HostArrayPointerTests.cpp b/tests/expt/HostArrayPointerTests.cpp new file mode 100644 index 00000000..51112cab --- /dev/null +++ b/tests/expt/HostArrayPointerTests.cpp @@ -0,0 +1,315 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#include "chai/expt/HostArrayManager.hpp" +#include "chai/expt/ManagedArrayPointer.hpp" +#include "gtest/gtest.h" +#include +#include + +template +using HostArrayManager = ::chai::expt::HostArrayManager; + +template +using HostArrayPointer = ::chai::expt::ManagedArrayPointer>; + +template +using ConstHostArrayPointer = ::chai::expt::ManagedArrayPointer>; + +TEST(HostArrayPointer, DefaultConstructor) { + HostArrayPointer a; + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); +} + +TEST(HostArrayPointer, ManagerDefaultConstructor) { + HostArrayPointer a{HostArrayManager()}; + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); + a.free(); +} + +TEST(HostArrayPointer, MakeManagerDefaultConstructor) { + HostArrayPointer a = HostArrayPointer::make(); + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); + a.free(); +} + +TEST(HostArrayPointer, ManagerSizeConstructor) { + const std::size_t N = 10; + HostArrayPointer a{HostArrayManager(N)}; + EXPECT_EQ(a.size(), N); + ASSERT_NE(a.data(), nullptr); + + // For memory checking tools, use the allocated array. + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } + + a.free(); +} + +TEST(HostArrayPointer, MakeManagerSizeConstructor) { + const std::size_t N = 10; + HostArrayPointer a = HostArrayPointer::make(N); + EXPECT_EQ(a.size(), N); + ASSERT_NE(a.data(), nullptr); + + // For memory checking tools, use the allocated array. + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } + + a.free(); +} + +/* + * Note: The copy constructor is shallow. + */ +TEST(HostArrayPointer, CopyConstructor) { + // Set up array a + const std::size_t N = 10; + HostArrayPointer a{HostArrayManager(N)}; + + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } + + // Copy construct b + HostArrayPointer b(a); + + // Check that a is unchanged + EXPECT_EQ(a.size(), N); + EXPECT_NE(a.data(), nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(a[i], i); + } + + // Check that b matches a + EXPECT_EQ(b.size(), a.size()); + EXPECT_EQ(b.data(), a.data()); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(b[i], i); + } + + // Check that the copy is shallow + for (std::size_t i = 0; i < N; ++i) + { + b[i] = -i; + EXPECT_EQ(a[i], -i); + } + + // Free memory + a.free(); +} + +TEST(HostArrayPointer, ConvertingConstructor) { + // Set up array a + const std::size_t N = 10; + HostArrayPointer a{HostArrayManager(N)}; + + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } + + // Use the converting constructor to construct b + ConstHostArrayPointer b(a); + + // Check that a is unchanged + EXPECT_EQ(a.size(), N); + EXPECT_NE(a.data(), nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(a[i], i); + } + + // Check that b matches a + EXPECT_EQ(b.size(), a.size()); + EXPECT_EQ(b.data(), a.data()); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(b[i], i); + } + + // Check that the copy is shallow + for (std::size_t i = 0; i < N; ++i) + { + a[i] = -i; + EXPECT_EQ(b[i], -i); + } + + // Free memory + a.free(); +} + +TEST(HostArrayPointer, CopyAssignmentOperator) { + HostArrayPointer a; + + const std::size_t N = 10; + a = HostArrayPointer(HostArrayManager(N)); + + EXPECT_EQ(a.size(), N); + EXPECT_NE(a.data(), nullptr); +} + +TEST(HostArrayPointer, ResizeAllocate) { + const std::size_t N = 10; + HostArrayPointer a; + a.resize(N); + + EXPECT_EQ(a.size(), N); + EXPECT_NE(a.data(), nullptr); + + // For memory checking tools, use the allocated array. + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } + + a.free(); +} + +TEST(HostArrayPointer, ResizeDeallocate) { + std::size_t N = 10; + HostArrayPointer a{HostArrayManager(N)}; + + N = 0; + a.resize(N); + + EXPECT_EQ(a.size(), N); + EXPECT_EQ(a.data(), nullptr); + + a.free(); +} + +TEST(HostArrayPointer, ResizeSmaller) { + const std::size_t old_size = 10; + HostArrayPointer a{HostArrayManager(old_size)}; + + for (std::size_t i = 0; i < old_size; ++i) + { + a[i] = i; + } + + const std::size_t new_size = 5; + a.resize(new_size); + + EXPECT_EQ(a.size(), new_size); + EXPECT_NE(a.data(), nullptr); + + for (std::size_t i = 0; i < new_size; ++i) + { + EXPECT_EQ(a[i], i); + } + + a.free(); +} + +TEST(HostArrayPointer, ResizeLarger) { + const std::size_t old_size = 5; + HostArrayPointer a{HostArrayManager(old_size)}; + + for (std::size_t i = 0; i < old_size; ++i) + { + a[i] = i; + } + + const std::size_t new_size = 10; + a.resize(new_size); + + EXPECT_EQ(a.size(), new_size); + EXPECT_NE(a.data(), nullptr); + + for (std::size_t i = 0; i < old_size; ++i) + { + EXPECT_EQ(a[i], i); + } + + a.free(); +} + +TEST(HostArrayPointer, Data) { + const std::size_t N = 10; + HostArrayPointer a{HostArrayManager(N)}; + + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } + + int* data = a.data(); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], i); + } + + a.free(); +} + +TEST(HostArrayPointer, Update) { + const std::size_t N = 10; + HostArrayPointer a{HostArrayManager(N)}; + a.update(); + + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } + + int* data = a.data(); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], i); + } + + a.free(); +} + +TEST(HostArrayPointer, Free) { + const std::size_t N = 10; + HostArrayPointer a{HostArrayManager(N)}; + a.free(); + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); +} + +TEST(HostArrayPointer, LambdaCapture) { + const std::size_t N = 10; + HostArrayPointer a{HostArrayManager(N)}; + + auto f = [=] (std::size_t i) + { + a[i] = i; + }; + + for (std::size_t i = 0; i < N; ++i) + { + f(i); + } + + int* data = a.data(); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], i); + } + + a.free(); +} diff --git a/tests/expt/HostArraySharedPointerTests.cpp b/tests/expt/HostArraySharedPointerTests.cpp new file mode 100644 index 00000000..5859bc87 --- /dev/null +++ b/tests/expt/HostArraySharedPointerTests.cpp @@ -0,0 +1,281 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#include "chai/expt/HostArrayManager.hpp" +#include "chai/expt/ManagedArraySharedPointer.hpp" +#include "gtest/gtest.h" +#include +#include + +template +using HostArrayManager = ::chai::expt::HostArrayManager; + +template +using HostArraySharedPointer = ::chai::expt::ManagedArraySharedPointer>; + +template +using ConstHostArraySharedPointer = ::chai::expt::ManagedArraySharedPointer>; + +TEST(HostArraySharedPointer, DefaultConstructor) { + HostArraySharedPointer a; + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); +} + +TEST(HostArraySharedPointer, ManagerDefaultConstructor) { + HostArraySharedPointer a{HostArrayManager()}; + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); +} + +TEST(HostArraySharedPointer, MakeManagerDefaultConstructor) { + HostArraySharedPointer a = HostArraySharedPointer::make(); + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); +} + +TEST(HostArraySharedPointer, ManagerSizeConstructor) { + const std::size_t N = 10; + HostArraySharedPointer a{HostArrayManager(N)}; + EXPECT_EQ(a.size(), N); + ASSERT_NE(a.data(), nullptr); + + // For memory checking tools, use the allocated array. + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } +} + +TEST(HostArraySharedPointer, MakeManagerSizeConstructor) { + const std::size_t N = 10; + HostArraySharedPointer a = HostArraySharedPointer::make(N); + EXPECT_EQ(a.size(), N); + ASSERT_NE(a.data(), nullptr); + + // For memory checking tools, use the allocated array. + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } +} + +/* + * Note: The copy constructor is shallow. + */ +TEST(HostArraySharedPointer, CopyConstructor) { + // Set up array a + const std::size_t N = 10; + HostArraySharedPointer a{HostArrayManager(N)}; + + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } + + // Copy construct b + HostArraySharedPointer b(a); + + // Check that a is unchanged + EXPECT_EQ(a.size(), N); + EXPECT_NE(a.data(), nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(a[i], i); + } + + // Check that b matches a + EXPECT_EQ(b.size(), a.size()); + EXPECT_EQ(b.data(), a.data()); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(b[i], i); + } + + // Check that the copy is shallow + for (std::size_t i = 0; i < N; ++i) + { + b[i] = -i; + EXPECT_EQ(a[i], -i); + } +} + +TEST(HostArraySharedPointer, ConvertingConstructor) { + // Set up array a + const std::size_t N = 10; + HostArraySharedPointer a{HostArrayManager(N)}; + + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } + + // Use the converting constructor to construct b + ConstHostArraySharedPointer b(a); + + // Check that a is unchanged + EXPECT_EQ(a.size(), N); + EXPECT_NE(a.data(), nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(a[i], i); + } + + // Check that b matches a + EXPECT_EQ(b.size(), a.size()); + EXPECT_EQ(b.data(), a.data()); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(b[i], i); + } + + // Check that the copy is shallow + for (std::size_t i = 0; i < N; ++i) + { + a[i] = -i; + EXPECT_EQ(b[i], -i); + } +} + +TEST(HostArraySharedPointer, CopyAssignmentOperator) { + HostArraySharedPointer a; + + const std::size_t N = 10; + a = HostArraySharedPointer(HostArrayManager(N)); + + EXPECT_EQ(a.size(), N); + EXPECT_NE(a.data(), nullptr); +} + +TEST(HostArraySharedPointer, ResizeAllocate) { + const std::size_t N = 10; + HostArraySharedPointer a; + a.resize(N); + + EXPECT_EQ(a.size(), N); + EXPECT_NE(a.data(), nullptr); + + // For memory checking tools, use the allocated array. + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } +} + +TEST(HostArraySharedPointer, ResizeDeallocate) { + std::size_t N = 10; + HostArraySharedPointer a{HostArrayManager(N)}; + + N = 0; + a.resize(N); + + EXPECT_EQ(a.size(), N); + EXPECT_EQ(a.data(), nullptr); +} + +TEST(HostArraySharedPointer, ResizeSmaller) { + const std::size_t old_size = 10; + HostArraySharedPointer a{HostArrayManager(old_size)}; + + for (std::size_t i = 0; i < old_size; ++i) + { + a[i] = i; + } + + const std::size_t new_size = 5; + a.resize(new_size); + + EXPECT_EQ(a.size(), new_size); + EXPECT_NE(a.data(), nullptr); + + for (std::size_t i = 0; i < new_size; ++i) + { + EXPECT_EQ(a[i], i); + } +} + +TEST(HostArraySharedPointer, ResizeLarger) { + const std::size_t old_size = 5; + HostArraySharedPointer a{HostArrayManager(old_size)}; + + for (std::size_t i = 0; i < old_size; ++i) + { + a[i] = i; + } + + const std::size_t new_size = 10; + a.resize(new_size); + + EXPECT_EQ(a.size(), new_size); + EXPECT_NE(a.data(), nullptr); + + for (std::size_t i = 0; i < old_size; ++i) + { + EXPECT_EQ(a[i], i); + } +} + +TEST(HostArraySharedPointer, Data) { + const std::size_t N = 10; + HostArraySharedPointer a{HostArrayManager(N)}; + + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } + + int* data = a.data(); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], i); + } +} + +TEST(HostArraySharedPointer, Update) { + const std::size_t N = 10; + HostArraySharedPointer a{HostArrayManager(N)}; + a.update(); + + for (std::size_t i = 0; i < N; ++i) + { + a[i] = i; + } + + int* data = a.data(); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], i); + } +} + +TEST(HostArraySharedPointer, LambdaCapture) { + const std::size_t N = 10; + HostArraySharedPointer a{HostArrayManager(N)}; + + auto f = [=] (std::size_t i) + { + a[i] = i; + }; + + for (std::size_t i = 0; i < N; ++i) + { + f(i); + } + + int* data = a.data(); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], i); + } +} diff --git a/tests/expt/HostArrayViewTests.cpp b/tests/expt/HostArrayViewTests.cpp new file mode 100644 index 00000000..c7e77031 --- /dev/null +++ b/tests/expt/HostArrayViewTests.cpp @@ -0,0 +1,179 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#include "chai/expt/HostArrayManager.hpp" +#include "chai/expt/ManagedArrayView.hpp" +#include "gtest/gtest.h" + +#include + +template +using HostArrayManager = ::chai::expt::HostArrayManager; + +template +using HostArrayView = ::chai::expt::ManagedArrayView>; + +template +using ConstHostArrayView = ::chai::expt::ManagedArrayView>; + +TEST(HostArrayView, DefaultConstructor) { + HostArrayView a; + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); +} + +TEST(HostArrayView, ManagerDefaultConstructor) { + HostArrayManager manager; + HostArrayView a{manager}; + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); +} + +TEST(HostArrayView, ManagerSizeConstructor) { + const std::size_t N = 10; + HostArrayManager manager{N}; + HostArrayView a{manager}; + EXPECT_EQ(a.size(), N); + ASSERT_NE(a.data(), nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + a[i] = static_cast(i); + } +} + +TEST(HostArrayView, CopyConstructor) { + const std::size_t N = 10; + HostArrayManager manager{N}; + HostArrayView a{manager}; + + for (std::size_t i = 0; i < N; ++i) + { + a[i] = static_cast(i); + } + + HostArrayView b(a); + + EXPECT_EQ(b.size(), a.size()); + EXPECT_EQ(b.data(), a.data()); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(b[i], static_cast(i)); + } + + for (std::size_t i = 0; i < N; ++i) + { + b[i] = -static_cast(i); + EXPECT_EQ(a[i], -static_cast(i)); + } +} + +TEST(HostArrayView, ConvertingConstructor) { + const std::size_t N = 10; + HostArrayManager manager{N}; + HostArrayView a{manager}; + + for (std::size_t i = 0; i < N; ++i) + { + a[i] = static_cast(i); + } + + ConstHostArrayView b(a); + + EXPECT_EQ(b.size(), a.size()); + EXPECT_EQ(b.data(), a.data()); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(b[i], static_cast(i)); + } +} + +TEST(HostArrayView, CopyAssignmentOperator) { + HostArrayView a; + + const std::size_t N = 10; + HostArrayManager manager{N}; + a = HostArrayView(manager); + + EXPECT_EQ(a.size(), N); + EXPECT_NE(a.data(), nullptr); +} + +TEST(HostArrayView, Data) { + const std::size_t N = 10; + HostArrayManager manager{N}; + HostArrayView a{manager}; + + for (std::size_t i = 0; i < N; ++i) + { + a[i] = static_cast(i); + } + + int* data = a.data(); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], static_cast(i)); + } +} + +TEST(HostArrayView, Update) { + const std::size_t N = 10; + HostArrayManager manager{N}; + HostArrayView a{manager}; + a.update(); + + for (std::size_t i = 0; i < N; ++i) + { + a[i] = static_cast(i); + } + + int* data = a.data(); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], static_cast(i)); + } +} + +TEST(HostArrayView, ReflectsManagerResizeAfterUpdate) { + HostArrayManager manager{4}; + HostArrayView a{manager}; + + EXPECT_EQ(a.size(), 4); + + manager.resize(7); + a.update(); + + EXPECT_EQ(a.size(), 7); + EXPECT_EQ(a.data(), manager.data()); +} + +TEST(HostArrayView, LambdaCapture) { + const std::size_t N = 10; + HostArrayManager manager{N}; + HostArrayView a{manager}; + + auto f = [=] (std::size_t i) + { + a[i] = static_cast(i); + }; + + for (std::size_t i = 0; i < N; ++i) + { + f(i); + } + + int* data = a.data(); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], static_cast(i)); + } +} diff --git a/tests/expt/ManagedArrayPointerTests.cpp b/tests/expt/ManagedArrayPointerTests.cpp new file mode 100644 index 00000000..f77751d7 --- /dev/null +++ b/tests/expt/ManagedArrayPointerTests.cpp @@ -0,0 +1,156 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#include "chai/expt/ManagedArrayPointer.hpp" +#include "gtest/gtest.h" + +#include +#include + +namespace { + /** + * Minimal "ManagerType" for exercising ManagedArrayPointer in unit tests. + * + * Requirements satisfied (as used by ManagedArrayPointer): + * - void resize(std::size_t) + * - std::size_t size() const + * - ElementType* data() + * + * Owns storage on host via std::realloc. + */ + template + class TestArrayManager + { + public: + TestArrayManager() = default; + + void resize(std::size_t size) + { + m_size = size; + m_data = static_cast(std::realloc(m_data, size*sizeof(ElementType))); + } + + std::size_t size() const + { + return m_size; + } + + ElementType* data() + { + return m_data; + } + + private: + std::size_t m_size{0}; + ElementType* m_data{nullptr}; + }; // class TestArrayManager +} // anonymous namespace + +template +using TestArrayPointer = ::chai::expt::ManagedArrayPointer>; + +template +using ConstTestArrayPointer = ::chai::expt::ManagedArrayPointer>; + +TEST(ManagedArrayPointer, DefaultConstructor) { + TestArrayPointer a; + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); +} + +TEST(ManagedArrayPointer, ManagerConstructor) { + TestArrayPointer a{TestArrayManager{}}; + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); + a.free(); +} + +TEST(ManagedArrayPointer, MakeManagerConstructor) { + TestArrayPointer a = TestArrayPointer::make(); + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); + a.free(); +} + +TEST(ManagedArrayPointer, CopyConstructor) { + TestArrayPointer a{TestArrayManager()}; + TestArrayPointer b(a); + EXPECT_EQ(b.size(), 0); + EXPECT_EQ(b.data(), nullptr); + b.free(); +} + +TEST(ManagedArrayPointer, ConvertingConstructor) { + TestArrayPointer a{TestArrayManager()}; + ConstTestArrayPointer b(a); + EXPECT_EQ(b.size(), 0); + EXPECT_EQ(b.data(), nullptr); + b.free(); +} + +TEST(ManagedArrayPointer, CopyAssignmentOperator) { + TestArrayPointer a; + a = TestArrayPointer(TestArrayManager()); + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); + a.free(); +} + +TEST(ManagedArrayPointer, Resize) { + const std::size_t n = 10; + TestArrayPointer a; + a.resize(n); + EXPECT_EQ(a.size(), n); + EXPECT_NE(a.data(), nullptr); + a.free(); +} + +TEST(ManagedArrayPointer, Data) { + const std::size_t n = 10; + TestArrayPointer a; + a.resize(n); + a.update(); + + for (std::size_t i = 0; i < n; ++i) + { + a[i] = i; + } + + int* data = a.data(); + + for (std::size_t i = 0; i < n; ++i) + { + EXPECT_EQ(data[i], i); + } + + a.free(); +} + +TEST(ManagedArrayPointer, LambdaCapture) { + const std::size_t n = 10; + TestArrayPointer a; + a.resize(n); + + auto f = [=] (std::size_t i) + { + a[i] = i; + }; + + for (std::size_t i = 0; i < n; ++i) + { + f(i); + } + + int* data = a.data(); + + for (std::size_t i = 0; i < n; ++i) + { + EXPECT_EQ(data[i], i); + } + + a.free(); +} diff --git a/tests/expt/ManagedArrayViewTests.cpp b/tests/expt/ManagedArrayViewTests.cpp new file mode 100644 index 00000000..838c43f2 --- /dev/null +++ b/tests/expt/ManagedArrayViewTests.cpp @@ -0,0 +1,159 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#include "chai/expt/ManagedArrayView.hpp" +#include "gtest/gtest.h" + +#include +#include + +namespace { + /** + * Minimal "ManagerType" for exercising ManagedArrayView in unit tests. + * + * Requirements satisfied (as used by ManagedArrayView): + * - std::size_t size() const + * - ElementType* data() + * + * Owns storage on host via std::realloc. + */ + template + class TestArrayManager + { + public: + TestArrayManager() = default; + + explicit TestArrayManager(std::size_t size) + { + m_size = size; + m_data = static_cast(std::realloc(m_data, size*sizeof(ElementType))); + } + + ~TestArrayManager() + { + std::free(m_data); + } + + void resize(std::size_t size) + { + m_size = size; + m_data = static_cast(std::realloc(m_data, size*sizeof(ElementType))); + } + + std::size_t size() const + { + return m_size; + } + + ElementType* data() + { + return m_data; + } + + private: + std::size_t m_size{0}; + ElementType* m_data{nullptr}; + }; // class TestArrayManager +} // anonymous namespace + +template +using TestArrayView = ::chai::expt::ManagedArrayView>; + +template +using ConstTestArrayView = ::chai::expt::ManagedArrayView>; + +TEST(ManagedArrayView, DefaultConstructor) { + TestArrayView a; + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); +} + +TEST(ManagedArrayView, ManagerConstructor) { + TestArrayManager manager; + TestArrayView a{manager}; + EXPECT_EQ(a.size(), 0); + EXPECT_EQ(a.data(), nullptr); +} + +TEST(ManagedArrayView, CopyConstructor) { + TestArrayManager manager{10}; + TestArrayView a{manager}; + TestArrayView b(a); + EXPECT_EQ(b.size(), a.size()); + EXPECT_EQ(b.data(), a.data()); +} + +TEST(ManagedArrayView, ConvertingConstructor) { + TestArrayManager manager{10}; + TestArrayView a{manager}; + ConstTestArrayView b(a); + EXPECT_EQ(b.size(), a.size()); + EXPECT_EQ(b.data(), a.data()); +} + +TEST(ManagedArrayView, CopyAssignmentOperator) { + TestArrayView a; + TestArrayManager manager{10}; + a = TestArrayView(manager); + EXPECT_EQ(a.size(), 10); + EXPECT_NE(a.data(), nullptr); +} + +TEST(ManagedArrayView, Data) { + const std::size_t n = 10; + TestArrayManager manager{n}; + TestArrayView a{manager}; + a.update(); + + for (std::size_t i = 0; i < n; ++i) + { + a[i] = static_cast(i); + } + + int* data = a.data(); + + for (std::size_t i = 0; i < n; ++i) + { + EXPECT_EQ(data[i], static_cast(i)); + } +} + +TEST(ManagedArrayView, LambdaCapture) { + const std::size_t n = 10; + TestArrayManager manager{n}; + TestArrayView a{manager}; + + auto f = [=] (std::size_t i) + { + a[i] = static_cast(i); + }; + + for (std::size_t i = 0; i < n; ++i) + { + f(i); + } + + int* data = a.data(); + + for (std::size_t i = 0; i < n; ++i) + { + EXPECT_EQ(data[i], static_cast(i)); + } +} + +TEST(ManagedArrayView, ReflectsManagerResizeAfterUpdate) { + TestArrayManager manager{4}; + TestArrayView a{manager}; + + EXPECT_EQ(a.size(), 4); + + manager.resize(7); + a.update(); + + EXPECT_EQ(a.size(), 7); + EXPECT_EQ(a.data(), manager.data()); +} diff --git a/tests/expt/TestHelpers.hpp b/tests/expt/TestHelpers.hpp new file mode 100644 index 00000000..5ff0b392 --- /dev/null +++ b/tests/expt/TestHelpers.hpp @@ -0,0 +1,16 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#ifndef CHAI_TEST_HELPERS_HPP +#define CHAI_TEST_HELPERS_HPP + +#define CUDA_TEST(X, Y) \ + static void cuda_test_##X##Y(); \ + TEST(X, Y) { cuda_test_##X##Y(); } \ + static void cuda_test_##X##Y() + +#endif // CHAI_TEST_HELPERS_HPP diff --git a/tests/expt/UnifiedArrayManagerTests.cpp b/tests/expt/UnifiedArrayManagerTests.cpp new file mode 100644 index 00000000..8ae96399 --- /dev/null +++ b/tests/expt/UnifiedArrayManagerTests.cpp @@ -0,0 +1,574 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. +// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// + +#include "chai/config.hpp" +#include "chai/expt/Context.hpp" +#include "chai/expt/ContextGuard.hpp" +#include "chai/expt/ContextManager.hpp" +#include "chai/expt/UnifiedArrayManager.hpp" +#include "camp/helpers.hpp" +#include "gtest/gtest.h" + +#include + +#if defined(CHAI_ENABLE_CUDA) +#include +#endif + +#if defined(CHAI_ENABLE_HIP) +#include +#endif + +namespace { + using ::chai::expt::Context; + using ::chai::expt::ContextGuard; + using ::chai::expt::ContextManager; + using ::chai::expt::UnifiedArrayManager; + + template + T* malloc_managed(std::size_t count) + { + T* ptr = nullptr; + +#if defined(CHAI_ENABLE_CUDA) + CAMP_CUDA_API_INVOKE_AND_CHECK(cudaMallocManaged, (void**)&ptr, sizeof(T) * count); +#elif defined(CHAI_ENABLE_HIP) + CAMP_HIP_API_INVOKE_AND_CHECK(hipMallocManaged, (void**)&ptr, sizeof(T) * count); +#else + static_cast(count); +#endif + + return ptr; + } + + inline void free_managed(void* ptr) + { +#if defined(CHAI_ENABLE_CUDA) + CAMP_CUDA_API_INVOKE_AND_CHECK(cudaFree, ptr); +#elif defined(CHAI_ENABLE_HIP) + CAMP_HIP_API_INVOKE_AND_CHECK(hipFree, ptr); +#else + static_cast(ptr); +#endif + } + +#if defined(CHAI_ENABLE_CUDA) || defined(CHAI_ENABLE_HIP) + __global__ void increment_kernel(int* data, std::size_t size) + { + const std::size_t i = static_cast(blockIdx.x) * blockDim.x + threadIdx.x; + if (i < size) + { + data[i] += 1; + } + } + + __global__ void copy_kernel(const int* in, int* out, std::size_t size) + { + const std::size_t i = static_cast(blockIdx.x) * blockDim.x + threadIdx.x; + if (i < size) + { + out[i] = in[i]; + } + } + + inline void device_synchronize_raw() + { +#if defined(CHAI_ENABLE_CUDA) + CAMP_CUDA_API_INVOKE_AND_CHECK(cudaDeviceSynchronize); +#elif defined(CHAI_ENABLE_HIP) + CAMP_HIP_API_INVOKE_AND_CHECK(hipDeviceSynchronize); +#endif + } + + inline void launch_increment(int* data, std::size_t size) + { + constexpr int BLOCK_SIZE = 256; + const int grid_size = static_cast((size + BLOCK_SIZE - 1) / BLOCK_SIZE); + +#if defined(CHAI_ENABLE_CUDA) + increment_kernel<<>>(data, size); + CAMP_CUDA_API_INVOKE_AND_CHECK(cudaGetLastError); +#elif defined(CHAI_ENABLE_HIP) + hipLaunchKernelGGL(increment_kernel, + dim3(grid_size), + dim3(BLOCK_SIZE), + 0, + 0, + data, + size); + CAMP_HIP_API_INVOKE_AND_CHECK(hipGetLastError); +#endif + } + + inline void launch_copy(const int* in, int* out, std::size_t size) + { + constexpr int BLOCK_SIZE = 256; + const int grid_size = static_cast((size + BLOCK_SIZE - 1) / BLOCK_SIZE); + +#if defined(CHAI_ENABLE_CUDA) + copy_kernel<<>>(in, out, size); + CAMP_CUDA_API_INVOKE_AND_CHECK(cudaGetLastError); +#elif defined(CHAI_ENABLE_HIP) + hipLaunchKernelGGL(copy_kernel, + dim3(grid_size), + dim3(BLOCK_SIZE), + 0, + 0, + in, + out, + size); + CAMP_HIP_API_INVOKE_AND_CHECK(hipGetLastError); +#endif + } +#endif + + class UnifiedArrayManagerTest : public ::testing::Test + { + protected: + void SetUp() override + { + ContextManager::getInstance().reset(); + } + + void TearDown() override + { + ContextManager::getInstance().reset(); + } + }; +} // namespace + +TEST_F(UnifiedArrayManagerTest, DefaultConstructor) +{ + UnifiedArrayManager manager{}; + EXPECT_EQ(manager.size(), 0); + + { + ContextGuard guard{Context::HOST}; + EXPECT_EQ(manager.data(false), nullptr); + EXPECT_EQ(manager.data(true), nullptr); + } +} + +TEST_F(UnifiedArrayManagerTest, AllocatorConstructor) +{ + constexpr std::size_t N = 32; + auto& rm = ::umpire::ResourceManager::getInstance(); + umpire::Allocator allocator = rm.getAllocator("UM"); + + UnifiedArrayManager manager{N, allocator}; + EXPECT_EQ(manager.size(), N); + + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(true); + ASSERT_NE(data, nullptr); + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], 0); + data[i] = static_cast(i * 2); + } + } + + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(false); + ASSERT_NE(data, nullptr); + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], static_cast(i * 2)); + } + } +} + +TEST_F(UnifiedArrayManagerTest, ResizeToZero) +{ + UnifiedArrayManager manager{10}; + EXPECT_EQ(manager.size(), 10); + + { + ContextGuard guard{Context::HOST}; + EXPECT_NE(manager.data(false), nullptr); + } + + manager.resize(0); + EXPECT_EQ(manager.size(), 0); + + { + ContextGuard guard{Context::HOST}; + EXPECT_EQ(manager.data(false), nullptr); + EXPECT_EQ(manager.data(true), nullptr); + } +} + +TEST_F(UnifiedArrayManagerTest, ResizeSmaller) +{ + constexpr std::size_t N0 = 16; + constexpr std::size_t N1 = 6; + + UnifiedArrayManager manager{N0}; + + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(true); + ASSERT_NE(data, nullptr); + for (std::size_t i = 0; i < N0; ++i) + { + data[i] = static_cast(i); + } + } + + manager.resize(N1); + EXPECT_EQ(manager.size(), N1); + + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(false); + ASSERT_NE(data, nullptr); + for (std::size_t i = 0; i < N1; ++i) + { + EXPECT_EQ(data[i], static_cast(i)); + } + } +} + +TEST_F(UnifiedArrayManagerTest, ResizeLarger) +{ + constexpr std::size_t N0 = 8; + constexpr std::size_t N1 = 16; + + UnifiedArrayManager manager{N0}; + + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(true); + ASSERT_NE(data, nullptr); + for (std::size_t i = 0; i < N0; ++i) + { + data[i] = static_cast(i + 10); + } + } + + manager.resize(N1); + EXPECT_EQ(manager.size(), N1); + + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(false); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N0; ++i) + { + EXPECT_EQ(data[i], static_cast(i + 10)); + } + + for (std::size_t i = N0; i < N1; ++i) + { + EXPECT_EQ(data[i], 0); + } + } +} + +TEST_F(UnifiedArrayManagerTest, HostReadThenHostRead) +{ + // Set up + constexpr std::size_t N = 128; + UnifiedArrayManager manager{N}; + + // Host read + { + ContextGuard guard{Context::HOST}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], 0); + } + } + + // Host read + { + ContextGuard guard{Context::HOST}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], 0); + } + } +} + +TEST_F(UnifiedArrayManagerTest, HostWriteThenHostRead) +{ + // Set up + constexpr std::size_t N = 128; + UnifiedArrayManager manager{N}; + + // Host write + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(true); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + data[i] = static_cast(i); + } + } + + // Host read + { + ContextGuard guard{Context::HOST}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], static_cast(i)); + } + } +} + +TEST_F(UnifiedArrayManagerTest, HostReadThenDeviceRead) +{ + // Set up + constexpr std::size_t N = 256; + UnifiedArrayManager manager{N}; + + // Host read + { + ContextGuard guard{Context::HOST}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], 0); + } + } + + // Set up + int* out = malloc_managed(N); + ASSERT_NE(out, nullptr); + + // Device read + { + ContextGuard guard{Context::DEVICE}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + launch_copy(data, out, N); + } + + // Synchronize + device_synchronize_raw(); + + // Check result + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(out[i], 0); + } + + // Clean up + free_managed(out); +} + +TEST_F(UnifiedArrayManagerTest, HostWriteThenDeviceRead) +{ + // Set up + constexpr std::size_t N = 256; + UnifiedArrayManager manager{N}; + + // Host write + { + ContextGuard guard{Context::HOST}; + int* data = manager.data(true); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + data[i] = static_cast(i); + } + } + + // Set up + int* out = malloc_managed(N); + ASSERT_NE(out, nullptr); + + // Device read + { + ContextGuard guard{Context::DEVICE}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + launch_copy(data, out, N); + } + + // Synchronize + device_synchronize_raw(); + + // Check result + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(out[i], static_cast(i)); + } + + // Clean up + free_managed(out); +} + +TEST_F(UnifiedArrayManagerTest, DeviceReadThenHostRead) +{ + // Set up + constexpr std::size_t N = 256; + UnifiedArrayManager manager{N}; + + int* out = malloc_managed(N); + ASSERT_NE(out, nullptr); + + // Device read + { + ContextGuard guard{Context::DEVICE}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + launch_copy(data, out, N); + } + + // Host read + { + ContextGuard guard{Context::HOST}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], 0); + } + } + + // Synchronize + // Note: The host read should have caused a synchronize, but the following + // checks should independent of whether than part works. + device_synchronize_raw(); + + // Checks + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(out[i], 0); + } + + // Clean up + free_managed(out); +} + +TEST_F(UnifiedArrayManagerTest, DeviceWriteThenHostRead) +{ + // Set up + constexpr std::size_t N = 256; + UnifiedArrayManager manager{N}; + + // Device write + { + ContextGuard guard{Context::DEVICE}; + int* data = manager.data(true); + ASSERT_NE(data, nullptr); + launch_increment(data, N); + } + + // Host read + { + ContextGuard guard{Context::HOST}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(data[i], 1); + } + } +} + +TEST_F(UnifiedArrayManagerTest, DeviceReadThenDeviceRead) +{ + // Set up + constexpr std::size_t N = 256; + UnifiedArrayManager manager{N}; + + int* out0 = malloc_managed(N); + int* out1 = malloc_managed(N); + ASSERT_NE(out0, nullptr); + ASSERT_NE(out1, nullptr); + + // Device read + { + ContextGuard guard{Context::DEVICE}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + launch_copy(data, out0, N); + } + + // Device read + { + ContextGuard guard{Context::DEVICE}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + launch_copy(data, out1, N); + } + + // Synchronize + device_synchronize_raw(); + + // Checks + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(out0[i], 0); + EXPECT_EQ(out1[i], 0); + } + + // Clean up + free_managed(out0); + free_managed(out1); +} + +TEST_F(UnifiedArrayManagerTest, DeviceWriteThenDeviceRead) +{ + // Set up + constexpr std::size_t N = 256; + UnifiedArrayManager manager{N}; + + // Device write + { + ContextGuard guard{Context::DEVICE}; + int* data = manager.data(true); + ASSERT_NE(data, nullptr); + launch_increment(data, N); + } + + // Set up + int* out = malloc_managed(N); + ASSERT_NE(out, nullptr); + + // Device read + { + ContextGuard guard{Context::DEVICE}; + const int* data = manager.data(false); + ASSERT_NE(data, nullptr); + launch_copy(data, out, N); + } + + // Synchronize + device_synchronize_raw(); + + // Checks + for (std::size_t i = 0; i < N; ++i) + { + EXPECT_EQ(out[i], 1); + } + + // Clean up + free_managed(out); +} + diff --git a/tests/install/CMakeLists.txt b/tests/install/CMakeLists.txt index b3ed310a..badb8776 100644 --- a/tests/install/CMakeLists.txt +++ b/tests/install/CMakeLists.txt @@ -1,9 +1,9 @@ -############################################################################### -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC -# and CHAI project contributors. See the CHAI LICENSE file for details. +############################################################################## +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # -# SPDX-License-Identifier: (BSD-3-Clause) -############################################################################### +# SPDX-License-Identifier: BSD-3-Clause +############################################################################## configure_file( using-with-cmake/host-config.cmake.in diff --git a/tests/install/using-with-cmake/CMakeLists.txt b/tests/install/using-with-cmake/CMakeLists.txt index d49d4bac..c45dd12a 100644 --- a/tests/install/using-with-cmake/CMakeLists.txt +++ b/tests/install/using-with-cmake/CMakeLists.txt @@ -1,9 +1,9 @@ -############################################################################### -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC -# and CHAI project contributors. See the CHAI LICENSE file for details. +############################################################################## +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # -# SPDX-License-Identifier: (BSD-3-Clause) -############################################################################### +# SPDX-License-Identifier: BSD-3-Clause +############################################################################## if (ENABLE_HIP) cmake_minimum_required(VERSION 3.23) diff --git a/tests/install/using-with-cmake/host-config.cmake.in b/tests/install/using-with-cmake/host-config.cmake.in index 637fcaeb..c74e1e85 100644 --- a/tests/install/using-with-cmake/host-config.cmake.in +++ b/tests/install/using-with-cmake/host-config.cmake.in @@ -1,9 +1,9 @@ -############################################################################### -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC -# and CHAI project contributors. See the CHAI LICENSE file for details. +############################################################################## +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # -# SPDX-License-Identifier: (BSD-3-Clause) -############################################################################### +# SPDX-License-Identifier: BSD-3-Clause +############################################################################## # Config related to compiler set(CMAKE_C_COMPILER "@CMAKE_C_COMPILER@" CACHE PATH "") diff --git a/tests/install/using-with-cmake/using-with-cmake.cpp b/tests/install/using-with-cmake/using-with-cmake.cpp index 585cdc56..d63f6946 100644 --- a/tests/install/using-with-cmake/using-with-cmake.cpp +++ b/tests/install/using-with-cmake/using-with-cmake.cpp @@ -1,9 +1,9 @@ -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC -// and CHAI project contributors. See the CHAI LICENSE file for details. +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // -// SPDX-License-Identifier: (BSD-3-Clause) -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// SPDX-License-Identifier: BSD-3-Clause +////////////////////////////////////////////////////////////////////////////// #include "chai/ManagedArray.hpp" #include diff --git a/tests/integration/CMakeLists.txt b/tests/integration/CMakeLists.txt index 884c8337..4d70741e 100644 --- a/tests/integration/CMakeLists.txt +++ b/tests/integration/CMakeLists.txt @@ -1,11 +1,11 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## set (chai_integration_test_depends - chai umpire gtest) + chai ${CHAI_UMPIRE_TARGET} gtest) blt_list_append(TO chai_integration_test_depends ELEMENTS cuda IF ${CHAI_ENABLE_CUDA}) blt_list_append(TO chai_integration_test_depends ELEMENTS blt::hip IF ${CHAI_ENABLE_HIP}) diff --git a/tests/integration/managed_array_tests.cpp b/tests/integration/managed_array_tests.cpp index 07011d28..9e4a22a9 100644 --- a/tests/integration/managed_array_tests.cpp +++ b/tests/integration/managed_array_tests.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/tests/integration/managed_ptr_tests.cpp b/tests/integration/managed_ptr_tests.cpp index a79edb94..73358b61 100644 --- a/tests/integration/managed_ptr_tests.cpp +++ b/tests/integration/managed_ptr_tests.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/tests/integration/managed_shared_ptr_tests.cpp b/tests/integration/managed_shared_ptr_tests.cpp index 3d17c2dc..f08e7204 100644 --- a/tests/integration/managed_shared_ptr_tests.cpp +++ b/tests/integration/managed_shared_ptr_tests.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-24, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/tests/integration/raja-chai-launch.cpp b/tests/integration/raja-chai-launch.cpp index 6ada0f7b..c1d70b1a 100644 --- a/tests/integration/raja-chai-launch.cpp +++ b/tests/integration/raja-chai-launch.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/tests/integration/raja-chai-nested.cpp b/tests/integration/raja-chai-nested.cpp index 7702dcc5..45097727 100644 --- a/tests/integration/raja-chai-nested.cpp +++ b/tests/integration/raja-chai-nested.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/tests/integration/raja-chai-tests.cpp b/tests/integration/raja-chai-tests.cpp index c85850ae..0dd185c7 100644 --- a/tests/integration/raja-chai-tests.cpp +++ b/tests/integration/raja-chai-tests.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 1831dfe9..00da03f7 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -1,11 +1,11 @@ ############################################################################## -# Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -# project contributors. See the CHAI LICENSE file for details. +# Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +# contributors. See the CHAI LICENSE and COPYRIGHT files for details. # # SPDX-License-Identifier: BSD-3-Clause ############################################################################## set (chai_unit_test_depends - chai umpire gtest) + chai ${CHAI_UMPIRE_TARGET} gtest) blt_list_append(TO chai_unit_test_depends ELEMENTS cuda IF ${CHAI_ENABLE_CUDA}) blt_list_append(TO chai_unit_test_depends ELEMENTS blt::hip IF ${CHAI_ENABLE_HIP}) diff --git a/tests/unit/array_manager_unit_tests.cpp b/tests/unit/array_manager_unit_tests.cpp index 341ff576..072c0731 100644 --- a/tests/unit/array_manager_unit_tests.cpp +++ b/tests/unit/array_manager_unit_tests.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/tests/unit/managed_array_unit_tests.cpp b/tests/unit/managed_array_unit_tests.cpp index 2a65d2b2..b5d3f04f 100644 --- a/tests/unit/managed_array_unit_tests.cpp +++ b/tests/unit/managed_array_unit_tests.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause ////////////////////////////////////////////////////////////////////////////// diff --git a/tests/unit/managed_ptr_unit_tests.cpp b/tests/unit/managed_ptr_unit_tests.cpp index 907a1c9a..d8fc518e 100644 --- a/tests/unit/managed_ptr_unit_tests.cpp +++ b/tests/unit/managed_ptr_unit_tests.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Copyright (c) 2016-25, Lawrence Livermore National Security, LLC and CHAI -// project contributors. See the CHAI LICENSE file for details. +// Copyright (c) Lawrence Livermore National Security, LLC and other CHAI +// contributors. See the CHAI LICENSE and COPYRIGHT files for details. // // SPDX-License-Identifier: BSD-3-Clause //////////////////////////////////////////////////////////////////////////////