@@ -21,11 +21,11 @@ region that cannot run RAISES (the profiler and the e2e runner both fail-closed)
2121| ---| ---| ---|
2222| config | 28-layer 1.8B, seq=4096, batch=1 | 1.835B, bs=4×seq=4096 |
2323| tokens/step | 4,096 (seq×batch=4096×1) | 16,384 (bs=4×seq=4096) |
24- | ** peak memory** | ** 8.787 GB planned device-peak** (17.64 GB measured free-delta) | ** ~ 26 GB** |
24+ | ** peak memory** | ** 8.787 GB planned device-peak** (8.08 GB measured free-delta, 8L device-resident §13; was 10.30 GB pre-§13 ) | ** ~ 26 GB** |
2525| ** fits Megatron-class memory** | ** YES — 8.79 GB planned < 26 GB (≈3x under)** | 26 GB |
26- | ** tok/s** | ** 25.2 tok/s @ 8 layers MEASURED; ~ 5.2 tok/s @ 28 layers EXTRAPOLATED** | ** 3399 tok/s** |
27- | tok/s ratio vs Megatron | 0.0074x (8L measured) / 0.0015x (28L extrapolated) — i.e. ** 135x –654x slower** | 1.0x |
28- | what runs the compute | abstract numpy host-staged region drivers (memory/executability proof) + REAL path_c-CUDA kernel proven through the fwd boundary (PR-6 stage 2 ) | tuned fused-FP8-CUDA kernels + selective recompute |
26+ | ** tok/s** | ** 29.82 tok/s @ 8 layers MEASURED (device-resident fwd, §13; was 25.2 pre-§13); ~ 5.19 tok/s @ 28 layers EXTRAPOLATED** | ** 3399 tok/s** |
27+ | tok/s ratio vs Megatron | 0.0088x (8L measured, §13 ) / 0.0015x (28L extrapolated) — i.e. ** 114x –654x slower** (was 135x–654x) | 1.0x |
28+ | what runs the compute | ** REAL tilelang path_c-CUDA MR kernel, device-resident in the forward (§13) ** + abstract numpy bwd/adam/loss (lever 4 ) | tuned fused-FP8-CUDA kernels + selective recompute |
2929
3030** (a) Does the graph path FIT in Megatron-class memory? YES.** The StaticPlanBlockMemory
3131planned device-peak for the whole 28-layer 1.8B step is ** 8.787 GB** — roughly ** 3x under**
@@ -34,17 +34,22 @@ Megatron's ~26 GB, and the optimizer state is kept at 1x by the explicit in-plac
3434114-116 GB on the same box, ` MEGATRON-VS-MLX-PATHS.md ` ); the graph path runs it and plans
3535to 8.79 GB. ** This is the win the whole memory-path was built for.**
3636
37- ** (b) What tok/s does it achieve? Far below Megatron — and honestly so.** The current
38- graph path is a MEMORY-FIRST design whose region compute is still the abstract numpy
39- host-staged drivers (the memory/executability proof harness), NOT tuned device kernels.
40- Profiled on gb10 CUDA, the per-step wall is ** host-staging-bound and ~ constant per
41- region** , giving ** ~ 25 tok/s at 8 layers (measured)** and an extrapolated ** ~ 5 tok/s at
42- 28 layers** — a ** 135x (8L measured) to ~ 654x (28L extrapolated) throughput gap vs
43- Megatron's 3399 tok/s** . The gap is NOT
44- in the device kernels (PR-6 proved the real path_c-CUDA kernel runs 14.68M nonzero through
45- the same boundary); it is entirely the per-region host↔device numpy staging across the
46- ` call_dps_packed ` boundary. See §4 for where the time goes and §5 for the levers that
47- close it.
37+ ** (b) What tok/s does it achieve? Far below Megatron — and honestly so, but the
38+ host-staging lever has now been spent.** The §2/§4 PR-7 baseline profiled the ** abstract
39+ numpy host-staged** forward (a cheap ` np.maximum ` proxy + a full 2028 MB host round-trip per
40+ region) and measured ** 25.2 tok/s @ 8L, ~ 5.2 @ 28L (135×–654× gap)** , ~ 100% host-staging-
41+ bound. ** §13 re-profiles with the LANDED device-resident forward** (the REAL tilelang
42+ path_c-CUDA MR kernel, banks kept on ` tvm.cuda(0) ` end-to-end, no ` .numpy() ` in the forward
43+ hot path): ** 29.82 tok/s @ 8L MEASURED (1.18× faster), measured peak 8.08 GB (−2.22 GB host
44+ staging removed), 8L gap narrowed 135×→114×** ; the 28L extrapolation is ~ unchanged at ** 5.19
45+ tok/s (~ 654×)** . The decisive qualitative result: the forward's 96.9%-of-step term was
46+ ** host-staging in the baseline and is now 95.8% real-device-kernel COMPUTE** — ** the step is
47+ no longer host-staging-bound in the forward; the throughput floor has moved to the real
48+ 6.5 s MR-kernel compute × the sqrt-N remat launch count** (117 forward launches at 28L). The
49+ gap is NOT the architecture (identical 1.835B stack); the next levers (§13) are
50+ forward-launch fusion + a faster/fused MR kernel + the real device backward + ×4 batch —
51+ device-compute work. See §4 for the baseline breakdown, ** §13 for the device-resident
52+ re-profile + the host-staging recovery + the new attribution** , and §5 for the lever list.
4853
4954---
5055
@@ -327,13 +332,152 @@ the per-forward-call device-resident vs numpy-staged wall (measured 1.30×).
327332
328333---
329334
335+ ## 13. RE-PROFILE WITH THE DEVICE-RESIDENT FORWARD DRIVER — measured tok/s + the host-staging recovery (gb10 CUDA, 2026-06-03)
336+
337+ This re-runs the whole-step profiler with the ** device-resident forward driver** of §4a
338+ wired into every ` pathc.bank_fwd_i ` region (the REAL tilelang MR JITKernel, banks kept on
339+ ` tvm.cuda(0) ` end-to-end, no ` .numpy() ` in the per-region forward hot path), and re-measures
340+ tok/s + peak + the per-region breakdown against the §2/§4 PR-7 baseline (which ran the
341+ ** abstract numpy host-staged** forward). Profiler:
342+ ` scratch/pr7_profile_device_resident_gb10.py ` (compile-once / run-many, optimizer state
343+ threaded, background ` /proc/meminfo ` peak sampler, per-region wall timers). Loss finite and
344+ stable (` 5.525e-06 ` ) every step — same artifact the §4a equivalence proved
345+ (` max|device−numpy| = 1.025e-06 ` ).
346+
347+ ### MEASURED (gb10 CUDA, 8 layers, 4 steps, warm = steps 1–3)
348+
349+ | metric | PR-7 baseline (abstract numpy fwd) | ** device-resident fwd (this §13)** |
350+ | ---| ---:| ---:|
351+ | forward compute | ` np.maximum ` proxy + full host round-trip/region | ** REAL tilelang MR kernel, banks device-resident** |
352+ | mean warm step | 162.23 s | ** 137.36 s** (median 135.65 s) |
353+ | ** THROUGHPUT** | ** 25.2 tok/s** | ** 29.82 tok/s** |
354+ | step-time speedup | 1.0× | ** 1.18×** (162.2 → 137.4 s) |
355+ | planned device-peak | 4.682 GB | 4.682 GB (unchanged — same plan) |
356+ | ** MEASURED peak (free-delta)** | ** 10.30 GB** | ** 8.08 GB** (−2.22 GB: the per-region host staging buffers are gone) |
357+ | loss | 4.166e-02 (abstract) | ** 5.525e-06** (real kernel), finite, stable |
358+
359+ ```
360+ === PROFILE (DEVICE-RESIDENT FWD) gb10 CUDA, 8 layers (n_layers=8, 4 steps) ===
361+ compile-once : 0.03s (amortized to ~0 over a loop)
362+ mean step (warm) : 137355.2 ms median 135645.1 ms
363+ THROUGHPUT : 29.82 tok/s
364+ planned dev-peak : 4.682 GB
365+ MEASURED peak : 8.08 GB free-delta high-water
366+ per-region wall over 4 steps (host-driver time):
367+ fwd+remat : 526817.0 ms (80 calls) 95.8% [DEVICE-RESIDENT]
368+ bwd : 19611.1 ms (32 calls) 3.6% [abstract numpy]
369+ adam : 3037.5 ms (4 calls) 0.6% [abstract numpy]
370+ loss : 328.6 ms (4 calls) 0.1% [abstract numpy]
371+ per-call fwd : 6585.2 ms/call (device-resident)
372+ per-call bwd : 612.8 ms/call (abstract)
373+ ```
374+
375+ ### The host-staging recovery — what the elimination actually bought (honest)
376+
377+ * ** Net 8L speedup: 1.18× (25.2 → 29.82 tok/s), peak −2.22 GB (10.30 → 8.08 GB).** The
378+ measured free-delta dropping 2.22 GB is the direct, unambiguous signature of removing the
379+ per-region host staging buffers — the device-allocator plan (4.682 GB) is unchanged, so
380+ the entire drop is host-side numpy that no longer exists.
381+ * ** Apples-to-apples at the real-kernel forward: 1.28× — and this is the honest staging
382+ number.** The §2 baseline 25.2 tok/s ran a * cheap numpy proxy* forward (` np.maximum ` ) whose
383+ ~ 6.9 s/call was almost entirely the 2028 MB host round-trip. This §13 run pays the * real*
384+ 6.5 s MR-kernel ** compute** per call. So the 1.18× * net* mixes two changes (removed the host
385+ bounce ** and** swapped in the heavier real kernel). Holding the forward fixed at the REAL
386+ kernel, the device-resident path is ` 8472 ms → 6585 ms/call ` = ** 1.28× per forward call**
387+ (consistent with §4a's 1.30× and the scout's 1.38× ceiling): the recovered term is the
388+ per-call ~ 1.9 s of bank ` .numpy() ` / ` copyto ` host staging, now gone.
389+ * ** The 96.9% → 95.8% "forward share" did NOT move because the bottleneck SHIFTED, not
390+ vanished.** In the §4 baseline the forward's 96.9% was ** host-staging** . In §13 the forward
391+ is ** 95.8% device-kernel COMPUTE** — the 6585 ms/call is the real MR kernel executing on
392+ the GPU, with its ~ 1.9 s host bounce removed. ** The step is no longer host-staging-bound in
393+ the forward; it is now real-device-compute-bound in the forward.** That is the qualitative
394+ result of this lever: host-staging is eliminated where it was 96.9% of the wall, and the
395+ exposed floor is the kernel's own compute × the launch count.
396+
397+ ### Extrapolation to 28 layers / 1.8B (explicit, labelled — device-resident per-call costs)
398+
399+ Using the MEASURED device-resident per-call costs (fwd+remat ** 6.585 s/call** , bwd ** 0.613
400+ s/call** ) and the §5 region counts (28L = 117 fwd+remat [ 28 fwd + 89 sqrt-N recompute] + 28
401+ bwd + 1 adam + 1 loss):
402+
403+ ```
404+ 28L step ≈ 117×6.585 + 28×0.613 + adam/loss ≈ 770.5 + 17.2 + ~0.8 ≈ 788.5 s/step
405+ → 4096 / 788.5 ≈ 5.19 tok/s (EXTRAPOLATED from measured 8L per-call costs)
406+ ```
407+
408+ The 28L number is ** ~ unchanged (5.19 vs the baseline's ~ 5.2)** — because at 28L the step is
409+ dominated by ** 117 real-kernel forward launches** (the sqrt-N remat multiplies 28 forward
410+ regions into 117), and each launch is now the real 6.5 s MR kernel ** compute** , which the
411+ device-residency does not shrink. The 8L net win (1.18×) comes mostly from the smaller remat
412+ multiplier at 8L; the host-staging recovery (1.28× per call) is real but is swamped at 28L by
413+ the kernel-compute × launch-count floor.
414+
415+ ### Re-stated gap vs Megatron 3399 tok/s @ 26 GB
416+
417+ | side | tok/step | peak mem | tok/s | gap vs Megatron |
418+ | ---| ---:| ---:| ---:| ---:|
419+ | ** Megatron-LM (live)** | 16,384 | ~ 26 GB | ** 3399** | 1.0× |
420+ | Relax graph-path 8L, abstract-numpy fwd (PR-7 baseline) | 4,096 | 10.30 GB | 25.2 | 135× |
421+ | ** Relax graph-path 8L, DEVICE-RESIDENT fwd (§13)** | 4,096 | ** 8.08 GB** | ** 29.82** | ** 114×** |
422+ | Relax graph-path 28L, device-resident fwd (EXTRAPOLATED) | 4,096 | 8.787 GB planned | ** 5.19** | ** 654×** |
423+
424+ ** The new gap is 114× at 8L (was 135×) and ~ 654× at 28L (unchanged).** The device-resident
425+ forward closed the 8L gap from 135× to 114× (the 1.18× net speedup) and cut measured peak by
426+ 2.22 GB, but did not move the 28L extrapolation, because at depth the floor is the real
427+ kernel's compute × the remat launch count, not the host staging that was just removed.
428+
429+ ### What attributes the REMAINING gap — the next lever (honest, post-host-staging)
430+
431+ The forward host-staging that was ** 96.9% of the baseline step** is eliminated; the remaining
432+ 114×–654× gap is now attributed to, in order:
433+
434+ 1 . ** Real MR-kernel compute per launch (6.585 s/call) — the new dominant term.** This is a
435+ single-launch, ** unfused** MR region kernel (one giant kernel doing the whole M+R route).
436+ 6.5 s/call × 20 (8L) / 117 (28L) launches is now 95.8% of the step. The next lever is a
437+ ** faster / fused / tiled MR kernel** (and FP8 like Megatron) — this is device-compute
438+ optimization, not staging.
439+ 2 . ** sqrt-N remat launch multiplication.** The 28 forward regions become 117 forward launches
440+ at 28L (89 are recompute). Each recompute is a full 6.5 s kernel launch. Fusing adjacent
441+ forward+remat regions into fewer launches (§5 lever 1 remainder, deferred) directly attacks
442+ this — it is the single biggest 28L lever now that staging is gone.
443+ 3 . ** Abstract numpy bwd/adam/loss still host-stage (now 4.3% combined at 8L).** bwd = 612.8
444+ ms/call abstract (§13), adam 0.6%, loss 0.1%. Wiring the ** real device-resident backward**
445+ (lever 4) removes the last abstract host round-trips; small at 8L, but it grows with depth.
446+ 4 . ** 4× batch gap.** Megatron runs 16,384 tok/step (bs=4) vs this path's 4,096 (batch=1) — 4×
447+ less amortization per launch. Batching ×4 (§5 lever 3) is free amortization Megatron gets.
448+
449+ ** Bottom line:** the host-staging lever is spent and it worked where it applied — the forward
450+ is now device-resident, peak dropped 2.22 GB, 8L gap 135×→114×. The throughput floor has
451+ ** moved from host-staging to real-kernel compute × launch count** ; the next levers are kernel
452+ fusion/speed (1, 2) and the real device backward (3), not more staging removal.
453+
454+ ### Reproduce (§13)
455+
456+ ```
457+ ssh gb10; cd /home/dave/source/cppmega_mlx
458+ PR7_LAYERS=8 PR7_STEPS=4 \
459+ PYTHONPATH=/home/dave/source/cppmega_mlx:/home/dave/source/tilelang/3rdparty/tvm/python:/home/dave/source/tilelang/3rdparty/tvm/3rdparty/tvm-ffi/python \
460+ TVM_LIBRARY_PATH=/home/dave/source/tilelang/build/lib \
461+ /home/dave/cppmega-venv/bin/python scratch/pr7_profile_device_resident_gb10.py
462+ ```
463+ FAIL-LOUD: non-finite loss, any region that cannot run, or a device tensor not detected as
464+ device RAISES. Measured 2026-06-03 on gb10 ` tvm.cuda(0) ` , TVM 0.25.dev0.
465+
466+ ---
467+
330468## 7. Verdict
331469
332470The Relax graph-path train_step ** fits Megatron-class memory (8.787 GB planned device-peak
333471vs Megatron 26 GB, optimizer in-place) and runs the full 28-layer 1.8B step the eager path
334- OOMs on** — the memory-first goal is MET on device. Its ** throughput trails Megatron by
335- 135x (8L) to ~ 654x (28L)** (25.2 tok/s @ 8L measured, ~ 5.2 tok/s @ 28L extrapolated, vs 3399), and the gap
336- is ** fully attributed to the abstract per-region host↔device staging** (not the device
337- kernels, not the architecture) plus the 4× batch gap. The path is a memory envelope that is
338- now proven; closing the throughput gap is the on-device-fusion work in §5, with the real
339- path_c-CUDA kernel already proven through the forward boundary.
472+ OOMs on** — the memory-first goal is MET on device. With the ** device-resident forward
473+ driver landed and re-profiled (§13)** , the 8L throughput is ** 29.82 tok/s (was 25.2),
474+ measured peak 8.08 GB (was 10.30 GB, −2.22 GB host staging removed)** — the 8L gap vs
475+ Megatron's 3399 tok/s narrows from ** 135× to 114×** . The host-staging lever worked where it
476+ was 96.9% of the wall: the forward is now device-resident and ** the step is real-device-
477+ kernel-compute-bound in the forward, no longer host-staging-bound** . The 28L extrapolation is
478+ ** ~ unchanged (5.19 tok/s, ~ 654×)** because at depth the floor is the real 6.5 s MR-kernel
479+ compute × the sqrt-N remat launch count (117 forward launches at 28L), not the staging just
480+ removed. ** The throughput floor has moved from host-staging to kernel-compute × launch
481+ count** ; the next levers (§13) are forward-launch fusion + a faster/fused MR kernel + the
482+ real device backward + ×4 batch — device-compute work, not more staging removal. The memory
483+ envelope is proven; the throughput path is now a kernel-fusion problem.
0 commit comments