Skip to content

Commit 5889826

Browse files
committed
docs: fix mislabel — the gb10 3399 tok/s stack is Megatron-LM (PyTorch+TE-CUDA), NOT 'C++'
The repo is named cppmega/megacpp but the training that hits 3399 tok/s is Megatron-LM (Python + PyTorch + TransformerEngine CUDA kernels), not a C++ binary. Also surface the live torch memory: [Rank 0] max allocated 25.7->28GB / max reserved 28->30GB (the '~26G' is now measured this session, not receipt-only). Replace C++/Megatron, C++/torch, C++ with Megatron-LM / Megatron/PyTorch / Megatron.
1 parent caff39a commit 5889826

3 files changed

Lines changed: 51 additions & 51 deletions

File tree

docs/MEGATRON-VS-MLX-PATHS.md

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# Megatron (C++/torch) vs MLX Paths — Definitive Throughput Comparison
1+
# Megatron-LM (PyTorch + TransformerEngine CUDA) vs MLX Paths — Definitive Throughput Comparison
22

33
Date: 2026-06-01 · Host: gb10 (NVIDIA GB10, sm_121, 121 GB unified) · single GPU (TP=1 PP=1 DP=1 CP=1, EP local)
44

5-
This doc pairs the **LIVE-reproduced** C++/Megatron `local_gb10_quarter` training number against our
5+
This doc pairs the **LIVE-reproduced** Megatron-LM `local_gb10_quarter` training number against our
66
MLX paths (path_b / path_c / path_c_chunked) from the gb10 1B speed matrix. It is the single
7-
apples-to-apples reference for "how fast is the C++ stack vs our MLX port, and which configs each can run."
7+
apples-to-apples reference for "how fast is the Megatron stack vs our MLX port, and which configs each can run."
88

99
Cross-references: `docs/TOKPS-DISCREPANCY.md` (the "75 vs 3000 tok/s" verdict) and
1010
`reports/MATRIX-REVIEW-INDEX.md` (the full Path-A..E campaign index).
@@ -15,7 +15,7 @@ cannot run say **cannot run** with the exact reason.
1515

1616
---
1717

18-
## 1. The C++/Megatron number — LIVE-REPRODUCED (not read from a receipt)
18+
## 1. The Megatron-LM number — LIVE-REPRODUCED (not read from a receipt)
1919

2020
Reproduced live on gb10 this session, **not** read from `plan.md`. Launcher:
2121
`/home/dave/source/cppmega/scripts/local_gb10_quarter_train.sh` (gb10 copy; cppmega SHA `8a3498f`).
@@ -57,7 +57,7 @@ not a dry pass).
5757
- **Steady-state (iters 7-10): mean 4820 ms/step → 3399 tok/s. Best iter 3404 tok/s.**
5858
- Wider warm window (iters 5-10): 4854 ms → 3375 tok/s.
5959
- Measured-system peak memory during the run: 38 GB (includes a concurrent MLX probe campaign on the same
60-
box). The **C++ run's own footprint is ~26 GB** per the receipt / `MATRIX-REVIEW-INDEX.md`.
60+
box). The **Megatron run's own footprint is ~26 GB** per the receipt / `MATRIX-REVIEW-INDEX.md`.
6161

6262
### Live vs receipt
6363

@@ -71,7 +71,7 @@ not a dry pass).
7171
4413 ms. The gap is **not** a config or correctness difference (same 16,384 tok/step, same fwd+bwd+Muon, same
7272
loss trajectory) — it is **memory-bandwidth contention**: another agent was running a concurrent MLX
7373
`probe_real_step_mem … --batch 1 --seq 4096` campaign that bursts to ~93 GB on the same 121 GB unified-memory
74-
device throughout the C++ run. The receipt was measured on a clean idle box. On an idle box this run lands on
74+
device throughout the Megatron run. The receipt was measured on a clean idle box. On an idle box this run lands on
7575
the 3712-3747 cluster. **3399 tok/s is the honest live number under contention; ~3700 tok/s is the clean-box
7676
number, now confirmed reproducible (not just receipt-read).**
7777

