Status: current · RTX 4090 (sm_89), CUDA 13.2, /opt/dpcpp-cuda
include/batchlas/tuning_params.hh holds the kernel parameters that depend on problem order n. The shipped values come from the 2026-08-07 retune (924b3a59). Every constant was measured on sm_89, in float, through evaluation/tuning/: treat them as hypotheses on other GPUs and for other scalar types. Per-op sweep numbers live on the op pages linked in where the per-op sweeps live.
Each tunable quantity has five constants, one per size bucket of n, and a constexpr table function <knob>_default_for_n(n) that picks one:
| bucket | n |
|---|---|
| TINY | n <= 64 |
| SMALL | 64 < n <= 128 |
| MEDIUM | 128 < n <= 256 |
| LARGE | 256 < n <= 512 |
| XLARGE | n > 512 |
| family | consumer | meaning of 0 |
|---|---|---|
| ORMQR_BLOCK_SIZE_* | ormqr WY block width | n/a |
| GEBRD_BLOCK_SIZE_* | gebrd panel width in gesvd | n/a |
| SB2ST_BACK_TILE_*, SB2ST_BACK_SUBS_* | sb2st wave back-transform geometry | keep the shape-adaptive heuristic in sytrd_sb2st_hh.cc (all ship 0) |
| SY2SB_ORMQR_NB_* | WY width of the sy2sb panel back-transform | keep the shape gate in sytrd_sy2sb.cc |
| SYTRD_BLOCK_SIZE_* | sytrd panel width | n/a |
| LATRD_LOWER_PANEL_WG_HINT_* | latrd lower-panel work-group size | no hint |
| SYTRD_FUSE_PANEL_UPDATE_* | fused panel update on/off | off |
| STEDC_RECURSION_THRESHOLD_* | stedc leaf size | n/a; 32 is the CTA invariant, not a tuning result |
| STEDC_MERGE_VARIANT_* | StedcMergeVariant (1 Fused, 2 FusedCta) | Auto, never returned (see below) |
| STEDC_THREADS_PER_ROOT_*, STEDC_WG_MULTIPLIER_* | stedc secular-solve geometry | n/a |
Production code calls the runtime accessors <knob>_for_n(n). Each consults its BATCHLAS_TUNE_* override first and falls back to the table. latrd_lower_panel_wg_hint() pins n to 256 for the legacy path. sytrd_fuse_panel_update_for_n has no override; its control is BATCHLAS_SYTRD_FUSE_PANEL_UPDATE, which is tri-state (Environment variables).
The harness (BatchLAS tuning harness (bottom-up)) grid-searches benchmark executables per bucket and writes a JSON profile. evaluation/tuning/generate_tuning_header.py turns per-case winners into bucket constants. A retune takes about 12 minutes. Every group is A/B'd end to end at its consumers before adoption; see the 2026-08-07 constant retune.
Tuning was float-only. The constants apply unchanged to double, complex<float> and complex<double>. When another type looks bad, sweep that type first. Per-type corrections live at the consumer, where a retune cannot overwrite them:
Before trusting "no change" from a knob, check for a second consumer (aliasing) or a bypass on the measured path (shadowing). See knobs that shadow each other.
Each runtime accessor passes its captured settings().geometry.tune.<field> and the table value to detail::tuning_env_override. One process can therefore A/B a retune without a rebuild. The eleven variables are BATCHLAS_TUNE_{ORMQR_BLOCK_SIZE, GEBRD_BLOCK_SIZE, SB2ST_BACK_TILE, SB2ST_BACK_SUBS, SY2SB_ORMQR_NB, SYTRD_BLOCK_SIZE, LATRD_WG_HINT, STEDC_RECURSION_THRESHOLD, STEDC_MERGE_VARIANT, STEDC_THREADS_PER_ROOT, STEDC_WG_MULTIPLIER}.
BATCHLAS_SY2SB_ORMQR_NB is not a BATCHLAS_TUNE_* variable. It is three-valued: 0 or off means never hint, and values above 1024 are ignored (sy2sb_ormqr_nb_env in src/ops/syev/sytrd/sytrd_sy2sb.cc). BATCHLAS_SYEV_TWO_STAGE_KD goes through env_positive_int_or in src/util/settings.cc, which accepts "16x".
Five of these sit under an older, outer variable for the same quantity, which wins. See two variables for one quantity.
The constants are generated. The accessors are hand-maintained and mirrored in the template _emit_header in evaluation/tuning/generate_tuning_header.py. Any change to an accessor, to tuning_env_override, or to the #include <batchlas/settings.hh> that brings in EnvValue must land in the template too. The Doxygen text and evidence pointers are carried verbatim by the template, so header comment edits must be copied into it.
The template is the committed header with each constant replaced by its placeholder, plus one line, // Source profile: <path>, after the "GENERATED" banner. Regenerating with the committed constants reproduces the header exactly apart from that line. Check a template edit by regenerating with the committed constants and diffing.
Warning: the template is a Python f-string. Write C++ character escapes with doubled backslashes: a single '\0' becomes a raw NUL, which makes git treat the header as binary.
The committed header wins. CMake no longer generates tuning_params.hh. cmake/tuning_params.h.in and the batchlas_tuning_header target were removed on 2026-10-07, because include/ precedes the build tree on the include path and the committed file shadowed the generated one. A retune takes effect only when its constants are ported into the committed header by hand (evidence).
| constants | evidence |
|---|---|
| ORMQR_BLOCK_SIZE_*, SYTRD_BLOCK_SIZE_*, SY2SB_ORMQR_NB_*, SB2ST_BACK_* | syev: the 2026-08-07 constant retune, the 2026-08-03 block-size sweep |
| GEBRD_BLOCK_SIZE_* | gesvd: the gebrd panel-width split from ORMQR |
| STEDC_MERGE_VARIANT_*, STEDC_THREADS_PER_ROOT_*, STEDC_WG_MULTIPLIER_*, STEDC_RECURSION_THRESHOLD_* | stedc: current tuning values |
| LATRD_LOWER_PANEL_WG_HINT_*, SYTRD_FUSE_PANEL_UPDATE_* | none recorded; see tuning: open debts |