Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
f48a595
feat(cco): FlyDSL LSA all-reduce benchmarked against aiter custom AR
yangyuhuiling Sep 7, 2026
30ddad9
perf(cco): bring the FlyDSL LSA all-reduce to parity with aiter
yangyuhuiling Sep 8, 2026
0f4d277
feat(cco): SDMA all-reduce in FlyDSL, and settle the _ns/quiet question
yangyuhuiling Sep 8, 2026
3bdc32a
feat(cco): fuse the AR scatter into aiter's 8-wave GEMM epilogue
yangyuhuiling Sep 8, 2026
16ddbb9
perf(cco): profile the fused GEMM+AR; the cost is a quadratic release…
yangyuhuiling Sep 8, 2026
1b5b427
perf(cco): ATT-guided fixes to the fused epilogue, 450us -> 413us
yangyuhuiling Sep 8, 2026
60996cf
perf(cco): size the SDMA reduce grid independently; 342us -> 294us
yangyuhuiling Sep 8, 2026
b4ed569
perf(cco): price the fused epilogue's fence in isolation (--no-put, n…
yangyuhuiling Sep 8, 2026
c73efe1
fix(cco): the fused GEMM+AR had two races; correct the record and the…
yangyuhuiling Sep 8, 2026
d6fb537
perf(cco): the fused epilogue never needed a release fence; 440us -> …
yangyuhuiling Sep 8, 2026
b5e5916
feat(cco): port gcnasm's Direct LSA fusion; it absorbs the transfer b…
yangyuhuiling Sep 8, 2026
72c47de
perf(cco): MFMA operand swap for a wider C store -- correct, and not …
yangyuhuiling Sep 8, 2026
f555292
perf(cco): --swap-ab --permlane, bit-exact and 3.3% off the GEMM
yangyuhuiling Sep 8, 2026
0b26ebf
perf(cco): port gcnasm's lane transpose too; C store now 6.7% off the…
yangyuhuiling Sep 8, 2026
76e285b
fix(cco): wire the lane transpose into fused-lsa, and fail loudly on …
yangyuhuiling Sep 8, 2026
8bd495d
docs(cco): persistent tiles tried and rejected -- FlyDSL spills throu…
yangyuhuiling Sep 8, 2026
4ec4e3b
docs(cco): correct the persistent-tile diagnosis -- it is VGPRs, not …
yangyuhuiling Sep 8, 2026
a03d5a0
fix(cco): the fused epilogue raced on a barrier phase, not a queue
yangyuhuiling Sep 8, 2026
40f4d39
docs(cco): rewrite the race section for the barrier-phase cause; repa…
yangyuhuiling Sep 8, 2026
ddb48d8
fix(cco): close the half-wave barrier pair unconditionally, as gcnasm…
yangyuhuiling Sep 8, 2026
9f8e0e7
perf(cco): --hoist-scales -- the redundancy is real, removing it is n…
yangyuhuiling Sep 8, 2026
0f2aa74
fix(cco): fused-lsa is correct now -- the producing kernel has to pub…
yangyuhuiling Sep 8, 2026
1c661cb
fix(cco): fused-lsa is correct now -- publish from the producing kernel
yangyuhuiling Sep 8, 2026
69c6896
fix(cco): the 8wave GEMM under-waits on one s_waitcnt, corrupting lar…
yangyuhuiling Sep 9, 2026
73c0865
perf(cco): turn the three C-store stages on by default in the benchmark
yangyuhuiling Sep 9, 2026
2cd72de
perf(cco): unblock --chunks, and fused-sdma finally beats split
yangyuhuiling Sep 9, 2026
5cd5250
perf(cco): port gcnasm's striped tile order, -12.5% on fused-lsa
yangyuhuiling Sep 9, 2026
253c71b
perf(cco): sweep the whole stripe range, and drop the separate chunk-…
yangyuhuiling Sep 9, 2026
3175289
fix(cco): the n_stripe guard rejected chunk-major on non-rotated builds
yangyuhuiling Sep 9, 2026
ef76030
feat(cco): support the model's fp8 block scale, and the fusion margin…
yangyuhuiling Sep 9, 2026
fd29138
fix(cco): adapt the raw buffer ops to FlyDSL 0.3.2's aux signature
yangyuhuiling Sep 9, 2026
d823dae
feat(cco): make the SDMA queue count a parameter, and default the pip…
yangyuhuiling Sep 10, 2026
e675079
bench(cco): port CK's 4-wave B-out-of-LDS GEMM, and find the gap is e…
yangyuhuiling Sep 10, 2026
1d6c568
bench(cco): apply the scale a tile at a time in preshuffle4w, as CK does
yangyuhuiling Sep 10, 2026
4f9b998
bench(cco): align preshuffle4w to CK at 64x256, and the GEMM lands on it
yangyuhuiling Sep 10, 2026
fc89289
bench(cco): migrate swap_ab to preshuffle4w -- it aligns the instruct…
yangyuhuiling Sep 10, 2026
ed2e66a
bench(cco): attribute swap_ab's register cost -- it is entirely the C…
yangyuhuiling Sep 10, 2026
63bc1ab
bench(cco): give swap_ab a register-free write-out -- and it changes …
yangyuhuiling Sep 10, 2026
c4c536a
bench(cco): the scheduling lead is dead, and so is the premise it res…
yangyuhuiling Sep 10, 2026
ec1f31b
bench(cco): read the loop bodies side by side -- the gap is stalls, n…
yangyuhuiling Sep 10, 2026
72b2b8c
bench(cco): the tight vmcnt waits are the scale loads, and they cost …
yangyuhuiling Sep 10, 2026
1dead3f
bench(cco): ATT decodes with --eager, and it puts the gap in VALU and…
yangyuhuiling Sep 10, 2026
9f99063
bench(cco): the C store outlier resolves, and warns about reading ATT…
yangyuhuiling Sep 10, 2026
54fef96
bench(cco): the MFMA/VALU clumping is real, has a cause, and is not t…
yangyuhuiling Sep 10, 2026
cc69676
bench(cco): hardware counters say the work is identical and the wait …
yangyuhuiling Sep 10, 2026
e7225e6
delete the preshuffle4w negative result, keeping its findings
yangyuhuiling Sep 11, 2026
b00acd6
move the fused GEMM+AR into mori.ops.gemm_ar, and drop the aiter depe…
yangyuhuiling Sep 11, 2026
e760674
point the benchmarks and tests at the package, and de-aiter the tests
yangyuhuiling Sep 11, 2026
089d43e
gate the fused GEMM+AR on CI: numerics assert, timings record
yangyuhuiling Sep 11, 2026
2182d60
make the gemm_ar sources pass pre-commit
yangyuhuiling Sep 11, 2026
854bcbe
gemm_ar: add window_bytes_for, and take nranks off the Communicator
yangyuhuiling Sep 11, 2026
1358b7e
Merge remote-tracking branch 'origin/main' into xiangch/flydsl-cco-ar
yangyuhuiling Sep 11, 2026
f5d82cf
gemm_ar: give ArConfig an fp8 wire format, regions only
yangyuhuiling Sep 11, 2026
4f38b8b
gemm_ar: fp8 on the gather leg
yangyuhuiling Sep 11, 2026
a4ad014
gemm_ar: expose the fp8 gather on the op and the fused benchmark
yangyuhuiling Sep 11, 2026
67bffcf
gemm_ar: widen the fp8 conversions to a full 16B access per lane
yangyuhuiling Sep 12, 2026
2579649
gemm_ar: pull the fp8 gather over LSA and widen it in the same kernel
yangyuhuiling Sep 12, 2026
3eaaa3f
gemm_ar: record the LSA-pull sweep and the fused-reduce loss in the R…
yangyuhuiling Sep 12, 2026
53b418a
docs: add MORI-GEMM-AR-BENCHMARK
yangyuhuiling Sep 12, 2026
693fd54
gemm_ar: run on the flydsl the CI image actually pins
yangyuhuiling Sep 12, 2026
2673ea8
gemm_ar: fire the gather's puts from the reduce -- measured, and it l…
yangyuhuiling Sep 14, 2026
92a379c
gemm_ar: pay the publish release in the store policy, not in a fence
yangyuhuiling Sep 14, 2026
e5f712e
gemm_ar: hoist the loop-invariant lsa_ptr calls out of the band loop
yangyuhuiling Sep 14, 2026
2bc532b
cco: add Window.lsa_geometry / lsa_ptr_at, and measure that it change…
yangyuhuiling Sep 14, 2026
046391f
cco: global_load the window geometry, and convert every lsa_ptr in ke…
yangyuhuiling Sep 14, 2026
81fe2fe
cco: put the window-geometry caching in a class, not in every call site
yangyuhuiling Sep 14, 2026
536eba6
cco: CachedWindow in kernels_lsa and kernels_fused -- and the first r…
yangyuhuiling Sep 14, 2026
d5e26fa
gemm_ar: reuse w_pre instead of rebuilding the window twice more
yangyuhuiling Sep 14, 2026
7c8c9c7
cco: the scf-boundary note now points at hoisting, not at a line that…
yangyuhuiling Sep 14, 2026
96bd952
gemm_ar: fix fuse-reduce-push, broken by the CachedWindow conversion
yangyuhuiling Sep 14, 2026
83046d4
docs: the window-geometry result, and retract the "machine drift" claim
yangyuhuiling Sep 14, 2026
e3514e2
gemm_ar: fix the review's P1/P2 findings in the public op, and test t…
yangyuhuiling Sep 14, 2026
5576f50
gemm_ar: pin the payload map to m_max, so two shapes stop aliasing ea…
yangyuhuiling Sep 15, 2026
465547b
docs: the fp8 gather does not pay in the server, and the pull costs
yangyuhuiling Sep 15, 2026
3bde626
gemm_ar: stop guessing what an [M, K/128] scale means, and retract th…
yangyuhuiling Sep 15, 2026
f03469f
ci: teach the Triton ABI tests about the two new symbols, and run the…
yangyuhuiling Sep 15, 2026
c3177cb
gemm_ar: give every legal M a counter slot, instead of rationing eight
yangyuhuiling Sep 15, 2026
1531cfe
gemm_ar: prove the transport moves bytes before trusting anything it …
yangyuhuiling Sep 16, 2026
f4caced
gemm_ar: reject FNUZ and illegal tiles at the boundary, and fix the r…
yangyuhuiling Sep 16, 2026
dc8ba7f
gemm_ar: format the new assert the way black 25.1.0 wants it
yangyuhuiling Sep 16, 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
30 changes: 29 additions & 1 deletion .github/workflows/ci_cco.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
MORI_RDMA_DEVICES: ${{ matrix.rdma_devices }}
MORI_RDMA_SL: ${{ matrix.rdma_sl }}
MORI_RDMA_TC: ${{ matrix.rdma_tc }}
timeout-minutes: 30
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down Expand Up @@ -179,6 +179,34 @@ jobs:
cd $GITHUB_WORKSPACE && \
timeout 300 pytest tests/python/cco/test_sdma_api.py -v"