@@ -134,16 +134,16 @@ Sources: `reports/cppmega_1b_speed_matrix_gb10_fastfused_20260601_b2s512.md`,
134134
| bs=1 × seq=1024 | 1024 | **191**| **cannot run** | 32.6 (b) | path_c blocks at seq>512 |
135135
| bs=1 × seq=1024 (eff. MoE) | 1024 | 166 ✅ | n/a | 32.8 | `CPPMEGA_MOE_EFFICIENT=1`, loss 11.29→5.65 |
136136
| bs=1 × seq=4096 | 16384 | **cannot run** | n/a | fwd-only 4.9; fwd+bwd+adamw **97+** | backward+optimizer burst > 105 GB cap |
137-
| bs=4 × seq=4096 (C++ config) | 16384 | **cannot run** | n/a || unreachable (bwd+opt burst) |
137+
| bs=4 × seq=4096 (Megatron config) | 16384 | **cannot run** | n/a || unreachable (bwd+opt burst) |
138138

139139
(muon mirrors adamw on scale: bs1→bs2 path_b 92→159.)
140140

141141
---
142142

143143
## 3. Apples-to-apples normalization
144144

145-
The C++ run does **16,384 tok/step**; the MLX path_c run does **512 tok/step** — a **32×** token-count
146-
difference before any substrate effect. Per `TOKPS-DISCREPANCY.md`, the face-value C++/MLX-muon ratio
145+
The Megatron run does **16,384 tok/step**; the MLX path_c run does **512 tok/step** — a **32×** token-count
146+
difference before any substrate effect. Per `TOKPS-DISCREPANCY.md`, the face-value Megatron/MLX-muon ratio
147147
(3399…3747 vs 75.7) decomposes as roughly **32× (tokens/step) × ~5-11× (MLX-eager muon tax + eager-reference
148148
vs fused-FP8-CUDA substrate)**, with **0× from GPU count** (both single-GPU, per-GPU == aggregate) and
149149
**0× from model architecture** (identical NAM56R stack, confirmed in `TOKPS-DISCREPANCY.md` §5).
@@ -152,19 +152,19 @@ vs fused-FP8-CUDA substrate)**, with **0× from GPU count** (both single-GPU, pe
152152

153153
| side | optimizer | tok/step | tok/s | ms per token | basis |
154154
|---|---|---:|---:|---:|---|
155-
| C++ Megatron (live) | muon | 16,384 | 3399 | **0.294** | 4820 ms ÷ 16384 |
156-
| C++ Megatron (receipt) | muon | 16,384 | 3712-3747 | 0.267-0.269 | clean box |
155+
| Megatron-LM (live) | muon | 16,384 | 3399 | **0.294** | 4820 ms ÷ 16384 |
156+
| Megatron-LM (receipt) | muon | 16,384 | 3712-3747 | 0.267-0.269 | clean box |
157157
| MLX path_b | adamw | 512 | 156 | 6.41 | best small-batch MLX |
158158
| MLX path_b | adamw | 1024 | 191 (seq=1024) | 5.24 | scales with seq |
159159
| MLX path_c | adamw | 512 | 117 | 8.55 | only shape path_c runs |
160160
| MLX path_b | muon | 512 | 92 | 10.87 | matched optimizer, small batch |
161161

162-
The per-token gap C++ vs MLX-path_b-adamw at their respective runnable shapes is ~**0.294 vs 5.24-6.41 ms/token
162+
The per-token gap Megatron vs MLX-path_b-adamw at their respective runnable shapes is ~**0.294 vs 5.24-6.41 ms/token
163163
(≈18-22×)**. This is the genuine **fused-FP8-CUDA-large-batch vs MLX-eager-bf16-small-batch** substrate +
164164
batch-amortization delta — it is **not** closeable to a single clean factor because the two measurements needed
165-
(MLX at bs=4×seq=4096, and C++ at bs=1×seq=512) do not exist: MLX cannot reach the C++ shape (below).
165+
(MLX at bs=4×seq=4096, and Megatron at bs=1×seq=512) do not exist: MLX cannot reach the Megatron shape (below).
166166

167-
### Why MLX cannot reach the C++ config (code-pinned, from `MATRIX-REVIEW-INDEX.md`)
167+
### Why MLX cannot reach the Megatron config (code-pinned, from `MATRIX-REVIEW-INDEX.md`)
168168

169169
1. **path_c is pinned to exactly bs=1 × seq=512.** It blocks at bs>1 *or* seq>512 with
170170
`direct_fusion_chain_logical_buffers_missing` — the fused direct-chain runtime was built for that one shape.
@@ -176,7 +176,7 @@ batch-amortization delta — it is **not** closeable to a single clean factor be
176176
(gradients + m/v optimizer state + recomputed grad-checkpoint activations all materialize at once) — over the
177177
105 GB SIGTERM safety cap. So bs=4×seq=4096 (and even bs=1×seq=4096 fwd+bwd) is unreachable in MLX-eager.
178178
3. The wall is the **whole-model backward+optimizer burst, NOT the MoE** — measured: efficient sparse MoE and
179-
dense MoE have the same ~32.6/32.8 GB peak at seq=1024 (MoE is only 4 of 13 layers). C++ does bs=4×seq=4096
179+
dense MoE have the same ~32.6/32.8 GB peak at seq=1024 (MoE is only 4 of 13 layers). Megatron does bs=4×seq=4096
180180
in ~26 GB because its fused training step (activation checkpointing + a fused optimizer that never
181181
materializes all grads + optimizer-state simultaneously) + sparse all-to-all MoE avoid that burst.
182182

@@ -185,34 +185,34 @@ batch-amortization delta — it is **not** closeable to a single clean factor be
185185
## 4. Final cross-path table
186186

187187
Rows = the four paths; columns = the configs each can run, with tok/s. **"cannot run"** cells state the exact
188-
reason. C++ = live this session; MLX = gb10 1B matrix (prior session, LIVE-measured). All single GB10, full
188+
reason. Megatron = live this session; MLX = gb10 1B matrix (prior session, LIVE-measured). All single GB10, full
189189
fwd+bwd+optimizer step.
190190

191191
| path | bs1×seq512 (512 tok) | bs2×seq512 (1024 tok) | bs1×seq1024 (1024 tok) | bs4×seq4096 (16384 tok) | dtype/opt of best cell |
192192
|---|---|---|---|---|---|
193-
| **C++ Megatron** | not measured¹ | not measured¹ | not measured¹ | **3399 tok/s live** (3712-3747 receipt, clean box) | bf16+FP8 / Muon |
193+
| **Megatron-LM** | not measured¹ | not measured¹ | not measured¹ | **3399 tok/s live** (3712-3747 receipt, clean box) | bf16+FP8 / Muon |
194194
| **MLX path_b** | 156 (adamw) / 92 (muon) | **259** (adamw) / 159 (muon) | **191** (adamw, seq=1024) | **cannot run** — bwd+optimizer burst ~97 GB > cap | bf16 / adamw |
195195
| **MLX path_c** | **117** (adamw) / 80.5 (muon) | **cannot run** — bs>1 → `direct_fusion_chain_logical_buffers_missing` | **cannot run** — seq>512 → same | **cannot run** — bs & seq both off build shape | bf16 / adamw |
196196
| **MLX path_c_chunked** | 121 (adamw) / 80.5 (muon) | **cannot run** — same direct-chain limit (bs>1) | **cannot run** — same (seq>512) | **cannot run** — same | bf16 / adamw; compiles 1.15-2.0× faster than path_c |
197197

198-
¹ C++ Megatron at small shapes (bs1×seq512 etc.) was **not run** — the launcher targets the production quarter
198+
¹ Megatron-LM at small shapes (bs1×seq512 etc.) was **not run** — the launcher targets the production quarter
199199
config (bs4×seq4096). It is technically runnable there but out of scope; the one cell that matters for the
200-
comparison (its native bs4×seq4096) is the live-reproduced 3399 tok/s. This asymmetry — C++ only measured at its
201-
big shape, MLX only runnable at small shapes — is exactly why a single clean MLX-vs-C++ ratio does not exist
200+
comparison (its native bs4×seq4096) is the live-reproduced 3399 tok/s. This asymmetry — Megatron only measured at its
201+
big shape, MLX only runnable at small shapes — is exactly why a single clean MLX-vs-Megatron ratio does not exist
202202
(`TOKPS-DISCREPANCY.md` §6).
203203

204204
### Plain-language summary
205205

206-
- **C++/Megatron is the only path that runs the real production config (bs4×seq4096, 16,384 tok/step): live
206+
- **Megatron-LM is the only path that runs the real production config (bs4×seq4096, 16,384 tok/step): live
207207
3399 tok/s under contention, 3712-3747 tok/s on a clean box (receipt, now reproduced).**
208208
- **MLX path_b is the only MLX path that scales** with batch and sequence, but **tops out before seq=4096**
209-
(backward+optimizer memory burst) and so **cannot meet the C++ config**. Best MLX numbers: 259 tok/s
209+
(backward+optimizer memory burst) and so **cannot meet the Megatron config**. Best MLX numbers: 259 tok/s
210210
(bs2×seq512) / 191 tok/s (bs1×seq1024), adamw, bf16.
211211
- **MLX path_c / path_c_chunked are pinned to bs1×seq512** (117 / 121 tok/s adamw) — the fused direct-chain
212212
runtime exists only for that shape; everything larger fails loud. Their win is **faster compile**, not
213213
steady-state throughput.
214-
- The C++↔MLX gap is **batch/token-count (32×) + eager-reference-vs-fused-FP8-CUDA substrate**, not a model or
215-
GPU-count difference (`TOKPS-DISCREPANCY.md`). The highest-leverage MLX item to even approach the C++ config is
214+
- The Megatron↔MLX gap is **batch/token-count (32×) + eager-reference-vs-fused-FP8-CUDA substrate**, not a model or
215+
GPU-count difference (`TOKPS-DISCREPANCY.md`). The highest-leverage MLX item to even approach the Megatron config is
216216
a **fused/streamed (chunked-param) optimizer step** that never holds all grads + optimizer state at once.
217217

218218
---
@@ -232,20 +232,20 @@ since it is counterproductive on MLX-CUDA), with `free -g` as truth and the gb10
232232
**Conclusion (measured, not assumed):** at seq ≥ 2048 the chunked backward that *saves* the memory is
233233
compute-heavy, so MLX-eager trades the OOM for ~5 min/step — neither seq=2048 nor seq=4096 yields a practical
234234
completing throughput number, and seq=4096 additionally peaks 107 GB (>100 GB budget). The fixes brought
235-
seq=4096 from 121 GB→107 GB (close) but it stays over budget and ~100× slower per step than the fused C++
235+
seq=4096 from 121 GB→107 GB (close) but it stays over budget and ~100× slower per step than the fused Megatron
236236
kernel. So the literal bs4×seq4096 MLX path_b number is **fundamentally impractical** on this eager stack —
237237
now proven by direct runs, not inferred. The honest MLX throughput ceiling is **191 tok/s @ bs1×seq1024**;
238-
C++/Megatron does the full bs4×seq4096 step at **3399 tok/s live** in ~26 GB. The gap is the
239-
eager-reference-vs-fused-FP8-CUDA substrate + the streamed-optimizer/recompute design C++ has and MLX-eager lacks.
238+
Megatron-LM does the full bs4×seq4096 step at **3399 tok/s live** in ~26 GB. The gap is the
239+
eager-reference-vs-fused-FP8-CUDA substrate + the streamed-optimizer/recompute design Megatron has and MLX-eager lacks.
240240

241241
---
242242

243243
## Sources
244244

245-
- **Live C++ run:** `repro_quarter_20260601_192748` on gb10, launcher
245+
- **Live Megatron run:** `repro_quarter_20260601_192748` on gb10, launcher
246246
`/home/dave/source/cppmega/scripts/local_gb10_quarter_train.sh` (cppmega SHA `8a3498f`); raw per-iter timings
247247
in §1.
248-
- **C++ receipt:** cppmega `plan.md:989,991,110,116` (3628-3747 cluster, 2026-04-25).
248+
- **Megatron receipt:** cppmega `plan.md:989,991,110,116` (3628-3747 cluster, 2026-04-25).
249249
- **MLX matrix:** `reports/cppmega_1b_speed_matrix_gb10_fastfused_20260601.md`,
250250
`…_b2s512.md`, `cppmega_1b_seqscale_gb10_b1s1024_results.json`.
251251
- **Analyses:** `docs/TOKPS-DISCREPANCY.md`, `reports/MATRIX-REVIEW-INDEX.md`.

0 commit comments

Comments
 (0)