Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
0660f81
ccl: hierarchical cross-node AllGather (intra-node SDMA + inter-node …
inkcherry Jun 30, 2026
5909a30
ccl: auto-detect ranks_per_node; keep flat AllgatherSdma-compatible s…
inkcherry Jul 1, 2026
05deca8
Merge ROCm/mori main into sdma-hier-allgather
inkcherry Jul 1, 2026
5c2fd42
ccl: add traditional list-based all_gather to HierAllGather
inkcherry Jul 1, 2026
7fb4db3
docs/bench: use English wording (drop non-ASCII in README and gemm-ov…
inkcherry Jul 1, 2026
e14abec
bench: annotate result charts as cross-node (2 nodes x 4 GPU, intra-S…
inkcherry Jul 1, 2026
4188668
examples/fsdp_sdma: transparent FSDP2 all-gather over MORI (intra SDM…
inkcherry Jul 3, 2026
1e4bfad
ccl: param-contiguous zero-copy for HierAllGather (kill FSDP copy-out…
inkcherry Jul 3, 2026
b3e4475
ccl: fuse HierAllGather param-contiguous scatter into ONE launch (kil…
inkcherry Jul 3, 2026
d802d9e
ccl: overlap HierAllGather param-contiguous local-block scatter with …
inkcherry Jul 3, 2026
0d8f548
ccl: gate HierAllGather param-contiguous overlap OFF by default (HSA …
inkcherry Jul 3, 2026
e5809af
ccl: standalone bit-exact test for intra param-contiguous (HSDP winni…
inkcherry Jul 3, 2026
daa789e
ccl: system-scope fences in fused subgroup param-contiguous scatter +…
inkcherry Jul 3, 2026
a380c7a
ccl: drop ineffective threadfence_system from fused subgroup param-co…
inkcherry Jul 3, 2026
06d6a8a
ccl: gated measurement to skip inter-ring entry barrier — proves the …
inkcherry Jul 3, 2026
2a133f8
ccl: kill per-AG-call D2H syncs in param-contiguous zero-copy path (.…
inkcherry Jul 3, 2026
b5f4add
ccl: MORI_HIER_NO_ALL_BARRIER measurement switch (strip entry+finish+…
inkcherry Jul 3, 2026
2ad6498
ccl: FIX the 17-turn num_blocks=1 param-contiguous scatter 'bug' — it…
inkcherry Jul 3, 2026
0f1c22a
ccl: fix overlap zero-copy spin-deadlock — serialize side/main param-…
inkcherry Jul 3, 2026
6c26ebf
ccl: fix overlap zero-copy loss-drift race — record_stream input/outp…
inkcherry Jul 3, 2026
5c89a6c
ccl: MORI_HIER_REG_STATS diagnostic — count output-ptr registration c…
inkcherry Jul 3, 2026
401b075
ccl: MORI_HIER_DEBUG_SYNC isolation switch proves the FSDP copy-out l…
inkcherry Jul 3, 2026
949bb36
ccl: fix FSDP copy-out loss-nondeterminism — SDMA gather receiver spi…
inkcherry Jul 3, 2026
db71740
ccl: CU-domain Phase-B copy-OUT (transit out_ accessor + single torch…
inkcherry Jul 3, 2026
3a137e5
ccl: cross-stream overlap-determinism UT for HierAllGather param-cont…
inkcherry Jul 4, 2026
6ff8f8e
ccl: extend overlap-determinism UT to the COPY-OUT __call__ path (the…
inkcherry Jul 4, 2026
3a39c17
ccl: fix overlap-determinism UT false-NaN — use a FRESH handle per op…
inkcherry Jul 4, 2026
a9d3c65
test(hier-ag): add Qwen-band large-split profile + independent all_ga…
inkcherry Jul 4, 2026
e29365b
ccl(hier-ring): system-scope acquire + threadfence on inter-node ring…
inkcherry Jul 4, 2026
0d707c6
ccl(hier): default MORI_HIER_FUSE_LOCAL OFF — fused ring||local-gathe…
inkcherry Jul 4, 2026
bdfb4c8
ccl(hier-ring): transport-aware quiet on the default single-warp ring…
inkcherry Jul 4, 2026
16d172d
ccl(hier-ring): CU-domain ring finish copy-OUT (coherent reader) — re…
inkcherry Jul 4, 2026
86e2014
ccl(hier): env-gated Phase-B entry barrier (MORI_HIER_PHASEB_ENTRY_BA…
inkcherry Jul 4, 2026
1bcc08f
ccl(hier-ring): env-gated put-with-signal ring send (MORI_HIER_RING_P…
inkcherry Jul 4, 2026
dcb7de0
ccl(hier-ring): port put-with-signal to the multi-QP FANOUT path (MOR…
inkcherry Jul 4, 2026
aeba23e
core(rdma-ionic): add WRITE_WITH_IMM send device primitive (PostWrite…
inkcherry Jul 4, 2026
1fd6178
core(rdma-ionic): add WRITE_WITH_IMM receiver CQ-poll primitive (Poll…
inkcherry Jul 4, 2026
8bfc9b3
core(rdma-ionic): optional dedicated recv CQ for WRITE_WITH_IMM (conf…
inkcherry Jul 4, 2026
60b8529
ccl(hier): crown fill + chunk-pipelined DEEP_PIPE + host-proxy inter …
inkcherry Jul 8, 2026
97dc115
ccl(hier): DEEP_PIPE=16 -> all-size UT parity (>=1.0x) + reassembly S…
inkcherry Jul 9, 2026
3e1448e
Merge ROCm/mori main and finalize hierarchical AllGather
inkcherry Jul 13, 2026
ac56e73
docs(hier-allgather): refresh results to the current bit-exact benchm…
inkcherry Jul 13, 2026
ebdde48
docs(hier-allgather): full size-sweep w8/w16 UT + GEMM-overlap + E2E
inkcherry Jul 13, 2026
3426d38
Add one-key UT/E2E run scripts (incl. GEMM-overlap UT) + w16 E2E host…
inkcherry Jul 13, 2026
baf5c60
examples(fsdp): w16 E2E uses deferred landing fence (no inline host-d…
inkcherry Jul 13, 2026
cb0b848
examples(fsdp): consolidate bench into bench_scripts/bench_results + …
inkcherry Jul 13, 2026
7fa429c
examples(fsdp): save raw w16 bench logs (force-add past *.log gitignore)
inkcherry Jul 13, 2026
e01c144
examples(fsdp): slim bench to ut / ut-overlap / e2e (script + log + f…
inkcherry Jul 13, 2026
a9fd33e
overlap-UT: route through standalone_fast crown path (env MORI_HIER_U…
inkcherry Jul 13, 2026
c0b5e80
overlap-UT: persistent buffer pool for the crown route (unblock MORI_…
inkcherry Jul 13, 2026
8b1229d
inter-node AG: env-gated CU-yield backoff in RDMA landing spins (defa…
inkcherry Jul 13, 2026
b48e085
inter-node AG: enable CU-yield backoff N=2 for overlap measurement
inkcherry Jul 13, 2026
bc3f598
inter-node AG: gate CU-yield backoff OFF (kHierInterPollSleep=0) for …
inkcherry Jul 13, 2026
2fa62a4
host-proxy: env-gated ASYNC _post/_complete counter diagnostic (defau…
inkcherry Jul 13, 2026
f68f44c
host-proxy: double-buffered recv staging for ASYNC (MORI_HOSTPROXY_AS…
inkcherry Jul 13, 2026
57961de
host-proxy: ASYNC host-drain discriminator (MORI_HOSTPROXY_ASYNC_DRAI…
inkcherry Jul 13, 2026
8014a76
host-proxy: ASYNC auto-enables DRAIN+RING (bit-exact 269 TFLOPS, 1.07…
inkcherry Jul 13, 2026
757b005
examples(fsdp): w16 E2E run script defaults to host-proxy ASYNC (bit-…
inkcherry Jul 14, 2026
a042a76
examples(fsdp): add MI355X + AINIC (ionic) w16 E2E results + reproduc…
inkcherry Jul 14, 2026
89c331d
examples(fsdp): add host-proxy ASYNC w16 E2E loss+tflops curves (MI30…
inkcherry Jul 14, 2026
c375abe
examples(fsdp): run_e2e mode-selects env (mori=host-proxy / mori-ibgd…
inkcherry Jul 14, 2026
0ae5025
examples(fsdp): remove unused legacy mori_hier_allgather.py
inkcherry Jul 14, 2026
9f4025e
fix(hier-allgather): correct sub-group SDMA drain index (fixes host-p…
inkcherry Jul 14, 2026
c4eb8ae
perf(hier-allgather): realize the intra-SDMA CU-freedom dividend (hp_…
inkcherry Jul 15, 2026
9127d39
docs(hier-allgather): w16 E2E loss+tflops figures (RCCL / hp_sdma / h…
inkcherry Jul 15, 2026
7ffc420
docs(hier-allgather): consolidate w16 results — keep only combined fi…
inkcherry Jul 15, 2026
ab953b9
bench(e2e): run_e2e.sh selects the 4 named configs (RCCL / hp_sdma / …
inkcherry Jul 15, 2026
a7143cd
examples(fsdp): refresh MI355X+AINIC w16 E2E figures + raw logs
inkcherry Jul 15, 2026
9930165
bench(e2e): PLATFORM choice for run_e2e.sh (mi300x_mlx5 | mi355x_ainic)
inkcherry Jul 15, 2026
22c6706
test(ccl): cross-node overlap UT — GEMM runs faster under hp_sdma tha…
inkcherry Jul 15, 2026
c444469
bench: remove the superseded GEMM-overlap UT (ut_overlap_w16) in favo…
inkcherry Jul 15, 2026
8de01ea
ccl: skip RDMA MR registration for the SDMA-only intra transit
inkcherry Jul 15, 2026
90ce927
examples(fsdp): mi355x_ainic w16 E2E figures/logs -> hp_sdma
inkcherry Jul 15, 2026
a4e65eb
bench(ccl): cross-node AllGather UT with perf / E2E-stable switch pre…
inkcherry Jul 15, 2026
db6e008
bench(ccl): refine ag-perf E2E-stable chart (drop ratio labels, full-…
inkcherry Jul 15, 2026
cefc8d4
bench(fsdp): remove the old ut_w16.png UT chart
inkcherry Jul 15, 2026
f932507
examples(fsdp): gc.freeze after warmup removes the FSDP GC tail-spike
inkcherry Jul 15, 2026
12d5f2c
bench(ccl): drop per-point value labels on ag-perf chart (points only)
inkcherry Jul 15, 2026
856543b
bench(ccl): add run_ut_overlap.sh launcher for the cross-node overlap UT
inkcherry Jul 15, 2026
18ef908
docs(hier-allgather): clean up README + add UT/overlap/E2E reproduce …
inkcherry Jul 15, 2026
da593f9
examples(fsdp): add mi355x_ainic UT + E2E-stable AG-perf + overlap UT
inkcherry Jul 15, 2026
9acf8fa
chore(fsdp): relocate bench artifacts + move feature README out of re…
inkcherry Jul 15, 2026
4e4be8a
style(ccl): satisfy pre-commit on the ag-perf UT scripts
inkcherry Jul 17, 2026
d5f08e6
refactor(fsdp): move UT launchers + plotter out of the tests tree
inkcherry Jul 17, 2026
5391b5e
refactor(ccl): drop two dead files from the test tree
inkcherry Jul 17, 2026
c6fb756
refactor(fsdp): results layout — figures at top, logs+csv+plotters un…
inkcherry Jul 17, 2026
ae1a4bc
chore: neutralize the core.* .gitignore comment
inkcherry Jul 17, 2026
2978808
fix(memory): free peerRkeys2 host+GPU in DeregisterSymmMemObj (B11 leak)
inkcherry Jul 17, 2026
65c03e2
fix(sdma): drop [SDMAENG] fputs, dead commented std::cout, REFUTATION…
inkcherry Jul 17, 2026
39cb1cd
fix(mlx5): remove [DIAG_QP_MTU] std::cout, trim ECMP investigation co…
inkcherry Jul 17, 2026
44033bb
fix(allgather): remove in-kernel debug printf on data path (B3)
inkcherry Jul 17, 2026
95bab48
fix(pybind): correct stale 'inert until wired' comments, drop PHASE-4…
inkcherry Jul 17, 2026
a631305
docs(sdma): replace debugging-journal comments with contract comments…
inkcherry Jul 17, 2026
e09654b
docs(allgather): strip Txx/PHASE-N campaign tags from kernel comments…
inkcherry Jul 17, 2026
05185ad
fix(ccl): ruff+black on hier_allgather.py — drop unused G, rename O->…
inkcherry Jul 17, 2026
1b11498
chore(ccl): delete dead fsdp_prefetch.py — zero imports, bench.py dup…
inkcherry Jul 17, 2026
48831f2
chore(ccl): delete dead drain_deferred method — zero callers in repo …
inkcherry Jul 17, 2026
889c9f8
fix(ccl): remove default-OFF WRITE_IMM known-bug branch + os.environ …
inkcherry Jul 17, 2026
4fc514d
docs(ccl): rewrite docstrings for shipped multi-node path; drop DESIG…
inkcherry Jul 17, 2026
4d71e7c
docs(ccl): strip agent-process narration from comments/docstrings; ad…
inkcherry Jul 17, 2026
541ece8
docs(ccl): strip agent-process narration from hier_allgather.py comme…
inkcherry Jul 17, 2026
3af6f2a
docs(ccl): strip agent-process narration from hier_allgather.py comme…
inkcherry Jul 17, 2026
3ece74d
docs(ccl): strip agent-process narration from hier_allgather.py comme…
inkcherry Jul 17, 2026
8cd477b
docs(ccl): strip agent-process narration from hier_allgather.py comme…
inkcherry Jul 17, 2026
60c4335
docs(ccl): sanitize leaked cluster hostnames + strip residual turn ma…
inkcherry Jul 17, 2026
7013c72
docs(ccl): add missing MIT header to hostproxy_inter.py + strip direc…
inkcherry Jul 17, 2026
514d9d7
refactor(ccl): consolidate __init__ __all__ + hoist host_proxy_ag imp…
inkcherry Jul 17, 2026
68c05a0
fix(examples): ruff E741/E402 in mori_allgather.py (C4)
inkcherry Jul 17, 2026
7b2cebd
fix(examples): remove dead code + leaked path from bench.py (C4/C5/A#1)
inkcherry Jul 17, 2026
7cf9c2c
chore(examples): delete orphaned run_ut.sh launcher (A#8)
inkcherry Jul 17, 2026
16c5f1e
chore(examples): sanitize internal paths/hosts from bench logs, scrip…
inkcherry Jul 17, 2026
de5fdc1
docs(examples): fix figure-regeneration claim + link mi355x results (…
inkcherry Jul 17, 2026
b0d3644
docs(examples): strip agent-process narration from mori_allgather.py …
inkcherry Jul 17, 2026
fda88c7
docs(examples): document the torch FSDP overlay requirement in bench.…
inkcherry Jul 17, 2026
728c350
fix(tests): remove unused first_bad var (finding D#0 F841)
inkcherry Jul 17, 2026
63d4d3f
fix(tests): bind h_def/h_oip as closure params to satisfy ruff F821 (…
inkcherry Jul 17, 2026
e8652ff
fix(tests): split semicolon statements + bind h closure param, ruff g…
inkcherry Jul 17, 2026
d87a05e
test(ccl): add pytest entrypoint to GPU-free CPU spec test + repair g…
inkcherry Jul 17, 2026
ae1262d
test(ccl): add pytest.mark.skipif for <2 GPUs so CI skips not errors …
inkcherry Jul 17, 2026
e32eb89
test(ccl): add pytest entrypoints + torchrun skipif to cross-node har…
inkcherry Jul 17, 2026
eff6bd2
docs(ccl): document determinism test's scalar gate + where bit-exact …
inkcherry Jul 17, 2026
1a84a5f
test(ccl): add pytest entrypoint + torchrun skipif to overlap_w16 ben…
inkcherry Jul 17, 2026
14ea8b0
style: apply the repo's pinned clang-format/black to the remaining PR…
inkcherry Jul 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ python/mori/_jit_sources/

# Bundled tools/*.sh files copied into the package at build time
python/mori/tools/*.sh

# crash core dumps
core.*
138 changes: 138 additions & 0 deletions examples/fsdp_sdma/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# ccl: hierarchical cross-node AllGather (intra-node SDMA + inter-node RDMA)

## Summary

Adds a hierarchical AllGather to MORI-CCL (`mori.ccl.HierAllGather`, an
`all_gather_into_tensor`-compatible collective) that keeps intra-node traffic on
the GPU **SDMA copy engines** (XGMI) and moves inter-node traffic over **RDMA**
(NIC).

Motivation is **compute/communication overlap**: the collective runs
on the dedicated SDMA copy engines instead of the compute units, so an AllGather
issued concurrently with a GEMM does not steal CUs from the GEMM — parity with
the native (non-SDMA) path standalone, and a strict win when overlapped with
compute.

## Design

- Intra-node phase: SDMA sub-group gather over XGMI (no CU usage, no NIC).
- Inter-node phase: RDMA ring exchange of node-blocks over the NIC.
- Fused `ring || local-gather` kernel: the inter-node RDMA ring and the
ring-independent local node-block SDMA gather run concurrently in one grid,
stream-ordered, direct-to-output (no staging copy).
- Correctness: **bit-exact** vs `torch.distributed.all_gather_into_tensor`
(zero tolerance) for `{bf16, fp16, fp32, int32}`, all tested sizes.

## API

```python
from mori.ccl import HierAllGather

ag = HierAllGather(
my_pe=rank, npes=world_size, ranks_per_node=local_world_size,
input_buffer_size=per_rank_bytes,
output_buffer_size=per_rank_bytes * world_size,
copy_output_to_user=True,
)
ag(input_tensor, output_tensor, numel, stream) # intra=SDMA, inter=RDMA
```

## Results (MI300X, mlx5 RoCEv2 — w16 = 2 node × 8 GPU; all bit-exact vs RCCL)

Raw logs, CSVs, and the plot scripts live under
[`bench/`](bench/). The standalone AllGather-bandwidth figure is regenerated
from that data by `plot_ag_perf.py` (see **Reproduce**); the overlap and E2E
figures below are captured artifacts from the runs whose raw logs are committed
alongside them.

### 1. Standalone AllGather bandwidth vs RCCL (E2E-stable config)

The shipped E2E construction (`MORI_HIER_UT_FAST=0`, device `ibgda_sdma`) is
bit-exact and tracks RCCL closely, converging as the message grows. A single
AllGather is **not** where the win is — the collective is network-bound and
GPU-light, so standalone bandwidth is near-parity, not a beat:

| per-rank size | ibgda_sdma / RCCL |
|--------------:|:-----------------:|
| 64 MB | 0.90× |
| 128 MB | 0.94× |
| 256 MB | 0.95× |
| 512 MB | 0.96× |

![standalone AllGather bandwidth](bench/results/mi300x_mlx5/ag_perf_e2e_stable_w16.png)

### 2. GEMM time under concurrent AllGather (the no-CU-contention dividend)

Where the win actually comes from: RCCL's CU-resident AllGather kernels steal the
GPU from concurrent GEMMs; `hp_sdma` keeps the cross-node leg on the CPU and the
intra-node leg on the SDMA copy engine, so the GEMMs finish faster while 50
AllGathers run concurrently (lower = better, bit-exact vs RCCL):

| 50 AGs ‖ 50 GEMMs | RCCL | hp_sdma | speedup |
|---|--:|--:|:--:|
| 8 MB, GEMM n=2048 | 3.5 ms | 2.6 ms | 1.33× |
| 8 MB, GEMM n=4096 | 17.5 ms | 15.8 ms | 1.11× |
| 16 MB, GEMM n=4096 | 19.1 ms | 16.0 ms | 1.20× |

![GEMM time under concurrent AllGather](bench/results/mi300x_mlx5/overlap_w16_gemm_time.png)

### 3. End-to-end FSDP2 (Qwen-7B, seq 2048, w16) — drop-in MoriAllGather

Training loss is bit-identical to the native run over the whole curve while step
throughput beats the framework default. Three mori variants (intra × inter leg):

| variant | inter-node leg | intra-node leg | throughput vs RCCL |
|---|---|---|--:|
| `hp_sdma` | host-proxy (CPU-posted RDMA) | SDMA (XGMI, CU-free) | ~1.20× |
| `hp_cu` | host-proxy | NCCL (CU) | ~1.10× |
| `ibgda_sdma` | device IBGDA (GPU-posted RDMA) | SDMA | ~1.07× |

![E2E loss](bench/results/mi300x_mlx5/e2e_all_w16_loss.png)
![E2E throughput](bench/results/mi300x_mlx5/e2e_all_w16_tflops.png)

## Second platform (MI355X + AINIC / ionic)

A parallel w16 FSDP2 E2E result set on AMD **MI355X** GPUs with the **AINIC
(ionic)** RoCEv2 NIC is committed under
[`bench/results/mi355x_ainic/`](bench/results/mi355x_ainic/README.md) — same
`run_e2e.sh` script with the ionic node pair / NIC env, headline ~1.08×
TFLOPS/GPU vs native with bit-identical loss. See that README for the numbers
and the exact ionic overrides.

## Reproduce

All launchers live in `bench/scripts/`. Each one drives the 2-node run itself
(ssh into master + worker, clear stale procs, start `torchrun`); the UT sources
are in `tests/python/ccl/`. The node pair / NIC list is at the top of each script
(env-overridable: `MASTER`/`WORKER`/`IFACE`/`MORI_RDMA_DEVICES`/…). Raw logs +
figures land under `bench/results/mi300x_mlx5/`.

```bash
cd examples/fsdp_sdma/bench/scripts

# 1) Standalone AllGather bandwidth UT (device ibgda_sdma vs RCCL)
# -> ../results/mi300x_mlx5/ag_perf_e2e_stable_w16.png
bash run_ut_ag_perf.sh e2e 64 128 256 512 # E2E-stable (shipped) config
bash run_ut_ag_perf.sh perf 64 128 256 512 # pure-perf (standalone_fast, NOT E2E-legal), for context
python ../results/mi300x_mlx5/raw/plot_ag_perf.py # (re)draw the figure from the run (or committed CSV)

# 2) Compute/comm overlap UT (GEMM time under 50 concurrent AGs, hp_sdma vs RCCL)
# -> ../results/mi300x_mlx5/overlap_w16_gemm_time.png (args: gemm_n size_mb nops)
bash run_ut_overlap.sh 2048 8 50
bash run_ut_overlap.sh 4096 8 50
bash run_ut_overlap.sh 4096 16 50

# 3) End-to-end FSDP2 (Qwen-7B): RCCL baseline + one mori variant, bit-exact loss + tflops
bash run_e2e.sh # RCCL + hp_sdma (default)
bash run_e2e.sh hp_cu
bash run_e2e.sh ibgda_sdma
WORLD=w8 bash run_e2e.sh # world=8 (default w16)
```

## Test plan

- [x] Bit-exact vs `torch.distributed.all_gather_into_tensor` for
`{bf16, fp16, fp32, int32}` on every tested size (true 2-node, world=8 & 16).
- [x] Standalone AllGather bandwidth sweep, E2E-stable config (near-parity, bit-exact).
- [x] Compute/comm overlap UT — GEMM finishes 1.1–1.3× faster under 50 concurrent AGs.
- [x] End-to-end FSDP2 training, loss bit-identical to native at world=8 & 16.
Loading
Loading