- name: Run CCO GEMM+AR numerics (up to 8 ranks)
run: |
# The op ships in mori.ops.gemm_ar, so run pytest from /tmp: from a
# repo cwd `python/mori/` shadows the install and a packaging miss
# (a subpackage find_packages never picked up) would read as green.
#
# test_gemm_ar_op.py is the public wrapper's own tests. The other two
# go through the benchmark, which calls the low-level builders, so
# they said nothing about that layer -- and three correctness bugs
# lived there behind a green suite.
$CT exec -e MORI_ENABLE_SDMA=1 -e MORI_SOCKET_IFNAME=lo $CONTAINER bash -c "\
cd /tmp && python -c 'import mori.ops.gemm_ar as g; print(g.GemmAllReduceOp)' && \
timeout 1800 python -m pytest -v \
$GITHUB_WORKSPACE/tests/python/cco/test_gemm_ar.py \
$GITHUB_WORKSPACE/tests/python/cco/test_gemm_ar_op.py \
$GITHUB_WORKSPACE/tests/python/cco/test_flydsl_ar.py"

- name: Run CCO GEMM+AR benchmark (8 ranks, accuracy-gated)
run: |
# Accuracy is a gate (validated + rel_l2); absolute timings are only
# recorded -- this runner is shared, so a microsecond threshold would
# fail on a busy box and pass a real regression on an idle one. The
# one perf assertion is relative (fused beats split, measured back to
# back). -s so the numbers reach the log for a bisect to read.
$CT exec -e MORI_ENABLE_SDMA=1 -e MORI_SOCKET_IFNAME=lo $CONTAINER bash -c "\
cd $GITHUB_WORKSPACE && \
timeout 1800 pytest -v -s tests/python/cco/test_gemm_ar_bench.py"

