Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Gauntlet

Some scheduler bugs only exist on topologies you don’t develop on: a per-LLC work-splitting heuristic that breaks on an odd LLC count, an idle-core picker that lands both SMT siblings, a migration policy that never crosses a NUMA boundary. The gauntlet expands every #[ktstr_test] into one variant per topology preset — up to 24 presets (14 on aarch64) — so those bugs surface as a named, re-runnable test case instead of a production report.

Gauntlet variants are prefixed gauntlet/ and ignored by default:

# Run only base tests (default)
cargo ktstr test --kernel ../linux

# Run only gauntlet variants
cargo ktstr test --kernel ../linux -- --run-ignored ignored-only -E 'test(gauntlet/)'

# Run everything
cargo ktstr test --kernel ../linux -- --run-ignored all

# Run a single variant
cargo ktstr test --kernel ../linux -- --run-ignored ignored-only \
  -E 'test(=gauntlet/my_test/smt-2llc)'

This is what the expansion looks like when nextest lists a test with min_llcs = 1 and default constraints on this host:

ktstr::worktype_coverage_fork_gauntlet_e2e gauntlet/worktype_fork_gauntlet_covers_all_arms/medium-4llc
ktstr::worktype_coverage_fork_gauntlet_e2e gauntlet/worktype_fork_gauntlet_covers_all_arms/medium-4llc-nosmt
ktstr::worktype_coverage_fork_gauntlet_e2e gauntlet/worktype_fork_gauntlet_covers_all_arms/odd-3llc
ktstr::worktype_coverage_fork_gauntlet_e2e gauntlet/worktype_fork_gauntlet_covers_all_arms/smt-2llc
ktstr::worktype_coverage_fork_gauntlet_e2e gauntlet/worktype_fork_gauntlet_covers_all_arms/smt-3llc
ktstr::worktype_coverage_fork_gauntlet_e2e gauntlet/worktype_fork_gauntlet_covers_all_arms/tiny-1llc
ktstr::worktype_coverage_fork_gauntlet_e2e gauntlet/worktype_fork_gauntlet_covers_all_arms/tiny-2llc

Under a multi-kernel run a {kernel_label} segment is appended — gauntlet/{name}/{preset}/{kernel}. See Test names and variants for the label format.

Topology presets

Note

Multi-NUMA and scale-boundary presets are opt-in. The default constraints (max_numa_nodes = 1, max_llcs = 12, max_cpus = 192) exclude the five numa* presets plus near-max-llc, max-cpu, and their -nosmt variants — 15 of the 24 presets are active by default. Raise max_numa_nodes, max_llcs, or max_cpus on the test to opt in.

PresetTopologyCPUsLLCsNUMADescription
tiny-1llc1n1l4c1t411Single LLC
tiny-2llc1n2l2c1t421Minimal multi-LLC
odd-3llc1n3l3c1t931Odd CPU count
odd-5llc1n5l3c1t1551Prime LLC count
odd-7llc1n7l2c1t1471Prime LLC count
smt-2llc1n2l2c2t821SMT enabled
smt-3llc1n3l2c2t1231SMT, 3 LLCs
medium-4llc1n4l4c2t3241Medium topology
medium-8llc1n8l4c2t6481Medium, many LLCs
large-4llc1n4l16c2t12841Large, few LLCs
large-8llc1n8l8c2t12881Large, many LLCs
near-max-llc1n15l8c2t240151Near maximum
max-cpu1n14l9c2t252141Near KVM vCPU limit
medium-4llc-nosmt1n4l8c1t3241Medium, no SMT
medium-8llc-nosmt1n8l8c1t6481Medium, many LLCs, no SMT
large-4llc-nosmt1n4l32c1t12841Large, no SMT
large-8llc-nosmt1n8l16c1t12881Large, many LLCs, no SMT
near-max-llc-nosmt1n15l16c1t240151Near maximum, no SMT
max-cpu-nosmt1n14l18c1t252141Near KVM vCPU limit, no SMT
numa2-4llc2n4l4c1t1642Multi-NUMA, 2 nodes
numa2-8llc2n8l8c2t12882Multi-NUMA, 2 nodes, SMT
numa2-8llc-nosmt2n8l16c1t12882Multi-NUMA, 2 nodes, no SMT
numa4-8llc4n8l4c1t3284Multi-NUMA, 4 nodes
numa4-12llc4n12l8c2t192124Multi-NUMA, 4 nodes, SMT

Topology format: {numa_nodes}n{llcs}l{cores_per_llc}c{threads_per_core}t1n2l4c2t is 1 NUMA node, 2 LLCs, 4 cores per LLC, 2 threads per core = 16 CPUs. Note that llcs is the total across the machine, not per node.

aarch64: ARM64 CPUs do not have SMT. Presets with threads_per_core > 1 are excluded on aarch64, leaving 14 presets (the 5 small presets, 6 -nosmt variants, and 3 non-SMT NUMA presets).

Constraint filtering

#[ktstr_test] topology constraints filter which presets a test runs on. A preset is skipped when any constraint is not met:

  • num_numa_nodes() < min_numa_nodes
  • max_numa_nodes is set and num_numa_nodes() > max_numa_nodes
  • num_llcs() < min_llcs
  • max_llcs is set and num_llcs() > max_llcs
  • requires_smt and threads_per_core < 2
  • total_cpus() < min_cpus
  • max_cpus is set and total_cpus() > max_cpus

See The #[ktstr_test] Attribute for the attribute table.

Authoring gauntlet-ready tests

Worked example

A test with min_llcs = 2, requires_smt = true, and default max_numa_nodes = 1 against the preset table above:

  • tiny-1llc (1 LLC): excluded — below min_llcs
  • All non-SMT presets (tiny-2llc, odd-*, *-nosmt): excluded — requires_smt
  • near-max-llc (15 LLCs): excluded — above default max_llcs = 12
  • max-cpu (252 CPUs, 14 LLCs): excluded — above default max_cpus = 192 (also above default max_llcs = 12)
  • All numa* presets: excluded — above default max_numa_nodes = 1

Result: 6 of 24 presets survive (smt-2llc, smt-3llc, medium-4llc, medium-8llc, large-4llc, large-8llc). On aarch64, none survive — all aarch64 presets lack SMT.

Variant count

The total number of gauntlet variants for a test is valid_presets × resolved_kernels: the 6 surviving presets above produce 6 variants under a single kernel and 12 under --kernel A --kernel B.

Tests that skip gauntlet

Entries with host_only = true never produce gauntlet variants — they run on the host without booting a VM, so topology variation carries no signal. Tests whose names start with demo_ are ignored by default, gauntlet variants included.

Operator notes

  • Wall time. Each variant boots its own VM and runs the full scenario, so a sweep costs roughly (surviving presets × the per-run wall time you observe for the base test). nextest runs variants in parallel within your host’s budget. For a coverage-per-second subset under a deadline, use budget-based selection.
  • Memory. Each gauntlet VM gets max(cpus × 64 MiB, 256 MiB, entry.memory_mib) of guest RAM (plus an initramfs-derived floor). For the 252-CPU max-cpu presets that is at least 16128 MiB — the host needs that much free memory to run the variant.