Conversation
XSHMEM provides explicit comm-handle-based GPU communication with three
transport paths (P2P/RDMA/SDMA), replacing the singleton-based SHMEM design.
Host API (Phase 1 complete):
- XshmemCommCreate/Destroy: VMM flat VA reservation, RDMA QP setup via
Context, SDMA device handles, internal sync, groupId for LocalBootstrap
- XshmemMemAlloc/Free: VMM alloc (hipMemCreate + hipMemMap), local only
- XshmemWindowRegister/Deregister: P2P FD exchange + peer mapping, RDMA MR
registration (ibv_reg_dmabuf_mr iova=0), rkey Allgather, SDMA signals,
GPU-side XshmemWindowDevice construction
- XshmemDevCommCreate/Destroy: IBGDA context (QP endpoints + signal/counter
buffers + MR registration), window lookup table, H2D copy
Key design decisions:
- iova=0 RDMA: raddr = offset within window, no remote VA needed
- Flat VA addressing: winBase + pe * stride4G << 32 (NCCL-compatible)
- Per-window MR with XshmemIbgdaWin{peerRkeys, lkey}
- XshmemIbgdaContext bundles QP endpoints + signal/counter resources
- Window table (linked list) for XshmemFindWindow pointer lookup
- One DevComm per Comm (QP state safety)
- BUILD_TORCH_BOOTSTRAP default OFF
Also adds RegisterRdmaMemoryRegionDmabufIova0 to mori_application RDMA layer.
Tests: single-process multi-thread, fork multi-process, MPI — all 8-GPU on
MI355X + AINIC verified.
Each XshmemDevCommCreate now creates fresh QPs via Context::CreateAdditionalEndpoints + ConnectAdditionalEndpoints, instead of copying the original QP set from CommCreate.
- add XshmemGda object define - add xshmem gda device api define
Module-wide rename. No functional changes.
- Directories: include/mori/xshmem -> include/mori/cco,
src/xshmem -> src/cco, tests/cpp/xshmem -> tests/cpp/cco
- Files: xshmem_*.{hpp,cpp} -> cco_*.{hpp,cpp},
test_xshmem_*.cpp -> test_cco_*.cpp, xshmem.md -> cco.md
- Identifiers: XSHMEM -> CCO, Xshmem -> Cco, xshmem -> cco
(namespace mori::cco, CcoComm, CcoDevComm, CcoWindowDevice,
CcoCommCreate, CcoMemAlloc, CcoWindowRegister, CcoDevCommCreate,
CcoBarrierAll, CcoIbgdaContext, CcoIbgdaWin, CcoGda*, etc.)
- CMake: BUILD_XSHMEM -> BUILD_CCO, target mori_xshmem -> mori_cco
Co-authored-by: Cursor <cursoragent@cursor.com>
* gda_device_api.hpp: include path was "mori/Cco/gda/gda_device_common.hpp" (capital C) — actual directory is lowercase cco/. Originated from a typo in the initial xshmem commit (4f3aac9) where it wrote "mori/Xshmem/..." with a capital X; carried into cco by the module rename. * gda_device_common.hpp: was missing #pragma once, would break under multiple includes. Added license header for consistency too. Co-authored-by: Cursor <cursoragent@cursor.com>
…nvention
Codify the naming split that already emerged organically in the codebase:
* Host API (CommCreate / MemAlloc / WindowRegister / DevCommCreate / ...)
keeps mori's Google C++ style: PascalCase free fns with Cco prefix,
camelCase fields, SCREAMING_SNAKE constants.
* Device API (CcoGda / CcoLsa / CcoSdma / CcoLsaBarrierSession) follows
NCCL device API style (nccl_device/gin.h, nccl_device/lsa_barrier.h):
- PascalCase session class with Cco prefix
- camelCase member methods (put, flushAsync, readSignal)
- Cco<Module>_<Tag> tag types with underscore separator
- Cco<...>_t typedefs for handles, _ prefix for internal members
- namespace-internal free functions are camelCase WITHOUT Cco prefix
(the namespace already disambiguates)
This split mirrors the existing layering: host operates over
mori_application primitives, device operates over per-backend session
contexts. The convention is documented in cco.md so future contributors
don't have to guess.
Concretely:
* cco.md: new "命名约定 (Naming Convention)" section right after 背景,
with full rule tables for host vs device and 4 共同约定 bullets;
Device API section rewritten from outdated mori-style CcoP2pPutThread/
CcoRdmaPutThread free fns to NCCL-style CcoGda / CcoLsa / CcoSdma
session classes with a user-facing kernel usage example; file
structure diagram extended with future lsa/ and sdma/ subdirs.
* cco_device_api.hpp: dropped redundant Cco{Rdma,P2p,Sdma}PutThread,
CcoReadSignal/WaitSignal/Counter, CcoBarrierAllBlock — all subsumed
by per-backend session classes. Kept the genuinely common helpers
(findWindow, getPeerPtr, getLocalPtr) and renamed to camelCase
without Cco prefix to match the new convention. Phase 2 session
classes (CcoLsa, CcoSdma, CcoLsaBarrierSession) are noted in a
placeholder block.
* cco_device.hpp: umbrella header now pulls in both the common device
helpers and the GDA backend; removed redundant include of
gda_device_common.hpp (transitively pulled by gda_device_api.hpp).
No source files (.cpp) are touched; this is a header + docs change only.
Co-authored-by: Cursor <cursoragent@cursor.com>
…ce Window pattern (#336) Brings CCO host API to the Phase 1 + Phase 2 surface. After this PR, CCO has: - Stable user-facing API: `CcoCommCreate/Destroy`, `CcoMemAlloc/Free`, `CcoWindowRegister/Deregister` (two overloads), `CcoDevCommCreate/Destroy`, `CcoBarrierAll`. - Forward-compatible `CcoDevCommRequirements` (size/magic/version triplet) driving GDA connection type + per-DevComm resource sizing. - All four `CcoGdaConnectionType` modes implemented and tested: `NONE`, `CROSSNODE` (default), `FULL`, `RAIL` (same-lsaRank cross-node). - **Resource window** pattern: a single symmetric, dma-buf-MR registered, P2P-imported buffer backing every per-DevComm session resource (IBGDA signal pool + LSA barrier slabs). Allocated via VMM (`hipMemCreate` + `hipMemMap`), NOT `hipMalloc`, to satisfy LSA flat-VA addressing. - Four barrier handles in `CcoDevComm`: - `lsaBarrier` — standalone LSA barrier (resource window slab) - `hybridLsaBarrier` — hybrid LSA half (resource window slab) - `railGdaBarrier` — standalone rail GDA (IBGDA signal slots) - `hybridRailGdaBarrier` — hybrid rail half (IBGDA signal slots) - `resourceWindow` + `resourceWindow_inlined` (32B kernel-cmem copy) in `CcoDevComm`. Kernels read `winBase` / `stride4G` / `ibgdaWin.{lkey,peerRkeys}` directly from cmem with no GPU global memory dereference. - `Context` refactored into capability discovery (`PeerCapabilities`) + policy (`peerMask`), letting CCO drive QP setup without touching Context's defaults. - `HeapVAManager` replaces the original inline slot allocator for flat-VA management. - SPMT (single-process multi-thread) safe across bootstrap / Context / anvil / SDMA signal pool. `Context::SameProcessP2P(peer)` switches SDMA signal exchange between IPC handle and raw VA + `hipDeviceEnablePeerAccess`.
* feat(cco): typo and add gda primitive impl
ROCm 7.0 introduced a regression in `hipMemSetAccess`: when validating
sub-buffer coverage for a hipMemAddressReserve parent containing multiple
hipMemMap'd sub-buffers, the driver iterates from the parent's sub-buffer
0 (ignoring the ptr argument), so the call fails with hipErrorInvalidValue
whenever size != prefix sum starting at sub-buffer 0.
This affects CCO's symmetric flat-VA pattern (one reserve + many maps).
Reproducible: alloc(4 MiB) then alloc(4 KiB) → 2nd hipMemSetAccess fails.
Status:
- Bug present in all released ROCm 7.x (verified 7.0 → 7.2.3).
- Fix merged to clr/develop on 2026-01-26 as rocm-systems#2451
(commit be8bcd059); not yet cherry-picked to any release branch.
- External report: rocm-systems#2516 (open since 2026-01).
This commit patches the dev docker image to build a fixed libamdhip64.so
from the base image's matching rocm-X.Y.Z release branch plus the
cherry-picked fix. Auto-detects ROCm version from /opt/rocm/.info/version
and the target so-stamp from the libamdhip64.so.7 symlink, so the same
RUN block works across ROCm 7.2.0/1/2/3 on Ubuntu 22.04/24.04. ROCm 6.x
base images skip the patch (no bug).
Verified (cherry-pick + build + CCO test pass):
- rocm-7.2.0 / 7.2.1 / 7.2.2 / 7.2.3 × Ubuntu 22.04 / 24.04
* Implement lsa barrier API (#338) Co-authored-by: Qizhou Zhang <qizzhang@smci355-ccs-aus-n06-21.prov.aus.ccs.cpe.ice.amd.com>
* feat(cco): add device api ut and refactor the gda code hierarchy to decouple low-level nic operations from high-level window-base api * fix sigal mr offset * fix ut building failed
rm multimem in lsa (#350) Co-authored-by: Qizhou Zhang <qizzhang@smci355-ccs-aus-n06-21.prov.aus.ccs.cpe.ice.amd.com>
* add lsa mem check example & fix double unmap in ccoCommDestroy * Hip mem leak will be resolved by this PR: ROCm/rocm-systems#4363 Co-authored-by: Qizhou Zhang <qizzhang@smci355-ccs-aus-n06-21.prov.aus.ccs.cpe.ice.amd.com>
(format) fmt source files Co-authored-by: Qizhou Zhang <qizzhang@smci355-ccs-aus-n08-25.prov.aus.ccs.cpe.ice.amd.com>
* Add uts for host and lsa api Co-authored-by: Qizhou Zhang <qizzhang@smci355-ccs-aus-n06-21.prov.aus.ccs.cpe.ice.amd.com>
* reorganize device header Co-authored-by: Qizhou Zhang <qizzhang@smci355-ccs-aus-n06-21.prov.aus.ccs.cpe.ice.amd.com>
* add support for gda coop group * add signal test
…contained bootstrap (#375) - Consolidate the CCO surface into one header (include/mori/cco/cco.hpp); delete the split headers. GDA impl moved to mori::cco::impl; gda namespace dropped. - Decouple cco from shmem via application::RdmaEndpointDevice. - Add ccoUniqueId + ccoGetUniqueId + ccoCommCreate(uid, nRanks, rank, ...): bootstrap with only cco.hpp; BootstrapNetwork* overload kept. - LSA examples bootstrap via ccoUniqueId; extend host-API + barrier coverage. Verified on MI300X+BNXT: builds; cco tests pass single-node & 2-node; LSA examples pass.
…loc / copies) ccoDevCommCreate now fills a caller-provided host ccoDevComm in place int ccoDevCommCreate(ccoComm*, const ccoDevCommRequirements*, ccoDevComm* outDevComm); instead of allocating one on the device and returning a pointer. The struct holds device pointers but lives on the host, so kernels take it by value (it lands in kernel-arg space — no per-access GPU-memory dereference). This drops the device allocation + HostToDevice copy in create, and the DeviceToHost copy every consumer previously did to obtain a by-value snapshot. ccoDevCommDestroy reads the host struct directly (no copy-back) and no longer frees a device struct; it still releases the device resources the struct references (QP endpoints, SDMA pools, window table).
…#377) * feat(cco): support BNXT for GDA + runtime provider dispatch in gda tests * refactor(cco): split GDA device layer into cco_scale_out.hpp * test(cco): move LSA examples into the cco test suite
Add some gda UTs & abstract the common component of cco tests --------- Co-authored-by: Qizhou Zhang <qizzhang@smci355-ccs-aus-n06-21.prov.aus.ccs.cpe.ice.amd.com>
quietUntil polls the CQ in a nested loop until doneIdx reaches targetIdx. The inner loop breaks when a poll yields no new CQE — which happens normally while a transfer is still in flight — and the outer loop then hit an unconditional break, exiting the whole function without re-checking whether the target was actually reached. So when the CQE wasn't ready yet, quietUntil returned early and ccoGda::flush() returned mid-transfer, stopping the timer too soon Co-authored-by: Qizhou Zhang <qizzhang@smci355-ccs-aus-n06-21.prov.aus.ccs.cpe.ice.amd.com>
…#393) * refactor(cco): make cco.hpp self-contained and HIP-runtime-header-free * feat(cco): compile-time per-NIC GDA provider dispatch * refactor(cco): keep GDA provider as an informational ccoComm field
Motivation Add a CCO p2p microbenchmark suite (put/get × bw/latency) mirroring benchmark/shmem/, covering both transports: LSA (intra-node P2P) and IGBDA (cross-node RDMA). Technical Details New benchmark/cco/ with 4 binaries; transport chosen via MORI_DISABLE_P2P. Issues found & fixed: quietUntil (PSD) returned mid-transfer — unconditional break abandoned the CQ wait, inflating BW to multi-TB/s. Now breaks only on error. LSA bw cache absorption — added per-iter __threadfence_system(). 32-QP doorbell contention destabilized mid-size BW. Build: BUILD_BENCHMARK now implies MPI; util.cpp builds as CXX. Test Result LSA/IGBDA saturate near NIC limit; GDA tests pas Co-authored-by: Qizhou Zhang <qizzhang@smci355-ccs-aus-n06-21.prov.aus.ccs.cpe.ice.amd.com>
minor fix benchmark Co-authored-by: Qizhou Zhang <qizzhang@smci355-ccs-aus-n06-21.prov.aus.ccs.cpe.ice.amd.com>
…son (#407) LSA scope & sync aligned with shmem: all block threads now always participate — scope_size only sets copy granularity (block strides the whole chunk, warp per-wavefront, thread copies its own contiguous segment), instead of the old behavior that wrongly cut the thread count for thread/warp scope. Added a per-round cross-block barrier (mirrors shmem's bw_cross_block_barrier_round) so the timed window includes the same synchronization, removing the artificial mid-size speedup. --------- Co-authored-by: Qizhou Zhang <qizzhang@smci355-ccs-aus-n06-21.prov.aus.ccs.cpe.ice.amd.com>
- BNXT GDA: advance PSN by packet count (not WQE count) on the warp-aggregate path; reserve-gate drains to the doorbelled snapshot to avoid SQ self-deadlock. MLX5/Ionic unchanged. - Group GDA doorbells per peer (__ballot) so mixed-peer thread/warp scope rings once per peer instead of coalescing into a dropped doorbell — unblocks thread/warp-scope bandwidth. - Rename WarpMode→ThreadMode (sub-mode is thread-scope, per-thread work unit): ccoGdaThreadIndependent / ccoGdaThreadAggregate. - Bench: per-message size + unit count, thread_agg scope, Mpps column.
* feat(cco): add support for cco python runtime api * add example * add cco decomm device bak for kernel launch * fix device ptr issue * remove host binding workaround
…lti-thread mode # Root cause ExchangeFileDescriptors bound each server socket lazily inside a per-peer loop and called a blocking accept() before binding later peers. A client could only connect once the server's loop reached it. In fork mode ranks enter near-simultaneously and win the race; in thread mode they serialize on HIP locks, so a server stuck in accept() hadn't yet bound the socket a later client needed → ENOENT, 5s timeout, then a cascading bail. Fix local_bootstrap.cpp: bind+listen all server sockets up front, then accept/connect; widen the connect retry window. cco_init.cpp: drop the leader-side blanket unlink (could delete a live socket) and add a per-clique discriminator to the socket path.
Fix GDA barrier hang on MLX5 The barrier deadlocked on MLX5: a rank rang all N atomic-signal doorbells, but peers saw only one and spun forever in the phase-2 wait. Cause: the multi-lane path assumed MLX5's per-QP dbrAddr made doorbell stores independent, so lanes rang directly. On this GPU the per-QP doorbell stores issued in one SIMT step coalesce — only one survives, the rest are dropped, so those QPs' WQEs are never fetched and peers hang. Fix: route MLX5 through the same per-lane serialized ringDoorbellWalk PSD/BNXT already use.
…ng (#426) - FlyDSL GDA/LSA device-IR bindings: scalar FFI, template axes monomorphized into tagged symbols (no runtime dispatch), bitcode JIT per arch+NIC. - C++ examples (examples/cco/cpp) + examples/cco split into python/ + cpp/. - End-to-end pip packaging: optional flydsl extra; BUILD_EXAMPLES / BUILD_BENCHMARK install binaries into the package. - fix: ccoCommDestroy unmaps symmetric allocations before freeing the flat VA.
Fix MLX5 collapsed-CQ completion reconstruction (stale-read / 16-bit wrap) Problem Mlx5CollapsedCqDrain (and the cco quietUntil equivalent) reconstructed the 32-bit completion counter from the CQE's low 16 bits by patching the high bits and adding 0x10000 on an apparent wrap. On a shared QP, a stale/concurrent CQE read (counter just behind doneIdx) looks like a 64K wrap, so doneIdx gets shoved past postIdx — after which every quiet early-exits and stops waiting for real completions. Fix Reconstruct as cons + forward 16-bit distance, accepting the advance only if it falls inside the in-flight window (cons, dbTouchIdx]: Handles 16-bit wrap automatically (small delta added to the full 32-bit cons). Rejects stale/torn reads (they produce a near-65536 delta, outside the window). window is signed: once doneIdx catches up to dbTouchIdx (window <= 0) every delta is rejected — avoids the unsigned underflow that defeated the bound when cons races ahead of a stale dbTouchIdx read. Changes shmem/shmem_ibgda_kernels.hpp, cco/cco_scale_out.hpp: windowed signed reconstruction (+ low-volume [DRAIN-BUG] tripwire). Bench default iters 10 → 100 (shmem & cco) to average out a hardware-level small-transfer timing jitter. Testing shmem/cco p2p_get_bw and p2p_put_bw stable across many runs; tripwire never fires; data verified correct.
Resolve the squash-sync divergence: dev/cco was previously kept current with main via a squash (#410) rather than a merge, so main's later commits conflicted against the stale snapshot. All 57 conflicts were in non-cco areas (src/umbp, src/io, src/application, tests, docs, CI, tuning_configs); resolved by taking main's current version for every one. src/cco (the module) merged cleanly and is unchanged.
…ang-format, ruff) The cco module files were committed without the pre-commit gate; apply it now so the dev/cco->main PR passes CI: insert missing license headers, black + clang-format reformat, and drop an unused `win` binding (ruff F841) in the barrier example.
Condense the redundant header/self-contained/intrinsic-wrapper blocks and the over-explained resource-window notes; keep the safety guards, HARD-CONTRACT invariants, and addressing formulas. Remove stray external-project references.
cco.md was an internal agent handoff doc (not a user guide) accidentally committed to the repo root; it also carried external references. Remove it.
…ide symbols) Absorb the application layer statically into libmori_cco.so so consumers link only libmori_cco.so with no runtime dependency on libmori_application.so, and no application-symbol leakage. - application sources -> shared OBJECT library feeding both mori_application (SHARED, unchanged interface for shmem/io/ops/…) and a new mori_application_static. - mori_cco absorbs the static archive via --whole-archive and localizes all absorbed static-archive symbols with --exclude-libs,ALL; only cco* API stays exported. Drops the mori_application/ibverbs links (ibv dlopen shim embedded). - cco-only C++ targets (tests/cpp/cco, cco benchmarks) link only mori_cco; add find_package(MPI) where MPI was previously pulled in transitively via mori_application. cco examples already linked only mori_cco.
The privileged container runs as root and leaves root-owned files in GITHUB_WORKSPACE, breaking the runner's later cleanup/checkout. chown the workspace back to the runner uid:gid before removing the container.
The dev/cco<-main merge left a stale copy of EpDispatchIntraNodeLLKernel_body in intranode.hpp (a squash-sync artifact); main had moved it to intranode_ll.hpp. Building AOT ops (BUILD_OPS_DEVICE=ON, as the JAX CI does) pulled in both headers and failed with duplicate-definition / redefined-default-argument. Take main's intranode.hpp so the body lives only in intranode_ll.hpp.
dev/cco is merging into main, so the cco CI (originally a temp job for the dev/cco branch) should run on push to main and PRs targeting main.
umbp added its tests subdir unconditionally, so any BUILD_UMBP=ON build (even BUILD_TESTS=OFF, e.g. BUILD_EXAMPLES=ON) configured umbp tests and FetchContent'd googletest from github — breaking builds on github-less runners. Gate it behind BUILD_TESTS like the top-level tests/cpp.
…emented Drop the stale 'TODO: not yet enforced' on FULL/RAIL: ccoDevCommCreate builds a distinct peerMask per connType and creates the matching QPs (no silent fallback to CROSSNODE). Note that FULL allocates intra-node QPs but the device GDA barrier path still prefers LSA for intra-node peers.
dev/cco renamed the shmem p2p benchmarks to shmem_p2p_* (to sit alongside the
new cco_p2p_* ones), but ci.yml's shmem_benchmark step runs ./build/benchmark/
p2p_{put,get}_{bw,latency} — so mpirun failed with "could not access or execute".
cco benchmarks keep the cco_ prefix (no clash); rename shmem ones back to the
unprefixed names main's CI expects.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Merges the
dev/ccodevelopment branch intomain, landing the CCO (Collective Communication Object) module — mori's self-contained collective/communication layer (formerlyxshmem). Highlights:DevCommRequirements, connection types, Team API, resource/window pattern; single-header consolidation and shmem decoupling with a self-contained bootstrap.tests/cpp/cco.Communicator(alloc_mem/register_window/create_dev_comm/barrier),UniqueId, resources.ci_ccoworkflow, anddocker/Dockerfile.cco.docs/MORI-CCO-GUIDE.md(linked from the docs index).Merge status — conflicts resolved ✅
dev/ccohad been kept current withmainvia a squash-sync (#410) rather than a merge, somainwas merged intodev/ccohere and the resulting divergence resolved. The branch is now MERGEABLE (no conflicts). How the ~57 conflicts + a few clean-but-wrong auto-merges were handled:src/umbp,src/io,src/applicationinternals, tests, docs, CI, tuning_configs) → tookmain's current version.umbp/master_client.h: the squash auto-merge produced duplicate declarations (semantic dup, no textual conflict) → reset tomain.src/ops/dispatch_combine/intranode.hpp: a stale copy still definedEpDispatchIntraNodeLLKernel_bodythatmainhad moved tointranode_ll.hpp(duplicate definition under AOT ops build) → reset tomain.RegisterRdmaMemoryRegionDmabufIova0(cco's iova=0 dmabuf MR for the BNXT-GDA flat-VA path) is a genuine cco addition to the application RDMA layer that a naive "take main" dropped → re-applied ontomain'srdma.hpp/rdma.cpp.symmetric_memory.cpp/ibverbs.cpp/anvil.cpphad no genuine cco change (take-main correct);shmem_ibgda_kernels.hppbugfix: shm spike bandwidth #431 fix already inmain.src/ccomerged cleanly and is unchanged.Validation: full
pip install .build (incl. AOT ops, examples) succeeds in theDockerfile.ccocontainer after the merge;mori.ccoimports.Self-contained libmori_cco.so
libmori_cco.sonow absorbs the application layer statically, so cco consumers link onlylibmori_cco.so(no runtime dependency onlibmori_application.so) with no application-symbol leakage:mori_application(SHARED, unchanged for shmem/io/ops/…) and a newmori_application_static.mori_ccoabsorbs the static archive via--whole-archiveand localizes all absorbed static-archive symbols with--exclude-libs,ALL; only thecco*API stays exported (exported symbols dropped 151 → 15). The ibverbs dlopen shim is embedded, so cco links neitherlibmori_application.sonorlibibverbs.tests/cpp/cco, cco benchmarks, cco examples) link onlymori_cco.For the LSA scenario this means: include only
mori/cco/cco.hppand link onlylibmori_cco.so(verified end-to-end).Style / pre-commit ✅
The cco files had been committed without the pre-commit gate; applied it here (missing license headers, black + clang-format, ruff), and trimmed verbose comments / dropped stale references.
CI ✅
ci_cco.ymltriggers onmain(was the temporarydev/ccobranch) and chowns the workspace back to the runner in Cleanup.src/umbp/CMakeLists.txtgates its tests subdir behindBUILD_TESTSso non-test builds (e.g.BUILD_EXAMPLES=ON) no longer FetchContent googletest and fail on github-less runners.Not included (intentional)
dispatch_combine_v2, cco-LSA intranode MoE ops v2) is not part of this PR — it lands in a follow-up PR on top of mergeddev/cco.Test plan
docker/Dockerfile.ccocontainercco.hpp+libmori_cco.sotools/run_cco_tests.sh <build> 4(theci_ccoworkflow)maintest suite