- name: Validate CCO ROCm runtime import order
run: |
$CT exec $CONTAINER bash -c "\
Expand Down
203 changes: 203 additions & 0 deletions benchmark/cco/flydsl/ar/_probe_lsa.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
#!/usr/bin/env python3
# Copyright © Advanced Micro Devices, Inc. All rights reserved.
#
# MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# Copyright © Advanced Micro Devices, Inc. All rights reserved.
# SPDX-License-Identifier: MIT
"""Toolchain probe: example 05's LSA all-reduce, ported onto ``_compat``.

Validates the pieces the real kernels depend on, on whichever flydsl is
installed: ``Window.lsa_ptr``, the uncached signal barrier, vectorized peer
reads, and the cco device-bitcode JIT.

MORI_SOCKET_IFNAME=lo mpirun --allow-run-as-root -np 2 python _probe_lsa.py
"""

import os
import sys

from mpi4py import MPI

import flydsl.compiler as flyc
import flydsl.expr as fx
from flydsl._mlir import ir
from flydsl._mlir.dialects import scf
from flydsl.expr import gpu as fgpu
from flydsl.expr import range_constexpr
from flydsl.expr.typing import Int32, Int64

import mori.cco.device.flydsl as cco
from mori.cco import CCODevCommRequirements, Communicator, GDA_CONNECTION_NONE

