Repository navigation
Conversation
There was a problem hiding this comment.
ARGUS
Findings
5 more finding(s), not posted inline
.github/workflows/therock-rccl-ci-linux.yml:286(Low) Timeout comment attributes the extra 120 min to image builds, but builds run outside the script's 300-min timerprojects/rccl/ci/scripts/test_madengine.py:762(Low) rccl_banner_logs never checks that every node has a server log, so a node with no log is skipped in RCCL verificationprojects/rccl/ci/scripts/test_madengine.py:1557(Low) Only the top run_logs dir is 0777; the launcher's nobody-owned subdir may block the runner's rm -rf cleanupprojects/rccl/ci/scripts/tests/test_sglang_disagg.py:52(Low) Test passes dockerfile_name/local_only but with no overlay_ctx file or registry they do not affect the manifestprojects/rccl/ci/scripts/test_madengine.py:1368(Low) sglang overlay recipe, install_madengine raises, skip-overlay refusal and PREFLIGHT_DNS content have no tests
Bottom line: Worth settling before approval: run_logs is created 0777 with no sticky bit (test_madengine.py:1557), so another cluster user can plant the logs the RCCL swap is verified from and that the new artifact glob uploads.
Comment @argus review to re-run, or @argus re-review after pushing.
| # root-squashed NFS maps to nobody. | ||
| run_logs = (run_dir or work_dir) / "slurm_output" / "run_logs" | ||
| run_logs.mkdir(parents=True, exist_ok=True) | ||
| run_logs.chmod(0o777) |
There was a problem hiding this comment.
Medium
run_logs.chmod(0o777) has no sticky bit, and WORK_DIR sits under the world-writable /apps/rccl-ci. Any cluster user can rename the launcher's subdir and plant prefill_*/decode_* logs, which rccl_banner_logs (line 762) then trusts over the .out logs, and the new run_logs/*/*.log upload glob ships whatever is planted, symlinks included. Could we use 0o1777 and read and upload only the $SLURM_JOB_ID subdir, skipping symlinks?
| "--ulimit memlock=-1 --ulimit nofile=1048576 " | ||
| "-v /sys:/sys:ro -v /run/udev:/run/udev:ro", | ||
| }, | ||
| # The first inference workload: DeepSeek-R1 served disaggregated, two |
There was a problem hiding this comment.
Nit
| # The first inference workload: DeepSeek-R1 served disaggregated, two | |
| # DeepSeek-R1 served disaggregated, two |
A 4-node prefill/decode-disaggregated inference workload. The baseline is MAD's sglang overlay recipe built on a digest-pinned base, the candidate is the same recipe with the CI RCCL swapped in, so both phases differ only in librccl. The gate compares output throughput at two concurrency-64 sweep points. - per-phase /run_logs mount; the RCCL banner is read from the server logs - weights mounted read-only from the cluster's models_dir - image rdma-core kept: host libibverbs is not mounted for this workload - DNS preflight on every node, optional MADENGINE_SLURM_EXCLUDE hostlist - weekly matrix entry, dispatch choice, unit tests Co-authored-by: Cursor <cursoragent@cursor.com>
d852648 to
af49966
Compare
✅ All Policy Checks Passed
📖 Need help? See the Policy FAQ for details on every check and how to fix failures. |
Motivation
The madengine gate covers training only. This adds DeepSeek-R1 inference with
SGLang, prefill/decode disaggregated over 2 prefill and 2 decode nodes, so RCCL
carries the tensor-parallel collectives of an inference server under load. It
runs on the weekly schedule only.
Stacked on #13728 (Llama-3.1-70B PP=4), which is stacked on #13182.
Changes
deepseek-r1-sglang-disagg(family: sglang-disagg,type: inference,required_nodes: 4, 3 htime_limit).docker/sglang_disagg_inference_full_overlayrecipe atMAD_REF, with itsFROM $BASE_DOCKERpinned to the resolved base. Thecandidate is the same recipe plus the CI librccl swap, so the two phases
differ only in RCCL. Both phases take the local-image path, as the
maxtext baseline does: node 0 builds from the advertised recipe and the
other nodes load its tar from
WORK_DIR/docker_builds.output_token_throughput_tok_sof the whole deployment atisl1024_osl1024_con64andisl8192_osl1024_con64. Only those twopoints are run, three times each (
BENCHMARK_ITR=3); MAD's parser keepseach point's best pass. A point is just 2 x concurrency requests, and a
single pass at
isl1024_osl1024_con64moved 6.8% between two A/A phaseson the same nodes.
OMP_NUM_THREADS=8and theTORCH_NCCL_*settings are set in theworkload's own env, as in the hand-run manifest this was validated with.
The shared ones reach only the deployment env, not the container.
MOE_A2A_BACKEND=none: the MoE dispatch stays on RCCL, not MoRI.mount_host_ib_libs: False); thehosts' rdma-core 61 lacks the bnxt_re QP fix.
CLUSTER_CONFIGSkeymodels_dir.run.shdownloads intoMODEL_PATHwhen it finds theweights incomplete; read-only makes that fail instead of filling storage.
NCCL_DEBUG=INFOwithNCCL_DEBUG_SUBSYS=INIT,NET: at WARN, RCCL printsits version banner only on rank 0 of a communicator, and the replacement
check needs one per node.
/run_logsis a per-phase directory, created 0777. Both phases share oneSLURM_JOB_ID, which the launcher uses as its log directory name.(
prefill_NODE*.log,decode_NODE*.log) when a phase has them._isl..._osl..._con...suffix of therow name) when a row has no precision.
an address it has. A stale record otherwise leaves the sglang barrier
waiting for that node until timeout. Nodes can be kept out with the
repository variable
RCCL_MADENGINE_SLURM_EXCLUDE(a SLURM hostlist, passedas
MADENGINE_SLURM_EXCLUDEand validated beforesalloc --exclude).slurm_output/run_logs/*/*.log.nodes: '4',job_timeout_minutes: '360') and adispatch choice.
tests/test_sglang_disagg.py: manifest layout, recipe pin, result pairing,banner logs, DNS preflight and exclude handling, and that every gated point
is in the benchmark sweep.
CLUSTER_CONFIGS["ruby"]["models_dir"]is/apps/data/models; the weightsare at
/apps/data/models/DeepSeek-R1-0528, readable by the runner account.Nightly vs weekly after this stack
llama-3.1-70b-training(FSDP2, 2N)test_scope=all), serialgpt-oss-120b-training(2N),llama-3.1-70b-pp4-training(2N),llama-3.1-405b-maxtext(4N),deepseek-r1-sglang-disagg(4N)Validation
python3 -m unittest discover -s tests: 32 tests pass.A/A on ruby through this code path:
generate_manifest, the in-placesallocwith both preflights, madengine'ssglang-disagglauncher, bannercheck and result pairing, with the baseline image in both phases (4 x 8
MI355X). Output tok/s, phase 1 -> phase 2:
isl1024_osl1024_con64isl8192_osl1024_con6479615 is why the gate runs three passes. Within a phase each pass is faster
than the one before (82589 baseline,
isl1024: 1348.6, 1410.5, 1513.9),which keeping the best pass absorbs. The absolute level depends on the node
set (79505 and 82589 ran on the same four nodes), which is why both phases
share one allocation. 82589 took 67 min end to end, image build included.
CI dispatch of the new key: TODO, blocked by the runner account's disk
quota on ruby.
Run 39238800940
failed with
[Errno 122] Disk quota exceededin "Create Python environment",before any allocation: the runner account's home was full. feat(rccl): score the madengine gate against a same-node baseline #12899 now keeps
conda and pip out of that home.