Skip to content

Instantly share code, notes, and snippets.

@aganhui
Created September 9, 2026 06:35
Show Gist options
  • Select an option

  • Save aganhui/3b374ffb3d6d13b52d5688780fafac28 to your computer and use it in GitHub Desktop.

Select an option

Save aganhui/3b374ffb3d6d13b52d5688780fafac28 to your computer and use it in GitHub Desktop.
DeepGEMM nv_dev: SM120 k_grouped NT contiguous tensormap race — repro script and raw evidence (issue evidence)

Evidence: SM120 k_grouped NT contiguous tensormap race (DeepGEMM nv_dev @ 2642b32)

Companion evidence for the DeepGEMM issue this gist is linked from.

Environment: RTX 5090 D (SM120), CUDA 13.0, PyTorch 2.11.0+cu130, built from the nv_dev tarball @ 2642b32 with pinned submodules (CUTLASS @ f3fde58, fmt @ 553ec11).

Contents

  • repro_determinism.py — standalone repro. PRISTINE kernel: three different diffs on identical inputs (race). With the #343 drain ported: 0.000105 x3, bit-identical.
  • evidence_log.md — raw outputs: 56-config scan, trigger-rate runs, per-group error localization, post-fix determinism, 100x soak, perf A/B, bf16 note.

Raw evidence log — SM120 k_grouped NT tensormap race

Date: 2026-09-08 · Hardware: RTX 5090 D (SM120) · DeepGEMM nv_dev @ 2642b32 CUDA 13.0, PyTorch 2.11.0+cu130, CUTLASS @ f3fde58, fmt @ 553ec11

1. Full-config scan (all test_k_grouped_gemm_contiguous enumerations, PRISTINE kernel)

TOTAL_CONFIGS=56 FAILS=4

All 4 failures: m=768, n=2048, KMajor×KMajor (NT kernel), gran_k ∈ {32, 128}, k_alignment=128, psum=0 (both ks-variants of each). The same shape passes via the TN (MNMajor) path. 52/56 pass.

2. Trigger rate (stock test_k_grouped_gemm_contiguous, PRISTINE kernel)

  • warm JIT cache: 10/10 runs fail at the first shape
  • cold JIT cache (fresh compile per run): 3/3 fail
  • early manual runs: 1 fail / 1 pass
  • total: 13/14 fail (~93%)

Failure point is stable: always the first shape (8 groups, m=768, n=2048, k≈128/group) — the regression shape that #343 added to stress in-place tensor-map updates.

3. Race confirmation (identical inputs, PRISTINE kernel)

Fixed seeds, data regenerated per iteration (see repro_determinism.py):

run 1: diff = 0.006319
run 2: diff = 0.005205
run 3: diff = 0.003889

Per-group error localization (|d - ref_d| > 1.0, third run):

group 0 (k=256): 152483 elements, max abs err 3.30
group 1 (k=256): 153457, max 3.34
group 2 (k=128):  95317, max 89.83
group 3 (k=128): 169774, max 98.31
group 4 (k=128): 199877, max 98.11
group 5 (k=128):  63362, max 122.46
group 6 (k=256): 152180, max 3.53
group 7 (k=128):  34346, max 2.31

Errors spread across all groups — every group switch is a hazard, as expected for a tensormap publish race.

4. After porting the #343 drain (4 lines) — same hardware, same seeds

same-data 3 runs: 0.000105 / 0.000105 / 0.000105  (bit-identical)
full suites: k_grouped_contiguous + m_grouped_contiguous + m_grouped_masked: PASS
soak x100 (fresh data each iteration): 100/100 pass, max_diff constant at 0.000105

5. Perf A/B (same seeds and data, bench via the project's bench_kineto)

sentinel shape (8 groups, m=768, n=2048, k=1408 — worst case for group-switch density):
  PRISTINE: 87.0 us | FIXED: 87.8 us   (+0.9%)
EP shape (8 groups, m=4096, n=7168, k=28160 — typical):
  PRISTINE: 3106 us | FIXED: 3114 us   (+0.26%)

The drain cost is proportional to what is in flight at the switch: near-zero when the TMA queue is already empty (throttled producers, large k per group), sub-µs stalls on the sentinel shape where most of the wait hides under the epilogue.

6. bf16 note

sm120_bf16_gemm.cuh has the same un-drained group-switch pattern. We could not make it fail on this hardware (full test_bf16.py suite + 50 targeted stress runs of the same sentinel shape, max diff 2e-7). Per the commit-group ordering analysis in #365 it is the same UB class; left untouched in the accompanying PR pending maintainer preference.

# Standalone repro: SM120 k_grouped NT contiguous tensormap race
#
# Run from the repo root of a DeepGEMM nv_dev checkout (built with its pinned submodules):
# python3 repro_determinism.py
#
# Expected on a PRISTINE sm120_fp8_fp4_gemm_1d1d.cuh (e.g. nv_dev @ 2642b32):
# three DIFFERENT diffs (non-deterministic = race)
# Expected after porting the #343 drain (commit_group + wait_group before the GMEM publish):
# 0.000105 x3, bit-identical
import sys, random, torch
sys.path.insert(0, "tests") # for generators
import deep_gemm
from deep_gemm.testing import calc_diff
from generators import (KernelType, MajorTypeAB, get_ue8m0_usage,
generate_k_grouped_contiguous, set_mk_alignment_for_contiguous_layout)
ks = [256, 256, 128, 128, 128, 128, 256, 128]
use_ue8m0 = get_ue8m0_usage(KernelType.Kernel1D1D)
set_mk_alignment_for_contiguous_layout(128)
diffs = []
for rep in range(3):
# seeds INSIDE the loop: randn consumes the stream sequentially,
# so each iteration must reset to guarantee identical inputs
torch.manual_seed(42); random.seed(42)
total_k, a, b, c, d, ref_d, grouped_layout, _ = generate_k_grouped_contiguous(
8, 768, 2048,
MajorTypeAB.KMajor, MajorTypeAB.KMajor, # NT kernel = the failing path
ks, use_ue8m0=use_ue8m0, gran_k=128)
deep_gemm.k_grouped_fp8_gemm_nt_contiguous(a, b, d, ks, grouped_layout, c,
recipe=(1, 1, 128), use_psum_layout=False)
diffs.append(float(calc_diff(d, ref_d)))
print(f"run {rep + 1}: diff = {diffs[-1]:.6f}")
if len(set(diffs)) == 1:
print("-> identical across runs (deterministic)")
else:
print("-> differs across identical inputs: non-deterministic = race")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment