cheatah-gpu-linalg
cheatah-gpu-linalg v0.4.5-alpha — Biome Standard 0.6.5-alpha
GPU linear algebra (the linalg device backend)
Depends on: cheatah (toolchain v1.11.4-alpha) · cheatah-gpu
GPU-accelerated linear algebra for cheatah — a device backend for its stdlib/linalg, built on the cheatah-gpu Metal/Vulkan surface.
How it plugs in
cheatah's stdlib/linalg is one two-layer template per operation — template <ndarray::Field T, template <typename> class Array> … Array<T> … — and chooses host vs device at compile time with zero runtime cost and without ever naming a device type:
- an array-like models a structural
ArrayLikesurface (host-resident shape/strides/size/offset), and - it advertises *where its elements live* through the
location_oftrait. cheatah defines only the host tag; a device extension defines its own tag and specializeslocation_of.
This library is that extension. It provides:
1. cheatah::gpu::linalg::device_array<T> — a dense, row-major, GPU-resident array whose elements live in a cheatah-gpu buffer while its shape/strides stay on the host. 2. one location_of specialization — the entire opt-in; it makes device_array<T> satisfy cheatah::linalg::DeviceArray (and *not* HostArray). 3. device routine overloads (matmul, …) constrained requires DeviceArray<Array<T>>, in device_array's namespace, so cheatah's allocating fronts dispatch to them by ADL — no CPO, no tag, no ambiguity.
The result: cheatah::linalg::matmul(dev_a, dev_b) runs on the GPU with no extra plumbing.
#include "cheatah_gpu_linalg/cheatah_gpu_linalg.hpp"
namespace gl = cheatah::gpu::linalg;
auto a = gl::device_array<double>::from_host({M, K}, host_a);
auto b = gl::device_array<double>::from_host({K, N}, host_b);
gl::device_array<double> c = cheatah::linalg::matmul(a, b); // runs on the GPU
c.to_host(out);Kernels: Slang, once — both backends
Every kernel is written ONCE in Slang (kernels/linalg.slang) and compiled per backend at build time by slangc (ships in the Vulkan SDK):
| backend | kernel artifact | runs on | |---------|-----------------|---------| | Vulkan (cheatah_gpu_linalg_vulkan) | SPIR-V, one .spv per entry × element | any Vulkan device — discrete/integrated GPUs, llvmpipe | | Metal (cheatah_gpu_linalg_metal), Apple | slang-generated MSL, runtime-compiled | the Apple GPU | | Metal, off Apple | *(source ignored)* | cheatah-gpu's software-emulated device runs the C++ stand-ins in kernels.hpp |
The routine/container code never names a backend — context.hpp picks the implementation (CHEATAH_GPU_LINALG_VULKAN ⇒ vulkan_context.hpp, else metal_context.hpp), both exposing the same new_buffer / contents / dispatch_1d / dispatch_2d surface built on cheatah-gpu's vk.* / mtl.* forwarders and its gpu.dispatch workgroup math.
Vulkan device selection prefers discrete > integrated > CPU; force one with CHEATAH_GPU_LINALG_VK_DEVICE=<name substring | index> (e.g. llvmpipe). *_f64 kernels need the device's shaderFloat64 feature (NVIDIA/llvmpipe: yes; Intel Xe: f32 only — a clean throw says so).
Status
The full cheatah::linalg surface works with device_array operands. Three tiers:
- Device kernels (real f32/f64 + complex c64/c128, Slang-single-source):
matmul(register-tiled GEMM, 9.55 TFLOP/s f32 on an RTX 3070 Ti Laptop — 67% of that part's measured 14.2 TFLOP/s FFMA ceiling — plus an opt-in KHR cooperative-matrix (tensor-core) f16-in/f32-accumulate path at 21.5 TFLOP/s; both medians over 5 interleaved repetitions, see PERFORMANCE.md; batched[B,M,K]@[B,K,N]in one z-dispatch),outer,conj_transpose(true Hermitian adjoint for complex),kron,dot/vdot(conjugating for complex)/inner,trace— reductions are deterministic partial sums with a two-stage tree path above 64k elements (305+ GB/s). - Elementwise device ops (f32/f64) with OPERATORS —
a + b,2.0 * a,a += bresolve by ADL exactly as purr's codegen emits them: add/sub/mul/divide (array⊗array strict-shape, array⊗scalar both orders), sqrt/exp/log/abs (f64 exp/log host-evaluated — SPIR-V has no f64 transcendentals),sum/mean, and the fusedaxpy(α·x + y in one dispatch — ≈4× the chained form). No general broadcasting yet (scalar broadcast only). - Conv-support device kernels (f32/f64,
conv.hpp):im2col2d/col2im2d(the zero-padded receptive-field gather and its deterministic gather-form adjoint — no atomics) and the fusedconv_bias_act/conv_act_gradepilogues (bias + activation {identity, relu, tanh, sigmoid} + the filter-major ↔ sample-major layout transpose in one dispatch each, derivatives evaluated from the output) — a conv layer's staging and epilogues stay device-resident around the GEMM. - Host-bridged factorizations (
bridge.hpp— EXECUTE ON THE HOST, honestly labelled): cholesky, qr, svd, svdvals, eig, eigvals, eigh, eigvalsh, solve, lstsq, inv, pinv, matrix_power, det, slogdet, cond, matrix_rank, norm — download → cheatah's host algorithm → upload, so device-resident code can call the whole surface; complex comes free.
Memory model: device_array data lives in DEVICE-LOCAL memory (VRAM) on Vulkan with staged transfers; scratch (dims/scalars/partials) and every released buffer recycles through a pooled allocator (a dispatch costs ~30 µs end to end, down from ~1.4 ms unpooled; 23.5 µs of that is the fence wait, which is the floor).
Every op is tested on BOTH backends (gpu:<op>:vk / :mtl), scripts/qa.sh is the full gate (both backends + forced-llvmpipe + ASan/UBSan + Valgrind + 100% doc coverage + 100% unit coverage + cppcheck + a perf-ratchet report), and PERFORMANCE.md holds the honest numbers + bench/ the suite (compare.py cross-checks answers against NumPy/PyTorch before timing anything).
Not yet: general broadcasting, true device factorizations, streaming e2e transfers, real-Apple validation — see PERFORMANCE.md's named next steps. (Cooperative-matrix tensor-core GEMM was on this list long after it shipped; it is listed above, where it belongs. No Apple performance number exists or is claimed.)
Build
cmake -S . -B build -G Ninja # finds ../cheatah, ../cheatah-gpu and the Vulkan SDK by default
cmake --build build -j
ctest --test-dir build --output-on-failure # every op, both backends
bash scripts/qa.sh # the full QA gateOverride sibling locations with -DCHEATAH_DIR=…, -DCHEATAH_GPU_DIR=…, metal-cpp with -DCHEATAH_GPU_METAL_CPP=… (vendored in cheatah-gpu by default), and the SDK with -DCHEATAH_GPU_LINALG_VK_ROOT=… (defaults to $VULKAN_SDK, then the newest ~/Tools/vulkan-sdk/*/x86_64).
Coverage
Clang source-based coverage of the unit suite over the backend-neutral headers (the two backend bring-up headers are excluded the way cheatah-gpu excludes its driver layers — they need real driver matrices). Enforced at 100% lines + functions by scripts/qa.sh.
<!-- coverage:start --> | Metric | neutral surface | |--------|-----------------| | Lines | 100.00% (1322/1322) | | Functions | 100.00% (139/139) | | Regions | 92.80% | | Branches | 79.49% | <!-- coverage:end -->
License
MIT — Copyright (c) 2026 BigBrain LLC. See LICENSE and NOTICE.
Security
Single-trust threat model (the cheatah household standard): the embedding process is trusted, its inputs may still be wrong — robustness bugs at the API boundary are treated as security bugs. See SECURITY.md for the policy and SECURITY-AUDIT-v0.3.0.md for the latest full audit (element-count overflow caps, transfer bounds, dispatch limits, the vec4 tail invariant, loader surfaces, fusing discipline).
Modules
| Module | What it gives you |
|---|---|
gpu.linalg | |
gpu.linalg.kernels | |
gpulinalg |