from mori.ops.gemm_ar._compat import (
CM_CACHED,
FLYDSL_VERSION,
buffer_load,
buffer_store,
create_buffer_resource_from_addr,
i32_type,
signal_load_u32,
signal_ptr,
signal_store_u32,
)

sys.path.insert(
0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "..", "..")
)
sys.path.insert(
0,
os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"..",
"..",
"..",
"..",
"examples",
"cco",
"python",
),
)
from cco_example_common import F32, fill, read, set_device, sync, zero # noqa: E402

WS = 2
THREADS = 256
NUM_ELEMS = 256 * 1024
ELEMS_PER_PACK = 4
NUM_PACKS = NUM_ELEMS // ELEMS_PER_PACK

SIG_OFF = 0
SIG_BYTES = 256
IN_OFF = SIG_BYTES
OUT_OFF = IN_OFF + NUM_ELEMS * 4
WIN_BYTES = OUT_OFF + NUM_ELEMS * 4


@flyc.kernel(known_block_size=[THREADS, 1, 1])
def probe_ar_kernel(dev_comm: Int64, win: Int64, flag: Int32):
tid = fx.thread_idx.x
dc = cco.DevComm(dev_comm)
w = cco.Window(win)
rank = dc.lsa_rank

ins = [fx.Int64(w.lsa_ptr(p, IN_OFF)) for p in range(WS)]
self_sig = fx.Int64(w.lsa_ptr(rank, SIG_OFF))
out = fx.Int64(w.lsa_ptr(rank, OUT_OFF))

# start-sync: publish my arrival to every peer, then wait for all of them.
if tid < WS:
peer_base = fx.Int64(w.lsa_ptr(tid, SIG_OFF))
signal_store_u32(signal_ptr(peer_base + fx.Int64(rank) * fx.Int64(4)), flag)

