|
| 1 | +# TRITON-ROUTE-P1 — Routed Tri-Dao bwd: parity + exec-ms + prologue breakdown |
| 2 | + |
| 3 | +MEASURED from committed HEAD on gb10 (NVIDIA GB10 sm_121, aarch64-linux). |
| 4 | +- gb10 tilelang HEAD: `db5fe57c117460ce84d72cd7b07f153f51c4ef0a` (de-monomorph: symbolic flat-arg buffer extents) |
| 5 | +- local mirror HEAD: `48b9236a86ef0ebd0b22ec3625b374b7d2fbf874` (same logical fix, separate repo) |
| 6 | +- Working tree clean (only `3rdparty/tvm` submodule pointer = built state). No uncommitted source. |
| 7 | +- All 7 PrimFunc JSONs regenerated FRESH from HEAD via `emit_pf_json.py` before measuring. |
| 8 | + |
| 9 | +RULE#1: real-strided / §P1 numbers ONLY. No degenerate (single-K-trip / cs==BK) or |
| 10 | +tiny-config number reported as a real-strided/§P1 result. Routed exec ms reported ONLY |
| 11 | +for the parity-PASS kernel. Every failing kernel reports its EXACT defect; no fabricated PASS. |
| 12 | + |
| 13 | +--- |
| 14 | + |
| 15 | +## 1. Per-kernel parity — REAL strided multi-K-trip (cs=64 != BLOCK_K=32, 2 K-trips/chunk) |
| 16 | + |
| 17 | +### 1a. SMALL real-strided config (b1 nh8 hd64 ds64 nc4 cs64 ng2 s256, grid (1,4,8)) |
| 18 | + |
| 19 | +| Kernel | Status @ HEAD | MAXDIFF | ALLCLOSE 1e-3 | Notes | |
| 20 | +|--------------------------------|------------------------|--------------|---------------|-------| |
| 21 | +| `_chunk_scan_bwd_dstates` | **PASS** | 3.051758e-05 | True | nz 131072/131072 full; cs=64,BK=32 = 2 K-trips | |
| 22 | +| `_chunk_scan_bwd_dc` | SEGFAULT (routed launch) | n/a | — | dumps core at kernel launch | |
| 23 | +| `_chunk_scan_bwd_dcb` | NO-ROUTE / compile fail | n/a | — | emit RAISES `PtrState references unresolved SSA value '%1044'`; compiled variant fails nvcc (`mma.h` error limit) | |
| 24 | +| `_chunk_scan_bwd_dx` | NO-LAUNCH (de-mono incomplete) | n/a | — | `tvm InternalError: arg4_numel_243 used but not passed as API argument` | |
| 25 | +| `_chunk_state_bwd_db` | SEGFAULT (routed launch) | n/a | — | dumps core at kernel launch | |
| 26 | +| `_chunk_state_bwd_dx` | SEGFAULT (routed launch) | n/a | — | dumps core at kernel launch | |
| 27 | +| `_chunk_state_bwd_ddAcs_stable`| NO-COMPARE | n/a | — | atomic/return-only output; harness pin_kernel also KeyError BLOCK_SIZE_M | |
| 28 | + |
| 29 | +**SMALL real-strided result: 1/7 numerically correct (dstates).** |
| 30 | + |
| 31 | +### 1b. PRODUCTION §P1 config (b1 nh112 hd64 ds64 nc64 cs64 ng8 s4096, grid (1,64,112), numel 29,360,128) |
| 32 | + |
| 33 | +Only `_chunk_scan_bwd_dstates` routes+launches; only it has a §P1 parity number: |
| 34 | + |
| 35 | +| Kernel | Status | MAXDIFF | ALLCLOSE 1e-3 | nonzero | |
| 36 | +|---------------------------|--------|--------------|---------------|----------------| |
| 37 | +| `_chunk_scan_bwd_dstates` | **PASS** | 4.882812e-04 | True | 29360128/29360128 (native 29360127) | |
| 38 | + |
| 39 | +The SAME compiled kernel that passed at small (1,4,8) launches+passes at §P1 (1,64,112) with no |
| 40 | +segfault — the de-monomorph (symbolic flat-arg extents) fix is CONFIRMED for dstates: numel grew |
| 41 | +from ~131K to 29.36M with the same baked PrimFunc. |
| 42 | + |
| 43 | +**§P1 prod result: 1/7 numerically correct (dstates).** |
| 44 | + |
| 45 | +--- |
| 46 | + |
| 47 | +## 2. Routed EXEC ms/kernel @ §P1 (parity-PASS kernel only) |
| 48 | + |
| 49 | +Authoritative on-device kernel time, 3 independent methods, all agree: |
| 50 | + |
| 51 | +| Method | dstates §P1 routed ms/kernel | |
| 52 | +|-------------------------------------|------------------------------| |
| 53 | +| nsys `cuda_gpu_kern_sum` (1 launch) | **1473.43 ms** (avg of 4 kern instances 1465–1478ms) | |
| 54 | +| CUDA events (N=100) | 1470.52 ms | |
| 55 | +| Python wall (N=50) | 1476.32 / 1472.43 ms | |
| 56 | + |
| 57 | +Device time ≈ wall time → the cost is **genuine on-GPU kernel runtime**, NOT host/launch overhead. |
| 58 | + |
| 59 | +**vs native: native `_chunk_scan_bwd_dstates` @ §P1 = 1.14 ms/kernel.** |
| 60 | +Routed = ~1473 ms → **≈1292x SLOWER than native.** |
| 61 | + |
| 62 | +--- |
| 63 | + |
| 64 | +## 3. Prologue vs GEMM breakdown — strip-and-time (MEASURED) |
| 65 | + |
| 66 | +The routed kernel body is: (a) a ~133-`for`-loop **prologue** that materializes the Triton |
| 67 | +pointer arithmetic (`tl.arange`, broadcasts, int32-overflow guards) as serial per-thread |
| 68 | +element-wise loops over `bool[4096]` / `int[4096]` arrays, followed by (b) a tiny **GEMM** |
| 69 | +(2× `mma.sync` in a 4-iter K-loop with `ldmatrix`), then (c) carry/epilogue. |
| 70 | + |
| 71 | +Strip-and-time (inject `return;` immediately before the GEMM block, recompile through the |
| 72 | +identical TileLang adapter path, same §P1 args, CUDA-event timed): |
| 73 | + |
| 74 | +| Variant | DEVICE ms/kernel @ §P1 | |
| 75 | +|----------------------------------|------------------------| |
| 76 | +| FULL kernel | 1473.29 ms | |
| 77 | +| PROLOGUE-ONLY (return pre-GEMM) | 1474.99 ms | |
| 78 | +| ⇒ GEMM + epilogue contribution | ~0 ms (within noise) | |
| 79 | + |
| 80 | +**~100% of the 1473ms is the prologue. The actual GEMM is negligible.** |
| 81 | + |
| 82 | +### Is this inherent to the per-block model? |
| 83 | +YES — as currently lowered. The routed PrimFunc emits each Triton pointer-offset computation |
| 84 | +as a literal element-wise loop (e.g. `tile_binop[i] = (val <= INT_MAX) & (INT_MIN <= val)`) |
| 85 | +over 4096-element arrays, run **serially by every one of the 128 threads in every one of the |
| 86 | +7168 blocks**, instead of folding the offsets into the load addressing the way native Triton |
| 87 | +does. Roughly ~20 such `[4096]` loops × 128 threads × 7168 blocks of redundant scalar work |
| 88 | +dwarf the 2-instruction GEMM. This is a structural property of the current whole-block |
| 89 | +walker lowering (pointer math not fused into addressing, not thread-parallelized, not |
| 90 | +vectorized) — not a launch artifact and not fixable by tuning; it needs the frontend to |
| 91 | +fold pointer arithmetic into load/store addressing. |
| 92 | + |
| 93 | +--- |
| 94 | + |
| 95 | +## 4. GO / NO-GO |
| 96 | + |
| 97 | +**NO-GO for production routing of the Tri-Dao bwd as a whole.** |
| 98 | + |
| 99 | +Honest scorecard, measured from committed HEAD: |
| 100 | +- Correctness: **1/7** kernels numerically correct at real-strided multi-K-trip (small AND §P1): |
| 101 | + only `_chunk_scan_bwd_dstates`. The other 6 fail at HEAD: 3 SEGFAULT at launch (dc, db, state_dx), |
| 102 | + 1 NO-ROUTE emit-raise (dcb %1044), 1 NO-LAUNCH de-mono-incomplete (dx arg4_numel_243), |
| 103 | + 1 NO-COMPARE atomic-output (ddAcs). |
| 104 | +- Runnability: dstates IS de-monomorphized — same baked kernel runs small→§P1 with no segfault. GOOD. |
| 105 | +- Performance: even the one correct kernel is **~1292x slower than native** (1473ms vs 1.14ms), |
| 106 | + and the strip-and-time proves ~100% of that is the un-fused pointer-arithmetic prologue. |
| 107 | + |
| 108 | +### What is solid / reproducible |
| 109 | +- `_chunk_scan_bwd_dstates` multi-K-trip (cs!=BK) correctness: bit-close at small (3.05e-05) |
| 110 | + AND §P1 (4.88e-04), full output blocks written. The original BLOCKER-1 (multi-K-trip |
| 111 | + K-accumulation) and BLOCKER-2 (monomorphization segfault) are RESOLVED for dstates. |
| 112 | + |
| 113 | +### Exact residuals (RAISED, not papered over) |
| 114 | +1. **6/7 kernels do not route/run at HEAD** — each with the exact defect above. The §P1 GO |
| 115 | + requires fixing the dc/db/state_dx launch segfaults, the dx de-mono gap (`arg4_numel_243` |
| 116 | + not threaded as an API arg — same class of fix as the dstates extent symbolization, but |
| 117 | + for an index/numel symbol), and the dcb emit defect (`%1044` unresolved PtrState). |
| 118 | +2. **Performance is non-viable** even for the passing kernel: the prologue must fold Triton |
| 119 | + pointer arithmetic into addressing (eliminate the serial `[4096]` bool/int offset loops) |
| 120 | + before any routed kernel can compete with native. |
| 121 | + |
| 122 | +--- |
| 123 | + |
| 124 | +## 5. Reproduce (from committed HEAD on gb10) |
| 125 | + |
| 126 | +``` |
| 127 | +ssh gb10 |
| 128 | +cd /home/dave/source/tilelang && source /home/dave/cppmega-venv/bin/activate |
| 129 | +# 1. regen PrimFunc JSONs from HEAD |
| 130 | +for k in _chunk_scan_bwd_dstates _chunk_scan_bwd_dc _chunk_scan_bwd_dcb _chunk_scan_bwd_dx \ |
| 131 | + _chunk_state_bwd_db _chunk_state_bwd_dx _chunk_state_bwd_ddAcs_stable; do |
| 132 | + python poc/triton_frontend/_test_harness/tridao_parity/emit_pf_json.py $k; done |
| 133 | +# 2. small real-strided parity (per kernel, isolated so one segfault doesn't abort the rest) |
| 134 | +python poc/triton_frontend/_test_harness/tridao_parity/parity_all7.py small _chunk_scan_bwd_dstates |
| 135 | +# 3. §P1 production dstates parity + timing |
| 136 | +python poc/triton_frontend/_test_harness/tridao_parity/parity_prod_dstates.py |
| 137 | +# 4. prologue strip-and-time |
| 138 | +python /tmp/strip_time_final.py full |
| 139 | +python /tmp/strip_time_final.py prologue |
| 140 | +``` |
0 commit comments