From 5db2a4b25783ca547064275293aba296cbf7ee3d Mon Sep 17 00:00:00 2001 From: Riley Murray Date: Sun, 24 May 2026 22:41:56 -0700 Subject: [PATCH 1/5] new CI workflows --- .../actions/setup-randblas-deps/action.yml | 189 ++++++++++++++ .github/workflows/core.yml | 240 ++++++++++++++++++ 2 files changed, 429 insertions(+) create mode 100644 .github/actions/setup-randblas-deps/action.yml create mode 100644 .github/workflows/core.yml diff --git a/.github/actions/setup-randblas-deps/action.yml b/.github/actions/setup-randblas-deps/action.yml new file mode 100644 index 00000000..541cbd4b --- /dev/null +++ b/.github/actions/setup-randblas-deps/action.yml @@ -0,0 +1,189 @@ +name: setup-randblas-deps +description: > + Installs RandBLAS build dependencies (GoogleTest, BLAS++, Random123, and + optionally LAPACK++), with caching for the from-source dependencies. Exports + blaspp_DIR, Random123_DIR, and (optionally) lapackpp_DIR via GITHUB_ENV. + +inputs: + cc: + description: "C compiler to use for building from-source dependencies." + required: true + cxx: + description: "C++ compiler to use for building from-source dependencies." + required: true + blas-backend: + description: "BLAS backend for blaspp: openblas, mkl, accelerate, or auto." + required: false + default: auto + install-lapackpp: + description: "If 'true', also clone and build LAPACK++ (needed by examples)." + required: false + default: "false" + +runs: + using: composite + steps: + - name: install system packages (Linux) + if: runner.os == 'Linux' + shell: bash + run: | + set -euxo pipefail + export DEBIAN_FRONTEND=noninteractive + sudo apt-get update -qq + sudo apt-get install -qq -y \ + git-core gfortran cmake make automake m4 \ + libgtest-dev + case "${{ inputs.blas-backend }}" in + openblas) + sudo apt-get install -qq -y libopenblas-openmp-dev + ;; + mkl) + sudo apt-get install -qq -y libmkl-dev + ;; + auto) + sudo apt-get install -qq -y libopenblas-openmp-dev + ;; + accelerate) + echo "::error::accelerate backend is not available on Linux" >&2 + exit 1 + ;; + *) + echo "::error::unknown blas-backend: ${{ inputs.blas-backend }}" >&2 + exit 1 + ;; + esac + + - name: install system packages (macOS) + if: runner.os == 'macOS' + shell: bash + run: | + set -euxo pipefail + brew install googletest + case "${{ inputs.blas-backend }}" in + accelerate|auto) : ;; + openblas) brew install openblas ;; + mkl) + echo "::error::mkl backend is not supported on macOS" >&2 + exit 1 + ;; + *) + echo "::error::unknown blas-backend: ${{ inputs.blas-backend }}" >&2 + exit 1 + ;; + esac + + - name: resolve blaspp HEAD commit + id: blaspp-rev + shell: bash + run: | + set -euxo pipefail + sha="$(git ls-remote https://github.com/icl-utk-edu/blaspp.git HEAD | awk '{print $1}')" + echo "sha=${sha}" >> "$GITHUB_OUTPUT" + + - name: resolve lapackpp HEAD commit + if: inputs.install-lapackpp == 'true' + id: lapackpp-rev + shell: bash + run: | + set -euxo pipefail + sha="$(git ls-remote https://github.com/icl-utk-edu/lapackpp.git HEAD | awk '{print $1}')" + echo "sha=${sha}" >> "$GITHUB_OUTPUT" + + - name: cache blaspp install + id: blaspp-cache + uses: actions/cache@v4 + with: + path: ${{ github.workspace }}/../blaspp-install + key: blaspp-${{ runner.os }}-${{ runner.arch }}-${{ inputs.cc }}-${{ inputs.blas-backend }}-${{ steps.blaspp-rev.outputs.sha }} + + - name: build blaspp + if: steps.blaspp-cache.outputs.cache-hit != 'true' + shell: bash + env: + CC: ${{ inputs.cc }} + CXX: ${{ inputs.cxx }} + run: | + set -euxo pipefail + cd .. + rm -rf blaspp blaspp-build blaspp-install + git clone --depth 1 https://github.com/icl-utk-edu/blaspp.git + mkdir blaspp-build + cd blaspp-build + blas_arg="" + case "${{ inputs.blas-backend }}" in + openblas) blas_arg="-Dblas=openblas" ;; + mkl) blas_arg="-Dblas=mkl" ;; + accelerate) blas_arg="-Dblas=accelerate" ;; + auto) blas_arg="" ;; + esac + cmake \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="$(pwd)/../blaspp-install" \ + -Dbuild_tests=OFF \ + ${blas_arg} \ + ../blaspp + if [[ "$(uname)" == "Darwin" ]]; then + jobs="$(sysctl -n hw.logicalcpu)" + else + jobs="$(nproc)" + fi + make -j"${jobs}" install + + - name: cache lapackpp install + if: inputs.install-lapackpp == 'true' + id: lapackpp-cache + uses: actions/cache@v4 + with: + path: ${{ github.workspace }}/../lapackpp-install + key: lapackpp-${{ runner.os }}-${{ runner.arch }}-${{ inputs.cc }}-${{ inputs.blas-backend }}-${{ steps.blaspp-rev.outputs.sha }}-${{ steps.lapackpp-rev.outputs.sha }} + + - name: build lapackpp + if: inputs.install-lapackpp == 'true' && steps.lapackpp-cache.outputs.cache-hit != 'true' + shell: bash + env: + CC: ${{ inputs.cc }} + CXX: ${{ inputs.cxx }} + run: | + set -euxo pipefail + cd .. + rm -rf lapackpp lapackpp-build lapackpp-install + git clone --depth 1 https://github.com/icl-utk-edu/lapackpp.git + mkdir lapackpp-build + cd lapackpp-build + cmake \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="$(pwd)/../lapackpp-install" \ + -Dblaspp_DIR="$(pwd)/../blaspp-install/lib/cmake/blaspp" \ + -Dbuild_tests=OFF \ + ../lapackpp + if [[ "$(uname)" == "Darwin" ]]; then + jobs="$(sysctl -n hw.logicalcpu)" + else + jobs="$(nproc)" + fi + make -j"${jobs}" install + + - name: install Random123 headers + shell: bash + run: | + set -euxo pipefail + cd .. + rm -rf Random123 Random123-install + git clone --depth 1 https://github.com/DEShawResearch/Random123.git + cd Random123 + make prefix="$(pwd)/../Random123-install" install-include + + - name: export dependency paths + shell: bash + run: | + set -euxo pipefail + cd .. + echo "blaspp_DIR=$(pwd)/blaspp-install/lib/cmake/blaspp" >> "$GITHUB_ENV" + echo "Random123_DIR=$(pwd)/Random123-install/include" >> "$GITHUB_ENV" + if [[ "${{ inputs.install-lapackpp }}" == "true" ]]; then + echo "lapackpp_DIR=$(pwd)/lapackpp-install/lib/cmake/lapackpp" >> "$GITHUB_ENV" + fi diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml new file mode 100644 index 00000000..f4142672 --- /dev/null +++ b/.github/workflows/core.yml @@ -0,0 +1,240 @@ +name: core +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: ${{ matrix.label }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + # Linux / gcc / OpenBLAS — primary correctness cell (Release). + - label: linux-gcc-openblas-release + os: ubuntu-latest + cc: gcc + cxx: g++ + blas-backend: openblas + build-type: Release + sanitizer: none + openmp: true + + # Linux / gcc / OpenBLAS — Debug + ASan. + - label: linux-gcc-openblas-debug-asan + os: ubuntu-latest + cc: gcc + cxx: g++ + blas-backend: openblas + build-type: Debug + sanitizer: asan + openmp: true + + # Linux / gcc / OpenBLAS — Release + UBSan. + - label: linux-gcc-openblas-release-ubsan + os: ubuntu-latest + cc: gcc + cxx: g++ + blas-backend: openblas + build-type: Release + sanitizer: ubsan + openmp: true + + # Linux / gcc / MKL — exercises RandBLAS_HAS_MKL codepaths. + - label: linux-gcc-mkl-release + os: ubuntu-latest + cc: gcc + cxx: g++ + blas-backend: mkl + build-type: Release + sanitizer: none + openmp: true + + # Linux / clang / OpenBLAS — Release. + - label: linux-clang-openblas-release + os: ubuntu-latest + cc: clang + cxx: clang++ + blas-backend: openblas + build-type: Release + sanitizer: none + openmp: true + + # Linux / clang / OpenBLAS — Release + ASan. + - label: linux-clang-openblas-release-asan + os: ubuntu-latest + cc: clang + cxx: clang++ + blas-backend: openblas + build-type: Release + sanitizer: asan + openmp: true + + # macOS 14 / Apple Clang / Accelerate — no OpenMP (serial). + - label: macos14-appleclang-accelerate-release + os: macos-14 + cc: clang + cxx: clang++ + blas-backend: accelerate + build-type: Release + sanitizer: none + openmp: false + + # macOS 14 / Apple Clang / Accelerate — Debug + ASan, no OpenMP. + - label: macos14-appleclang-accelerate-debug-asan + os: macos-14 + cc: clang + cxx: clang++ + blas-backend: accelerate + build-type: Debug + sanitizer: asan + openmp: false + + # macOS 14 / Homebrew LLVM / Accelerate — OpenMP build. + - label: macos14-llvm-accelerate-release + os: macos-14 + cc: brew-llvm-clang + cxx: brew-llvm-clang++ + blas-backend: accelerate + build-type: Release + sanitizer: none + openmp: true + + # macOS 14 / Homebrew LLVM / Accelerate — Release + ASan with OpenMP. + - label: macos14-llvm-accelerate-release-asan + os: macos-14 + cc: brew-llvm-clang + cxx: brew-llvm-clang++ + blas-backend: accelerate + build-type: Release + sanitizer: asan + openmp: true + + # macOS 15 / Homebrew LLVM / Accelerate — track latest macOS runner. + - label: macos15-llvm-accelerate-release + os: macos-15 + cc: brew-llvm-clang + cxx: brew-llvm-clang++ + blas-backend: accelerate + build-type: Release + sanitizer: none + openmp: true + + steps: + - uses: actions/checkout@v4 + + - name: resolve compiler paths + id: compilers + shell: bash + run: | + set -euxo pipefail + case "${{ matrix.cc }}" in + brew-llvm-clang) + brew update + brew install llvm + llvm_prefix="$(brew --prefix llvm)" + echo "cc=${llvm_prefix}/bin/clang" >> "$GITHUB_OUTPUT" + echo "cxx=${llvm_prefix}/bin/clang++" >> "$GITHUB_OUTPUT" + echo "${llvm_prefix}/bin" >> "$GITHUB_PATH" + ;; + clang) + if [[ "${{ runner.os }}" == "Linux" ]]; then + sudo apt-get update -qq + sudo apt-get install -qq -y clang + fi + echo "cc=clang" >> "$GITHUB_OUTPUT" + echo "cxx=clang++" >> "$GITHUB_OUTPUT" + ;; + gcc) + echo "cc=gcc" >> "$GITHUB_OUTPUT" + echo "cxx=g++" >> "$GITHUB_OUTPUT" + ;; + *) + echo "::error::unknown matrix.cc: ${{ matrix.cc }}" >&2 + exit 1 + ;; + esac + + - name: setup RandBLAS dependencies + uses: ./.github/actions/setup-randblas-deps + with: + cc: ${{ steps.compilers.outputs.cc }} + cxx: ${{ steps.compilers.outputs.cxx }} + blas-backend: ${{ matrix.blas-backend }} + + - name: configure and build RandBLAS + shell: bash + env: + CC: ${{ steps.compilers.outputs.cc }} + CXX: ${{ steps.compilers.outputs.cxx }} + run: | + set -euxo pipefail + cd .. + mkdir -p RandBLAS-build + cd RandBLAS-build + + sanitize_address_arg="" + extra_cxx_flags="" + extra_link_flags="" + case "${{ matrix.sanitizer }}" in + none) ;; + asan) + sanitize_address_arg="-DSANITIZE_ADDRESS=ON" + ;; + ubsan) + extra_cxx_flags="-fsanitize=undefined -fno-sanitize-recover=undefined" + extra_link_flags="-fsanitize=undefined" + ;; + *) + echo "::error::unknown matrix.sanitizer: ${{ matrix.sanitizer }}" >&2 + exit 1 + ;; + esac + + cmake \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_BUILD_TYPE="${{ matrix.build-type }}" \ + -DCMAKE_CXX_FLAGS="${extra_cxx_flags}" \ + -DCMAKE_EXE_LINKER_FLAGS="${extra_link_flags}" \ + ${sanitize_address_arg} \ + -Dblaspp_DIR="${blaspp_DIR}" \ + -DRandom123_DIR="${Random123_DIR}" \ + -DCMAKE_INSTALL_PREFIX="$(pwd)/../RandBLAS-install" \ + "$(pwd)/../RandBLAS" + + if [[ "$(uname)" == "Darwin" ]]; then + jobs="$(sysctl -n hw.logicalcpu)" + else + jobs="$(nproc)" + fi + make -j"${jobs}" install + + - name: ctest (OMP_NUM_THREADS=1) + if: matrix.openmp + shell: bash + working-directory: ${{ github.workspace }}/../RandBLAS-build + env: + OMP_NUM_THREADS: "1" + run: ctest --output-on-failure + + - name: ctest (OMP_NUM_THREADS=4) + if: matrix.openmp + shell: bash + working-directory: ${{ github.workspace }}/../RandBLAS-build + env: + OMP_NUM_THREADS: "4" + run: ctest --output-on-failure + + - name: ctest (no OpenMP) + if: ${{ !matrix.openmp }} + shell: bash + working-directory: ${{ github.workspace }}/../RandBLAS-build + run: ctest --output-on-failure From ecf8ded39366efceac1ae311f6cdfe8fe904102d Mon Sep 17 00:00:00 2001 From: Riley Murray Date: Sun, 24 May 2026 22:47:42 -0700 Subject: [PATCH 2/5] bugfix --- .github/actions/setup-randblas-deps/action.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/actions/setup-randblas-deps/action.yml b/.github/actions/setup-randblas-deps/action.yml index 541cbd4b..bbbdd294 100644 --- a/.github/actions/setup-randblas-deps/action.yml +++ b/.github/actions/setup-randblas-deps/action.yml @@ -174,8 +174,11 @@ runs: cd .. rm -rf Random123 Random123-install git clone --depth 1 https://github.com/DEShawResearch/Random123.git - cd Random123 - make prefix="$(pwd)/../Random123-install" install-include + # Random123's `make install-include` target uses GNU `cp -d`, which + # isn't supported by BSD cp on macOS. Copy the headers directly so + # the same step works on both platforms. + mkdir -p Random123-install/include + cp -R Random123/include/Random123 Random123-install/include/ - name: export dependency paths shell: bash From d778549520debffa40dcd111034cc46ecaca4332 Mon Sep 17 00:00:00 2001 From: Riley Murray Date: Mon, 25 May 2026 09:38:40 -0700 Subject: [PATCH 3/5] thread sanitizer and examples --- .github/workflows/core-linux.yaml | 68 --------------------- .github/workflows/core-macos.yml | 63 ------------------- .github/workflows/docs.yml | 43 +++++++++++++ .github/workflows/downstream-consumer.yml | 55 +++++++++++++++++ .github/workflows/examples.yml | 56 +++++++++++++++++ .github/workflows/openmp-macos-15.yaml | 73 ----------------------- .github/workflows/openmp-macos.yaml | 55 ----------------- .github/workflows/thread-sanitizer.yml | 63 +++++++++++++++++++ CLAUDE.md | 2 +- INSTALL.md | 6 +- docker/tsan/Dockerfile | 52 ++++++++++++++++ docker/tsan/run.sh | 72 ++++++++++++++++++++++ test/downstream/CMakeLists.txt | 16 +++++ test/downstream/main.cc | 21 +++++++ 14 files changed, 382 insertions(+), 263 deletions(-) delete mode 100644 .github/workflows/core-linux.yaml delete mode 100644 .github/workflows/core-macos.yml create mode 100644 .github/workflows/docs.yml create mode 100644 .github/workflows/downstream-consumer.yml create mode 100644 .github/workflows/examples.yml delete mode 100644 .github/workflows/openmp-macos-15.yaml delete mode 100644 .github/workflows/openmp-macos.yaml create mode 100644 .github/workflows/thread-sanitizer.yml create mode 100644 docker/tsan/Dockerfile create mode 100755 docker/tsan/run.sh create mode 100644 test/downstream/CMakeLists.txt create mode 100644 test/downstream/main.cc diff --git a/.github/workflows/core-linux.yaml b/.github/workflows/core-linux.yaml deleted file mode 100644 index d83a13df..00000000 --- a/.github/workflows/core-linux.yaml +++ /dev/null @@ -1,68 +0,0 @@ -name: core-linux -on: - pull_request: - workflow_dispatch: - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: configure OS - run: | - # os level stuff - pwd - ls - set -x - export DEBIAN_FRONTEND="noninteractive" - export TZ="America/Los_Angeles" - sudo apt-get update -qq - sudo apt-get install -qq -y git-core gcc g++ \ - gfortran cmake subversion automake m4 \ - libgtest-dev libmkl-dev libopenblas-openmp-dev - - - name: install BLAS++ - run: | - cd .. - git clone https://github.com/icl-utk-edu/blaspp.git - mkdir blaspp-build - cd blaspp-build - cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=`pwd`/../blaspp-install -Dbuild_tests=OFF ../blaspp - make -j2 install - - - name: install Random123 - run: | - cd .. - git clone https://github.com/DEShawResearch/Random123.git - cd Random123/ - make prefix=`pwd`/../Random123-install install-include - - - name: build and test RandBLAS (release) - run: | - cd .. - mkdir RandBLAS-build - cd RandBLAS-build - cmake -DCMAKE_BUILD_TYPE=Release \ - -Dblaspp_DIR=`pwd`/../blaspp-install/lib/cmake/blaspp/ \ - -DRandom123_DIR=`pwd`/../Random123-install/include/ \ - -DCMAKE_INSTALL_PREFIX=`pwd`/../RandBLAS-install \ - -DCMAKE_BINARY_DIR=`pwd` \ - `pwd`/../RandBLAS - make -j2 install - ctest --output-on-failure - - - name: build and test RandBLAS (Debug/asan) - run: | - cd .. - mkdir RandBLAS-asan-build - cd RandBLAS-asan-build - cmake -DCMAKE_BUILD_TYPE=Debug \ - -DSANITIZE_ADDRESS=ON \ - -Dblaspp_DIR=`pwd`/../blaspp-install/lib/cmake/blaspp/ \ - -DRandom123_DIR=`pwd`/../Random123-install/include/ \ - -DCMAKE_INSTALL_PREFIX=`pwd`/../RandBLAS-install \ - -DCMAKE_BINARY_DIR=`pwd` \ - `pwd`/../RandBLAS - make -j2 install - ctest --output-on-failure diff --git a/.github/workflows/core-macos.yml b/.github/workflows/core-macos.yml deleted file mode 100644 index 08678a64..00000000 --- a/.github/workflows/core-macos.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: core-macos -on: - pull_request: - workflow_dispatch: - -jobs: - build: - runs-on: macos-latest - steps: - - uses: actions/checkout@v2 - - - name: configure OS - run: | - # os level stuff - set -x - brew install googletest - - - name: install BLAS++ - run: | - cd .. - git clone https://github.com/icl-utk-edu/blaspp.git - mkdir blaspp-build - cd blaspp-build - pwd - cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=`pwd`/../blaspp-install -Dbuild_tests=OFF ../blaspp - make -j2 install - - - name: install Random123 - run: | - cd .. - git clone https://github.com/DEShawResearch/Random123.git - cd Random123/ - mkdir -p `pwd`/../Random123-install/include - cp -rp include/Random123 `pwd`/../Random123-install/include/ - - - name: build and test RandBLAS (release) - run: | - cd .. - mkdir RandBLAS-build - cd RandBLAS-build - cmake -DCMAKE_BUILD_TYPE=Release \ - -Dblaspp_DIR=`pwd`/../blaspp-install/lib/cmake/blaspp/ \ - -DRandom123_DIR=`pwd`/../Random123-install/include/ \ - -DCMAKE_INSTALL_PREFIX=`pwd`/../RandBLAS-install \ - -DCMAKE_BINARY_DIR=`pwd` \ - `pwd`/../RandBLAS - make -j2 install - ctest --output-on-failure - - - name: build and test RandBLAS (Debug/asan) - run: | - cd .. - mkdir RandBLAS-asan-build - cd RandBLAS-asan-build - cmake -DCMAKE_BUILD_TYPE=Debug \ - -DSANITIZE_ADDRESS=ON \ - -Dblaspp_DIR=`pwd`/../blaspp-install/lib/cmake/blaspp/ \ - -DRandom123_DIR=`pwd`/../Random123-install/include/ \ - -DCMAKE_INSTALL_PREFIX=`pwd`/../RandBLAS-install \ - -DCMAKE_BINARY_DIR=`pwd` \ - `pwd`/../RandBLAS - make -j2 install - ctest --output-on-failure diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..2fa4bdba --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,43 @@ +name: docs +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + sphinx: + name: sphinx-build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: install doxygen + shell: bash + run: | + set -euxo pipefail + sudo apt-get update -qq + sudo apt-get install -qq -y doxygen + + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: pip + cache-dependency-path: rtd/requirements.txt + + - name: install Python deps + shell: bash + run: pip install -r rtd/requirements.txt + + # conf.py invokes `doxygen` itself before Sphinx runs, so a plain + # sphinx-build is sufficient. -W (warnings-as-errors) is intentionally + # NOT set here: this workflow lands as a shadow build first, and we'll + # flip on -W in a follow-up PR after the docstring backlog is cleared. + - name: sphinx-build + shell: bash + working-directory: ${{ github.workspace }}/rtd + run: sphinx-build source build diff --git a/.github/workflows/downstream-consumer.yml b/.github/workflows/downstream-consumer.yml new file mode 100644 index 00000000..9490c430 --- /dev/null +++ b/.github/workflows/downstream-consumer.yml @@ -0,0 +1,55 @@ +name: downstream-consumer +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + find-package-smoke: + name: linux-gcc-find-package + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: setup RandBLAS dependencies + uses: ./.github/actions/setup-randblas-deps + with: + cc: gcc + cxx: g++ + blas-backend: openblas + + - name: build and install RandBLAS + shell: bash + run: | + set -euxo pipefail + cd .. + mkdir RandBLAS-build + cd RandBLAS-build + cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -Dblaspp_DIR="${blaspp_DIR}" \ + -DRandom123_DIR="${Random123_DIR}" \ + -DCMAKE_INSTALL_PREFIX="$(pwd)/../RandBLAS-install" \ + "$(pwd)/../RandBLAS" + make -j"$(nproc)" install + + - name: configure and build downstream smoke test + shell: bash + working-directory: ${{ github.workspace }}/test/downstream + run: | + set -euxo pipefail + mkdir build + cd build + cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DRandBLAS_DIR="$(pwd)/../../../../RandBLAS-install/lib/cmake" \ + -Dblaspp_DIR="${blaspp_DIR}" \ + -DRandom123_DIR="${Random123_DIR}" \ + .. + make -j"$(nproc)" + ./smoke diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml new file mode 100644 index 00000000..4224140a --- /dev/null +++ b/.github/workflows/examples.yml @@ -0,0 +1,56 @@ +name: examples +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-examples: + name: linux-gcc-openblas-examples + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: setup RandBLAS dependencies (with LAPACK++) + uses: ./.github/actions/setup-randblas-deps + with: + cc: gcc + cxx: g++ + blas-backend: openblas + install-lapackpp: "true" + + - name: build and install RandBLAS + shell: bash + run: | + set -euxo pipefail + cd .. + mkdir RandBLAS-build + cd RandBLAS-build + cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -Dblaspp_DIR="${blaspp_DIR}" \ + -DRandom123_DIR="${Random123_DIR}" \ + -DCMAKE_INSTALL_PREFIX="$(pwd)/../RandBLAS-install" \ + "$(pwd)/../RandBLAS" + make -j"$(nproc)" install + + - name: configure and build examples + shell: bash + working-directory: ${{ github.workspace }}/examples + run: | + set -euxo pipefail + mkdir build + cd build + cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DRandBLAS_DIR="$(pwd)/../../../RandBLAS-install/lib/cmake" \ + -Dblaspp_DIR="${blaspp_DIR}" \ + -Dlapackpp_DIR="${lapackpp_DIR}" \ + -DRandom123_DIR="${Random123_DIR}" \ + .. + make -j"$(nproc)" diff --git a/.github/workflows/openmp-macos-15.yaml b/.github/workflows/openmp-macos-15.yaml deleted file mode 100644 index 6fd042e2..00000000 --- a/.github/workflows/openmp-macos-15.yaml +++ /dev/null @@ -1,73 +0,0 @@ -name: openmp-macos-15 -on: - pull_request: - workflow_dispatch: - -jobs: - build: - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - - name: configure OS - run: | - set -euxo pipefail - brew update - brew install googletest llvm - - LLVM_PREFIX="$(brew --prefix llvm)" - - # Export compilers for subsequent steps - echo "CC=${LLVM_PREFIX}/bin/clang" >> "$GITHUB_ENV" - echo "CXX=${LLVM_PREFIX}/bin/clang++" >> "$GITHUB_ENV" - - # Optional: ensure this clang/clang++ is what gets picked up by default - echo "${LLVM_PREFIX}/bin" >> "$GITHUB_PATH" - - # Debug info (helpful if something breaks later) - which clang || true - which clang++ || true - clang --version || true - clang++ --version || true - - - name: install BLAS++ - run: | - set -euxo pipefail - cd .. - git clone https://github.com/icl-utk-edu/blaspp.git - mkdir blaspp-build - cd blaspp-build - cmake \ - -DCMAKE_CXX_COMPILER="${CXX}" \ - -DCMAKE_C_COMPILER="${CC}" \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX="$(pwd)/../blaspp-install" \ - -Dbuild_tests=OFF \ - ../blaspp - make -j2 install - - - name: install Random123 - run: | - set -euxo pipefail - cd .. - git clone https://github.com/DEShawResearch/Random123.git - cd Random123/ - mkdir -p "$(pwd)/../Random123-install/include" - cp -rp include/Random123 "$(pwd)/../Random123-install/include/" - - - name: build and test RandBLAS (release) - run: | - set -euxo pipefail - cd .. - mkdir RandBLAS-build - cd RandBLAS-build - cmake \ - -DCMAKE_CXX_COMPILER="${CXX}" \ - -DCMAKE_C_COMPILER="${CC}" \ - -DCMAKE_BUILD_TYPE=Release \ - -Dblaspp_DIR="$(pwd)/../blaspp-install/lib/cmake/blaspp/" \ - -DRandom123_DIR="$(pwd)/../Random123-install/include/" \ - -DCMAKE_INSTALL_PREFIX="$(pwd)/../RandBLAS-install" \ - ../RandBLAS - make -j2 install - ctest --output-on-failure \ No newline at end of file diff --git a/.github/workflows/openmp-macos.yaml b/.github/workflows/openmp-macos.yaml deleted file mode 100644 index fba16aa6..00000000 --- a/.github/workflows/openmp-macos.yaml +++ /dev/null @@ -1,55 +0,0 @@ -name: openmp-macos-latest -on: - pull_request: - workflow_dispatch: - -jobs: - build: - runs-on: macos-latest - steps: - - uses: actions/checkout@v2 - - - name: configure OS - run: | - # os level stuff - set -x - brew install googletest llvm - - - name: install BLAS++ - run: | - cd .. - git clone https://github.com/icl-utk-edu/blaspp.git - mkdir blaspp-build - cd blaspp-build - cmake \ - -DCMAKE_CXX_COMPILER=/opt/homebrew/opt/llvm/bin/clang++ \ - -DCMAKE_C_COMPILER=/opt/homebrew/opt/llvm/bin/clang \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=`pwd`/../blaspp-install \ - -Dbuild_tests=OFF \ - ../blaspp - make -j2 install - - - name: install Random123 - run: | - cd .. - git clone https://github.com/DEShawResearch/Random123.git - cd Random123/ - mkdir -p `pwd`/../Random123-install/include - cp -rp include/Random123 `pwd`/../Random123-install/include/ - - - name: build and test RandBLAS (release) - run: | - cd .. - mkdir RandBLAS-build - cd RandBLAS-build - cmake \ - -DCMAKE_CXX_COMPILER=/opt/homebrew/opt/llvm/bin/clang++ \ - -DCMAKE_C_COMPILER=/opt/homebrew/opt/llvm/bin/clang \ - -DCMAKE_BUILD_TYPE=Release \ - -Dblaspp_DIR=`pwd`/../blaspp-install/lib/cmake/blaspp/ \ - -DRandom123_DIR=`pwd`/../Random123-install/include/ \ - -DCMAKE_INSTALL_PREFIX=`pwd`/../RandBLAS-install \ - ../RandBLAS - make -j2 install - ctest --output-on-failure diff --git a/.github/workflows/thread-sanitizer.yml b/.github/workflows/thread-sanitizer.yml new file mode 100644 index 00000000..1e0f42ba --- /dev/null +++ b/.github/workflows/thread-sanitizer.yml @@ -0,0 +1,63 @@ +name: thread-sanitizer +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + tsan: + name: linux-clang-tsan-openmp + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: install clang + libomp + shell: bash + run: | + set -euxo pipefail + sudo apt-get update -qq + sudo apt-get install -qq -y clang libomp-dev + + - name: setup RandBLAS dependencies + uses: ./.github/actions/setup-randblas-deps + with: + cc: clang + cxx: clang++ + blas-backend: openblas + + - name: configure and build RandBLAS with TSan + shell: bash + env: + CC: clang + CXX: clang++ + run: | + set -euxo pipefail + cd .. + mkdir RandBLAS-tsan-build + cd RandBLAS-tsan-build + cmake \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_CXX_FLAGS="-fsanitize=thread -fno-omit-frame-pointer" \ + -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=thread" \ + -Dblaspp_DIR="${blaspp_DIR}" \ + -DRandom123_DIR="${Random123_DIR}" \ + "$(pwd)/../RandBLAS" + make -j"$(nproc)" + + - name: ctest under TSan (OMP_NUM_THREADS=4) + shell: bash + working-directory: ${{ github.workspace }}/../RandBLAS-tsan-build + env: + OMP_NUM_THREADS: "4" + # ignore_noninstrumented_modules=1 silences spurious reports against + # blaspp/openblas/libomp/libc, none of which are built with TSan. + TSAN_OPTIONS: "halt_on_error=0 ignore_noninstrumented_modules=1 second_deadlock_stack=1" + # test_rng_speed is a benchmark, not a correctness test; skip it under TSan. + run: ctest --output-on-failure -E test_rng_speed diff --git a/CLAUDE.md b/CLAUDE.md index d27993cf..e407abbc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -293,7 +293,7 @@ All CI tests must pass before merging. - **BLAS++** (blaspp): BLAS portability layer - must be built with CMake - **Random123**: Header-only RNG library -- **C++20 compiler**: gcc ≥9, clang ≥10, or equivalent +- **C++20 compiler**: gcc ≥13, or any clang sufficiently recent to handle C++20 concepts (CI tests Apple Clang and Homebrew LLVM on macOS, clang from `apt` on Linux) ### Optional diff --git a/INSTALL.md b/INSTALL.md index 6ba51dcd..431ae514 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -17,9 +17,9 @@ If you want a TL;DR version of this guide, refer to one of the following. ## 1. Required dependencies: a C++20 compatible compiler, BLAS++, and Random123 RandBLAS uses C++20 [concepts](https://en.cppreference.com/w/cpp/language/constraints). -Make sure your compiler supports these. Some compilers (like gcc 8.5) might need to be -invoked with an additional flag (``-fconcepts``) in order to support this aspect of the -C++20 standard. See [this issue](https://github.com/BallisticLA/RandBLAS/issues/90) for more info. +Make sure your compiler supports these. We test gcc ≥13 on Linux, and both Apple Clang +and Homebrew LLVM on macOS; older toolchains (such as gcc 8.5 with `-fconcepts`) are not +supported. BLAS++ is a C++ API for the Basic Linear Algebra Subroutines. It can be installed with GNU make or CMake. diff --git a/docker/tsan/Dockerfile b/docker/tsan/Dockerfile new file mode 100644 index 00000000..0acccac7 --- /dev/null +++ b/docker/tsan/Dockerfile @@ -0,0 +1,52 @@ +# Dev container for running ThreadSanitizer locally on macOS Apple Silicon, +# where TSan on the host is broken (shadow-memory mapping fails on arm64 +# Darwin). The container is Linux, where TSan + libomp is reliable on both +# arm64 and amd64. +# +# Build: docker build -t randblas-tsan docker/tsan/ +# Run: ./docker/tsan/run.sh +# +# The image bakes blaspp + Random123 into /opt so that iterating on RandBLAS +# itself is fast — only RandBLAS gets rebuilt per session. Bump the upstream +# refs in this Dockerfile to refresh those dependencies. +FROM ubuntu:24.04 + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update -qq && apt-get install -qq -y --no-install-recommends \ + ca-certificates git build-essential gfortran cmake make \ + clang libomp-dev libclang-rt-18-dev llvm-18 \ + libopenblas-openmp-dev libgtest-dev \ + && rm -rf /var/lib/apt/lists/* \ + && ln -s /usr/bin/llvm-symbolizer-18 /usr/local/bin/llvm-symbolizer +# ^ libclang-rt-18-dev ships the compiler-rt sanitizer runtime archives +# (incl. libclang_rt.tsan-*.a); without it clang -fsanitize=thread fails to +# link. llvm-18 + the llvm-symbolizer symlink give TSan readable file:line +# stack traces instead of raw hex addresses. + +ENV CC=clang +ENV CXX=clang++ + +# blaspp: pinned to upstream HEAD at image build time; rebuild image to refresh. +RUN git clone --depth 1 https://github.com/icl-utk-edu/blaspp.git /tmp/blaspp \ + && cmake -S /tmp/blaspp -B /tmp/blaspp-build \ + -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/opt/blaspp-install \ + -Dblas=openblas \ + -Dbuild_tests=OFF \ + && cmake --build /tmp/blaspp-build -j"$(nproc)" --target install \ + && rm -rf /tmp/blaspp /tmp/blaspp-build + +# Random123: header-only. cp -R is portable (BSD/GNU) so we don't need the +# Random123 Makefile's `install-include` target (which uses GNU `cp -d`). +RUN git clone --depth 1 https://github.com/DEShawResearch/Random123.git /tmp/Random123 \ + && mkdir -p /opt/Random123-install/include \ + && cp -R /tmp/Random123/include/Random123 /opt/Random123-install/include/ \ + && rm -rf /tmp/Random123 + +ENV blaspp_DIR=/opt/blaspp-install/lib/cmake/blaspp +ENV Random123_DIR=/opt/Random123-install/include + +WORKDIR /work +CMD ["/bin/bash"] diff --git a/docker/tsan/run.sh b/docker/tsan/run.sh new file mode 100755 index 00000000..c38e9244 --- /dev/null +++ b/docker/tsan/run.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# Build the TSan dev image if missing, then drop into a shell with the repo +# mounted at /work/RandBLAS. Subcommands: +# +# ./docker/tsan/run.sh # interactive shell in the container +# ./docker/tsan/run.sh build-and-test # configure, build, and ctest under TSan +# ./docker/tsan/run.sh rebuild-image # force-rebuild the dev image +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +image_tag="randblas-tsan" +subcommand="${1:-shell}" + +if ! command -v docker >/dev/null 2>&1; then + echo "error: docker not found on PATH" >&2 + exit 1 +fi + +ensure_image() { + if ! docker image inspect "${image_tag}" >/dev/null 2>&1; then + docker build -t "${image_tag}" "${repo_root}/docker/tsan/" + fi +} + +case "${subcommand}" in + rebuild-image) + docker build --no-cache -t "${image_tag}" "${repo_root}/docker/tsan/" + ;; + + shell) + ensure_image + docker run --rm -it \ + -v "${repo_root}:/work/RandBLAS" \ + "${image_tag}" + ;; + + build-and-test) + ensure_image + # Mount the source read-only so the in-container build dir can't pollute + # the host tree; build artifacts live in a separate volume so they + # survive between runs and don't clash with the macOS host build. + docker run --rm \ + -v "${repo_root}:/work/RandBLAS:ro" \ + -v "randblas-tsan-build:/work/build" \ + "${image_tag}" \ + bash -c ' + set -euxo pipefail + cd /work/build + cmake \ + -DCMAKE_C_COMPILER=clang \ + -DCMAKE_CXX_COMPILER=clang++ \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_CXX_FLAGS="-fsanitize=thread -fno-omit-frame-pointer" \ + -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=thread" \ + -Dblaspp_DIR="${blaspp_DIR}" \ + -DRandom123_DIR="${Random123_DIR}" \ + /work/RandBLAS + make -j"$(nproc)" + # ignore_noninstrumented_modules=1 silences spurious reports + # against blaspp/openblas/libomp/libc, none of which are built + # with TSan. Without it, the run drowns in false positives. + OMP_NUM_THREADS=4 \ + TSAN_OPTIONS="halt_on_error=0 ignore_noninstrumented_modules=1 second_deadlock_stack=1" \ + ctest --output-on-failure -E test_rng_speed + ' + ;; + + *) + echo "usage: $0 [shell | build-and-test | rebuild-image]" >&2 + exit 1 + ;; +esac diff --git a/test/downstream/CMakeLists.txt b/test/downstream/CMakeLists.txt new file mode 100644 index 00000000..b688d070 --- /dev/null +++ b/test/downstream/CMakeLists.txt @@ -0,0 +1,16 @@ +# Minimal downstream-consumer smoke test for find_package(RandBLAS). +# +# This is NOT part of the in-tree test build. It is configured separately by +# .github/workflows/downstream-consumer.yml against an *installed* RandBLAS, so +# that the install/export rules in RandBLAS/CMakeLists.txt are exercised the +# way a real downstream project would exercise them. +cmake_minimum_required(VERSION 3.11) +project(randblas_downstream_smoke CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(RandBLAS REQUIRED) + +add_executable(smoke main.cc) +target_link_libraries(smoke PRIVATE RandBLAS) diff --git a/test/downstream/main.cc b/test/downstream/main.cc new file mode 100644 index 00000000..142fdbbe --- /dev/null +++ b/test/downstream/main.cc @@ -0,0 +1,21 @@ +// Downstream consumer smoke test for find_package(RandBLAS). +// +// The pattern below is taken directly from +// examples/total-least-squares/tls_dense_skop.cc (lines 56-62, the +// init_noisy_data routine) so it tracks real working RandBLAS usage rather +// than a hand-rolled snippet. Goal: catch breakage in the install/export +// path, not exercise numerical behavior — keep it tiny. +#include + +int main() { + constexpr int64_t m = 16; + constexpr int64_t n = 4; + + double A[m * n]; + + RandBLAS::DenseDist Dist_A(m, n); + RandBLAS::RNGState state(0); + RandBLAS::fill_dense(Dist_A, A, state); + + return 0; +} From fba2221c8b945f2fd072fb7505c4b5571f399319 Mon Sep 17 00:00:00 2001 From: Riley Murray Date: Mon, 25 May 2026 09:52:47 -0700 Subject: [PATCH 4/5] update CI builds that test using RandBLAS in a downstream project --- .github/workflows/downstream-consumer.yml | 2 +- .github/workflows/examples.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/downstream-consumer.yml b/.github/workflows/downstream-consumer.yml index 9490c430..9e316787 100644 --- a/.github/workflows/downstream-consumer.yml +++ b/.github/workflows/downstream-consumer.yml @@ -47,7 +47,7 @@ jobs: cd build cmake \ -DCMAKE_BUILD_TYPE=Release \ - -DRandBLAS_DIR="$(pwd)/../../../../RandBLAS-install/lib/cmake" \ + -DCMAKE_PREFIX_PATH="$(pwd)/../../../../RandBLAS-install" \ -Dblaspp_DIR="${blaspp_DIR}" \ -DRandom123_DIR="${Random123_DIR}" \ .. diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 4224140a..a9a34f45 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -48,7 +48,7 @@ jobs: cd build cmake \ -DCMAKE_BUILD_TYPE=Release \ - -DRandBLAS_DIR="$(pwd)/../../../RandBLAS-install/lib/cmake" \ + -DCMAKE_PREFIX_PATH="$(pwd)/../../../RandBLAS-install" \ -Dblaspp_DIR="${blaspp_DIR}" \ -Dlapackpp_DIR="${lapackpp_DIR}" \ -DRandom123_DIR="${Random123_DIR}" \ From 34fbd6fb7bc42bb504b5a0d7e1fc6323c190050e Mon Sep 17 00:00:00 2001 From: Riley Murray Date: Mon, 25 May 2026 09:59:33 -0700 Subject: [PATCH 5/5] bugfix in example --- examples/simple-kernel-benchmarks/spmm_performance.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/simple-kernel-benchmarks/spmm_performance.cc b/examples/simple-kernel-benchmarks/spmm_performance.cc index 03bb7c43..ecdcf8e6 100644 --- a/examples/simple-kernel-benchmarks/spmm_performance.cc +++ b/examples/simple-kernel-benchmarks/spmm_performance.cc @@ -101,10 +101,10 @@ void handrolled_left_spmm_csr( Layout layout_opB = layout; // opB == NoTrans Layout layout_C = layout; if (layout_opB == Layout::RowMajor && layout_C == Layout::RowMajor) { - RandBLAS::sparse_data::csr::apply_csr_left_ikb_p1b_rowmajor( + RandBLAS::sparse_data::csr::apply_csr_ikb_p1b_rowmajor( alpha, d, n, m, A, B, ldb, C, ldc); } else { - RandBLAS::sparse_data::csr::apply_csr_left_jik_p11( + RandBLAS::sparse_data::csr::apply_csr_jik_p11( alpha, layout_opB, layout_C, d, n, m, A, B, ldb, C, ldc); } }