Status: current · moved from the project README on 2026-10-09.
Requirements, tested platforms, CMake presets and options, the test and benchmark builds, the Python package and the install traps. Calling the library and linking an installed package are in the C++ API ("Building and installing BatchLAS", "Building against BatchLAS").
Warning: the SYCL compiler must have a backend for your GPU vendor. Stock Intel oneAPI icpx has no CUDA adapter: on an NVIDIA machine it configures cleanly, prints -- Using SYCL targets: spir64_x86_64, and builds a CPU-only library without warning. Use the Codeplay oneAPI for NVIDIA GPUs plugin on top of oneAPI, or a self-built intel/llvm configured with --cuda. sycl-ls must list a [cuda:gpu] entry.
Package suggestions and oneAPI notes: Agent environment guide.
Only the Primary configuration is exercised regularly; everything else is untested rather than known-good. .github/workflows/ci.yml runs static checks on GitHub-hosted runners (no SYCL compiler there, so nothing is configured or compiled) and a self-hosted GPU job on the Primary machine: configure with CUDA required, build all libraries and tests, ctest, install, check the export. A nightly job on that runner adds slow suites, the consumer packaging test and a vendor-free build.
| Compiler | CUDA | GPU / arch | OS | Status | |
|---|---|---|---|---|---|
| Primary | intel/llvm DPC++, clang 22.0.0git, built with --cuda (installed at /opt/dpcpp-cuda) | 13.2 | NVIDIA RTX 4090, sm_89 | Ubuntu 22.04 | Library, tests and benchmarks built and run here daily |
| Second GPU box | same toolchain (threadripper02) | 13.2 | NVIDIA RTX PRO 6000, sm_120 | Linux | Built and tested; sm_120 tuning tables measured here |
| CI — static checks | none (no toolchain) | — | none | ubuntu-latest | List files, source-level export and public headers only; nothing configured, compiled or run |
| CI — GPU gate | the Primary row's toolchain, on a self-hosted runner on that machine | 13.2 | NVIDIA RTX 4090, sm_89 | Ubuntu 22.04 | Build + ctest -LE slow + install on every push and non-fork PR; full ctest, packaging and a vendor-free build nightly |
| CPU only | Intel oneAPI icpx 2025.x | — | none (spir64_x86_64 / native_cpu) | Ubuntu 22.04 | Configures and builds; no NVIDIA support (see the warning above). Not built by CI |
| AMD / ROCm | — | — | — | — | Code paths exist; not built or run |
| Apple GPU (macOS) | AdaptiveCpp develop at 9ec394ef plus local patches 0001-0013 (below), Homebrew llvm@21 21.1.8 / lld@21, Command Line Tools only (no Xcode) | — | Apple M5 Max (applegpu_g17s), Metal | macOS 27.0.1 | Library and full test suite built and run (acpp-metal-tests); float and complex<float> on the GPU, double on the host through Homebrew OpenBLAS 0.3.34. Not built by CI |
| Windows | — | — | — | — | Untested |
Other NVIDIA architectures should work: the build detects the local GPU, and -DBATCHLAS_NVIDIA_ARCH=sm_XX overrides it.
main has known test failures, so the GPU job diffs each run against the ledger tests/known-failures.txt instead of using ctest's exit code. See the CI page for coverage, self-hosted runner setup and retiring a ledger entry.
| preset | builds |
|---|---|
| dev | default RelWithDebInfo library |
| dev-tests | library plus the full test suite |
| fast-dev | library plus the smoke-test subset |
| benchmarks | benchmarks and the table tuner (tools/tune) |
| cuda | dev-tests with BATCHLAS_ENABLE_CUDA=AUTO (not ON: without a [cuda:gpu] it still configures, CPU-only) and BATCHLAS_ALLOW_UNSAFE_ENV=OFF; the pre-push gate |
| dev-gpu / dev-gpu-tests | drop the native_cpu SYCL target (BATCHLAS_CPU_TARGET=none) |
| release | Release, no tests or benchmarks, one shared library |
| acpp / acpp-tests | dev / dev-tests built with the AdaptiveCpp 25.10 driver (--acpp-targets=generic) into build-acpp / build-acpp-tests (SYCL implementations) |
| acpp-metal / acpp-metal-tests | macOS only: Apple GPU through AdaptiveCpp Metal into build-acpp-metal / build-acpp-metal-tests (macOS); the test preset runs ctest serially |
BATCHLAS_ALLOW_UNSAFE_ENV is ON in every preset that inherits dev (dev, dev-tests, fast-dev, benchmarks, dev-gpu*, acpp*), which exist to measure and debug, and OFF in cuda and release, which run the arm a release build runs.
dev-gpu is 13-25% off a cold build of the default target on one 4-GPU box, but it is GPU coverage only: about half of every typed test suite is not instantiated and ctest still reports green. Use dev-tests or cuda for the pre-push gate, plus a vendor-free tree (-DBATCHLAS_ENABLE_VENDOR_BLAS=OFF) at that gate only.
| option | meaning |
|---|---|
| BATCHLAS_BUILD_TESTS | build unit tests |
| BATCHLAS_BUILD_BENCHMARKS | build benchmark executables and batchlas_tune |
| BATCHLAS_BUILD_PYTHON | build the Python package |
| BATCHLAS_ENABLE_CUDA | AUTO (default; enable cuBLAS/cuSOLVER when the SYCL runtime exposes a CUDA device), ON (require it; configure fails without an NVIDIA target, see "Device and toolkit detection") or OFF. Boolean spellings are accepted (1/TRUE/YES mean ON, 0/FALSE/NO mean OFF); an existing cache entry keeps its value |
| BATCHLAS_ENABLE_VENDOR_BLAS | the one switch over every vendor library (cuBLAS/cuSOLVER/cuSPARSE, rocBLAS/rocSOLVER/rocSPARSE, netlib LAPACKE/CBLAS), re-read on every configure; OFF builds the vendor-free library (vendor-free status). The three CUDA libraries are all-or-nothing: a toolkit missing one fails configure |
| BATCHLAS_MONOLITHIC_LIBRARY | one libbatchlas.so instead of the per-component libraries (default OFF; the release preset turns it on) |
| BATCHLAS_ALLOW_UNSAFE_ENV | honour the BATCHLAS_* overrides that disable a safety check (batchlas::Settings::unsafe; default OFF, see "Presets") |
| BATCHLAS_DISABLE_CUDA_FTZ | no flush-to-zero in CUDA device code (default ON) |
| BATCHLAS_KEEP_CUDA_INTERMEDIATES | keep CUDA/SYCL device intermediates for PTX/SASS analysis (default OFF) |
| BATCHLAS_SANITIZER_FRIENDLY_DEBUG | unwind-friendly debug flags for sanitizer runs (default OFF) |
| BATCHLAS_OPENBLAS_CORETYPE | OPENBLAS_CORETYPE that ctest sets to avoid a broken OpenBLAS kernel; empty means none (set by the health check) |
| BATCHLAS_BUILD_DOCS | add the batchlas_docs target (scripts/build_docs.sh) |
| BATCHLAS_BUILD_DEVICE_BLAS_BENCHMARKS | build the device_blas_* benchmarks (default OFF) |
| BATCHLAS_STRIP_RELWITHDEBINFO_G | drop the toolchain's -g from CMAKE_CXX_FLAGS_RELWITHDEBINFO (default ON; BatchLAS adds -gline-tables-only; full DWARF in device images has failed CUDA JIT program builds) |
| BATCHLAS_ENABLE_ROCM | enable ROCm backend support even if no AMD GPU is detected |
| BATCHLAS_CPU_TARGET | SYCL CPU target: auto, native_cpu, spir64_x86_64, none |
| BATCHLAS_TEST_TARGET_SET | all or smoke |
| BATCHLAS_AMD_ARCH | override ROCm target architecture |
| BATCHLAS_NVIDIA_ARCH | empty (default): the detected NVIDIA GPUs; sm_XX: build that architecture instead (cross builds, no GPU needed). The old default sm_50 is read as empty |
| BATCHLAS_USE_CCACHE | cache compilations with ccache when on PATH or in ~/.local/bin (default ON; your own CMAKE_CXX_COMPILER_LAUNCHER wins) |
| BATCHLAS_CCACHE_SHARE_ACROSS_TREES | let sibling checkouts and worktrees share cache entries (default ON; turn off for source-level debugging) |
| BATCHLAS_CCACHE_MAXSIZE | ccache size limit (default 20G) |
| BATCHLAS_CCACHE_BASEDIR | ccache base directory (default: deepest common parent of source and build directories, or $HOME if that is /) |
| BATCHLAS_TEST_GPUS | GPUs written to <build>/ctest_resources.json for scripts/ctest_gpus.sh: auto (nvidia-smi --list-gpus), a count, or 0 to disable. Needs a [cuda:gpu] in sycl-ls, else a count is a configure error |
| BATCHLAS_TEST_GPU_SLOTS | concurrent GPU tests per device under scripts/ctest_gpus.sh |
| BATCHLAS_SYCL_LINK_JOBS | parallelism of the DPC++ SYCL device link (default 4, 1 disables) |
| BATCHLAS_SYCL_IMPL | AUTO (default; ACPP when CMAKE_CXX_COMPILER is the acpp driver), DPCPP or ACPP. Only the matching compiler is accepted; ACPP without an acpp compiler takes acpp from PATH, else /opt/adaptivecpp/bin, also replacing a cached compiler (ccmake); CMake then resets the cache and the value reads AUTO |
| BATCHLAS_ACPP_TARGETS | --acpp-targets of an AdaptiveCpp build (default generic) |
| BATCHLAS_ENABLE_METAL | AdaptiveCpp only: AUTO (default; dispatch an Apple GPU as Backend::SYCL when acpp-info lists a Metal device), ON (require it; configure fails without one) or OFF (needs the GPU hidden with ACPP_VISIBILITY_MASK=omp; configure fails while acpp-info lists it) |
| BATCHLAS_DEVICE_FP64 | AUTO (default), ON or OFF: instantiate double and complex<double> for Backend::SYCL. AUTO resolves to OFF when Metal is enabled, and ON with Metal is a configure error. CUDA, ROCm and the host always keep all four types |
| BATCHLAS_OPENBLAS_ROOT | OpenBLAS prefix whose libopenblas provides LAPACKE and CBLAS. On macOS it is probed at /opt/homebrew/opt/openblas and /usr/local/opt/openblas; set it, the headers go on the library's include path. Empty on Linux by default, which keeps the system LAPACKE |
| BATCHLAS_MONOLITHIC_LIBRARY | one shared library instead of the component libraries (the release shape). Required on macOS: ld64 rejects the components' cyclic undefined symbols |
| BATCHLAS_HIDDEN_VISIBILITY | -fvisibility=hidden on the monolithic library (default ON; only with BATCHLAS_MONOLITHIC_LIBRARY). OFF lets the in-tree tests link against it, since they reach about 1,000 unexported internal symbols |
| BATCHLAS_ACPP_SLM_OPTIN | AdaptiveCpp + CUDA: a launch interposer that opts kernels into more than 48 KiB of local memory (default OFF; SYCL implementations) |
Configure needs only the compiler (-DCMAKE_CXX_COMPILER=<dpcpp>/bin/clang++, icpx, or -DBATCHLAS_SYCL_IMPL=ACPP); no setvars.sh, LD_LIBRARY_PATH, CUDA_PATH or nvcc on PATH.
The Apple GPU runs through AdaptiveCpp's Metal backend. Kernels are compiled once to generic SSCP IR and JIT-translated to Metal Shading Language at their first launch. Design, limits and patches: AdaptiveCpp Metal.
| On an Apple GPU Queue | On a CPU Queue | |
|---|---|---|
| Backend | Backend::SYCL: native kernels only, no vendor GPU library (no MPS) | Backend::NETLIB: Homebrew OpenBLAS (LAPACKE, CBLAS) plus native kernels on the AdaptiveCpp OpenMP device |
| Types | float and complex<float>. A double or complex<double> call throws batchlas::unsupported before any launch | all four |
| Not available | hemm, herk, her2k (NoRouteError: they have no native family yet); any shape whose every family needs more local memory than Apple's 32 KiB, or than a can_run occupancy slice of it (cfloat Upper potrf/posv at n=24 to about 50) | — |
batchlas::verify and the queue-less Matrix helpers run their double arithmetic on the CPU device (verification).
Toolchain. Needs the Command Line Tools and Homebrew; Xcode is not needed. The script installs cmake llvm@21 lld@21 libomp boost openblas python with brew, fetches metal-cpp, checks out AdaptiveCpp develop at 9ec394ef on the local branch batchlas-metal, applies scripts/macos/adaptivecpp-patches/*.patch with git am, then builds and installs:
| Variable | Default | Meaning |
|---|---|---|
| ACPP_SRC | ~/opt/src/AdaptiveCpp | source checkout |
| ACPP_PREFIX | ~/opt/adaptivecpp | install prefix; the presets read $HOME/opt/adaptivecpp/bin/acpp |
| METAL_CPP_DIR | ~/opt/src/metal-cpp | metal-cpp headers (downloaded when missing) |
| ACPP_BASE / ACPP_BRANCH | 9ec394ef / batchlas-metal | upstream commit and the local patch branch |
| ACPP_REAPPLY=1 | off | recreate the branch from the patch files. An existing branch is otherwise reused, and the script stops if its commit count differs from the number of patches |
| SKIP_BREW=1 | off | skip brew install |
The script configures AdaptiveCpp as its upstream macOS CI does (ACPP_COMPILER_FEATURE_PROFILE=full, Metal on, CUDA/ROCm/OpenCL/Level Zero off), with Homebrew opt/ paths so a patch-level brew upgrade does not leave stale Cellar/ paths in etc/AdaptiveCpp/acpp-core.json; it warns if any remain. It then pins the acpp, syclcc and syclcc-clang shebangs to Homebrew's python3. The patches are local only and not sent upstream; what each fixes, with its evidence, is in scripts/macos/adaptivecpp-patches/README.md.
Build and test.
The presets set ACPP_VISIBILITY_MASK=omp;metal (configure and ctest), BATCHLAS_ENABLE_METAL=ON, BATCHLAS_DEVICE_FP64=OFF, BATCHLAS_ENABLE_VENDOR_BLAS=ON (on macOS the only vendor library is netlib: LAPACKE and CBLAS from /opt/homebrew/opt/openblas for the CPU Queue; the Apple GPU has no vendor family either way), BATCHLAS_MONOLITHIC_LIBRARY=ON with BATCHLAS_HIDDEN_VISIBILITY=OFF, and BATCHLAS_TEST_GPUS=0. acpp-metal-tests also sets CMAKE_DISABLE_FIND_PACKAGE_GTest=ON, so GoogleTest is fetched and built by acpp against Homebrew LLVM's libc++, never a system GoogleTest built by another compiler. Configure prints Native SYCL GPU backend (Metal): TRUE; device fp64: OFF.
A full serial ctest takes about an hour; the first launch of each kernel pays the MSL translation and the Metal compile. The failure ledger of this tree is tests/known-failures-acpp-metal.txt, which .github/ci/compare_failures.py --build-dir build-acpp-metal-tests picks from the cached BATCHLAS_GPU_FAMILY_RESOLVED=METAL. The macOS traps (adaptivity level, the JIT cache, DYLD_ paths, the CPATH leak) are in Agent environment guide, "Known Pitfalls".
Warning: every tuning table and constant was measured on NVIDIA GPUs. An Apple GPU has no table of its own: it is keyed apple_m5_max, borrows the nearest table and warns once per op. Its routes are hypotheses until the device is tuned.
fast-dev builds only the smoke subset (util_span_tests, util_vector_tests, matrix_tests, mempool_tests, backend_dispatch_tests, options_api_tests, settings_tests, linalg_layer_tests; BATCHLAS_SMOKE_TEST_TARGETS in tests/CMakeLists.txt). None covers a specific algorithm. To iterate on one algorithm, build the library plus that one test:
With a [cuda:gpu] in sycl-ls, scripts/ctest_gpus.sh runs one test per GPU slot. Labels, the smoke set and the GPU slots: tests/README.md.
Benchmarks (BLAS kernels, QR/SVD, eigensolvers, band reduction, sparse) live in benchmarks/:
With BATCHLAS_BUILD_BENCHMARKS=ON the benchmark translation units join the default all target, so leave the option OFF in trees you iterate on. To build only them, or one:
Measurement rules (saturation, warm-up, one process per box): Agent environment guide.
The importable package lands in build/python and links against the in-tree BatchLAS::batchlas. It has NumPy dense-array support, SciPy sparse wrappers, available_backends(), available_devices(), compiled_features() and elementwise arithmetic (add, subtract, multiply, divide, axpby, scale). Twelve self-checking notebooks in python/examples/ are committed with output:
The consumer CMake recipe, the same-compiler rule, -fsycl flags and LD_LIBRARY_PATH are in the C++ API; Consuming BatchLAS from an outside CMake project is a runnable outside project. Three more traps:
| directory | contents |
|---|---|
| include/ | public C++ headers |
| src/ | library; src/ops/<op>/ holds each op's entry point, choices and launchers, src/select/ the table lookup |
| tuned/ | per-device selection tables (Tuned selection tables) |
| tools/tune/ | batchlas_tune, the table generator (batchlas_tune) |
| tests/ | GoogleTest unit tests and the smoke subset |
| benchmarks/ | performance and accuracy benchmarks; raw results in benchmarks/results/ (Git LFS) |
| python/ | pybind11 bindings, Python facade, tests, examples/ |
| scripts/ | campaign, result-processing and CI helpers |
| playground/ | Python reference implementations cited by the band-reduction and sb2st sources |
| examples/ | a minimal external CMake consumer |
| evaluation/ | tuning-constant and perf-regression harnesses; not built, not installed |
| docs/ | this site; docs/Doxyfile and docs/theme/ build it |