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.