Backend Picker (glass-defaults.cuh)#

Queryable backend-selection defaults — the measured thread / warp / block / nvidia ladder (bench/RESULTS.md) exposed as constexpr helpers, so callers and GRiD-style codegen pick a backend + launch config instead of hand-copying a table.

The pick cannot be a device function: the tiers need different <<<grid, block>>> launches, so the decision happens host-side / at codegen time. See Tuning for Your Hardware for the underlying numbers.

Distinct from this launch-level advisor, the tiny glass-dispatch.cuh header (included by both glass.cuh and this one; shared glass::op enum) carries glass::dispatch_body() — the measured in-block body table behind the bare glass::op face, applied automatically by the wrappers in src/base/dispatch.cuh under a fixed launch. See Namespaces, suffixes, and flags.

Note

backend::thread is measured and shipped for sm_120 (2026-07-18 quiet-GPU sweep): the thread tier takes the low-DOF corner of every op except gemm — up to 7.5× on posv f64 at N≤6 (the docs sweep-results page has the full verdicts). A thread pick means a thread-per-problem launch: <<<ceil(P/TPB), TPB>>> with suggested_threads_per_block<>(). The ideal_generic fallback for unswept arches remains warp/block/nvidia-only.

Include order#

Include glass-defaults.cuh after glass.cuh, and after glass-nvidia.cuh if you want the nvidia tier to be eligible (it reads GLASS_HAVE_CUBLASDX / GLASS_HAVE_CUSOLVERDX). With only glass.cuh linked, the nvidia tier collapses to its warp/block runner-up, so a no-MathDx caller always gets a backend it can launch.

Helpers#

enum class glass::op      { dot, gemv, gemm, chol, trsv, posv };
enum class glass::backend { warp, block, nvidia, thread };  // thread appended: pre-existing ordinals unchanged

// Which backend for (op, N, T) on this SM? (nvidia only when the vendor lib is linked)
template <op Op, uint32_t N, typename T, uint32_t SM = GLASS_DEFAULTS_SM>
constexpr backend  glass::suggested_backend();

// For the `block` backend: factor/solve want 32; gemm grows with N; dot/gemv 64–128.
template <op Op, uint32_t N, typename T = float, uint32_t SM = GLASS_DEFAULTS_SM>
constexpr uint32_t glass::suggested_block_threads();

// For the `warp` backend: dot packs 8; others 2 warps/block.
template <op Op, uint32_t N = 0, typename T = float, uint32_t SM = GLASS_DEFAULTS_SM>
constexpr uint32_t glass::suggested_warps_per_block();

// For the `thread` backend: launch <<<ceil(P/TPB), TPB>>>, one problem per thread.
// Seed heuristic (shrinks as N*N registers/thread grow), NOT measured by the ladder leg.
template <op Op, uint32_t N = 0, typename T = float, uint32_t SM = GLASS_DEFAULTS_SM>
constexpr uint32_t glass::suggested_threads_per_block();

Example#

#include "glass.cuh"
#include "glass-defaults.cuh"   // (after glass-nvidia.cuh too, to allow the nvidia tier)

constexpr auto be = glass::suggested_backend<glass::op::chol, N, float>();
if      constexpr (be == glass::backend::nvidia) { /* cuSOLVERDx launch */ }
else if constexpr (be == glass::backend::warp)   { /* <<<ceil(P/WPB), {32,WPB}>>> */ }
else /* block */ {
    constexpr int TB = glass::suggested_block_threads<glass::op::chol, N, float>();
    /* <<<P, TB>>> */
}

A runnable version is examples/08_backend_picker.cu.

Per-host override#

The shipped tables are per-arch: each swept SM has its own constexpr ladder (ideal_sm120 today, measured on an RTX 5090) behind an SM dispatch, and running bench/tune.py --sm auto on a new GPU (e.g. a Jetson Orin, sm_87) adds that arch’s table + dispatch case in-tree without touching the others; unmeasured SMs fall back to a coarse heuristic. Alternatively, for a host-local override that leaves the shipped tables alone, regenerate a table from a sweep run and point GLASS_DEFAULTS_TABLE_LOCAL at it:

cd bench && ./run_mega_sweep.sh sm_XX
python3 autotune.py --emit-defaults mega_sweep_<ts>.txt        # -> bench/tuning/<host>_defaults.cuh
nvcc ... -DGLASS_DEFAULTS_TABLE_LOCAL='"bench/tuning/<host>_defaults.cuh"' ...

bench/explore_sweep.ipynb visualizes a sweep (ladder plot + winner table); Backend Sweep Results shows the rendered ladder + winner table the defaults are seeded from.