wait_addr = self_sig + fx.Int64(tid) * fx.Int64(4)
wait_rsrc = signal_ptr(wait_addr)
i32 = i32_type()
first = signal_load_u32(wait_rsrc)
first_v = first.ir_value() if hasattr(first, "ir_value") else first
loop = scf.WhileOp([i32], [first_v])
cond = ir.Block.create_at_start(loop.before, [i32])
body = ir.Block.create_at_start(loop.after, [i32])
with ir.InsertionPoint(cond):
cur = fx.Int32(cond.arguments[0])
should_wait = fx.Uint32(cur) < fx.Uint32(flag)
scf.ConditionOp(should_wait.ir_value(), [cond.arguments[0]])
with ir.InsertionPoint(body):
nxt = signal_load_u32(wait_rsrc)
scf.YieldOp([nxt.ir_value() if hasattr(nxt, "ir_value") else nxt])
fgpu.barrier()

out_rsrc = create_buffer_resource_from_addr(out)
in_rsrc = [create_buffer_resource_from_addr(ins[p]) for p in range(WS)]
for pk in range(tid, NUM_PACKS, THREADS):
elem_off = pk * ELEMS_PER_PACK
acc = None
for p in range_constexpr(WS):
raw = fx.Vector(
buffer_load(in_rsrc[p], elem_off, vec_width=4, dtype=i32_type())
)
vf = raw.bitcast(fx.Float32)
acc = vf if acc is None else acc + vf
buffer_store(
acc.bitcast(fx.Int32), out_rsrc, elem_off, cache_modifier=CM_CACHED
)


@flyc.jit
def run_probe(dev_comm: Int64, win: Int64, flag: Int32, stream=fx.Stream(None)):
probe_ar_kernel(dev_comm, win, flag).launch(
grid=(1, 1, 1), block=[THREADS, 1, 1], stream=stream
)


def main() -> int:
mpi = MPI.COMM_WORLD
rank, nranks = mpi.Get_rank(), mpi.Get_size()
if nranks != WS:
if rank == 0:
print(f"probe is built for world_size={WS} (mpirun -n {WS})")
return 1
set_device(rank)
uid = Communicator.get_unique_id() if rank == 0 else None
uid = mpi.bcast(uid, root=0)

errors = 0
with Communicator.init(nranks, rank, uid, per_rank_vmm=256 * 1024 * 1024) as comm:
mem = comm.alloc_mem(WIN_BYTES)
win = comm.register_window(mem.ptr, mem.size)
zero(win.local_ptr, WIN_BYTES)
fill(
win.local_ptr + IN_OFF,
[(rank + 1) * (i + 1) for i in range(NUM_ELEMS)],
F32,
)

reqs = CCODevCommRequirements()
reqs.gda_connection_type = GDA_CONNECTION_NONE
reqs.gda_signal_count = 0
reqs.gda_counter_count = 0
dc = comm.create_dev_comm(reqs)

comm.barrier()
run_probe(dc.ptr, win.handle, 1)
sync()
comm.barrier()

S = WS * (WS + 1) // 2
host = read(win.local_ptr + OUT_OFF, NUM_ELEMS, F32)
for i in (0, 1, NUM_ELEMS // 2, NUM_ELEMS - 1):
exp = float(S * (i + 1))
if abs(host[i] - exp) > 1e-3 * max(1.0, exp):
print(f"[rank {rank}] MISMATCH [{i}]: {host[i]} != {exp}", flush=True)
errors += 1
print(
f"[rank {rank}] flydsl={FLYDSL_VERSION} "
f"{'PROBE OK' if errors == 0 else 'PROBE FAILED'} "
f"out[0,1,-1]={[host[0], host[1], host[NUM_ELEMS - 1]]}",
flush=True,
)

all_err = mpi.allreduce(errors, op=MPI.SUM)
if rank == 0:
print("SUCCESS" if all_err == 0 else "FAILED", flush=True)
return 0 if all_err == 0 else 1


if __name__ == "__main__":
sys.exit(main())
Loading
Loading