[DataFlow runtime] Domino disagg: 1-server + DP=7 launcher + working --num-epochs#661
Merged
jiapingW merged 1 commit intoJul 9, 2026
Conversation
Contributor
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
bdc1c6a to
f3eb84a
Compare
…--num-epochs
- examples/disagg/run_qwen3_8b_domino_disagg_1srv_dp7.sh: single inference
server (1 GPU) + DP=7 trainer (7 GPUs) variant of the multiserver launcher.
The domino disagg workload is trainer-bound and the capture server is
heavily overprovisioned in the 2-server layout (~6% util); this rebalances
to 1 server + 7 trainers, which raises both throughput and server util.
- examples/disagg/run_disagg_domino.py: the producer now replicates the prompt
pool by --num-epochs before streaming. The online streaming channel is
consume-once, so previously the pool streamed once regardless of
--num-epochs; multi-epoch training now works as expected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
perf(domino-disagg): env-tunable data-plane knobs + findings (28.8->50.1 samples/s)
Config-only tuning that ~doubles single-node online domino-disagg throughput,
with util/SM/mem healthy on all 8 GPUs. All knobs are off by default.
Launchers (1srv+dp7 and multiserver):
- DISAGG_SERVER_URLS now overridable; repeating one URL N times spawns N
concurrent producer workers with disjoint leases against one server, which
breaks the single-producer supply ceiling (the blocking HTTP prefill releases
the GIL so workers genuinely overlap).
- SERVER_MEM_FRACTION knob (default 0.85): 0.5 right-sizes the capture-only
server from ~126 GB to ~78 GB with no perf cost.
- NUM_ANCHORS / BLOCK_SIZE knobs on the 1srv launcher (quality<->throughput).
- multiserver launcher now honors BATCH_SIZE / ACCUM (were hardcoded to 2 / none).
FeatureDataLoader:
- LOADER_PREFETCH=N: background-thread batch prefetch so the training step never
pays mooncake get/collate latency inline (ack still after the trainer consumes).
- CLONE_ON_FETCH=0: skip the redundant defensive clone on the mooncake zero-copy
path (get() already allocates a fresh tensor).
See examples/disagg/PERF_FINDINGS.md for the full analysis: the pipeline is a
supply/demand seesaw (1:7 beats 2:6), bigger batch does not help (compute-latency
bound, MFU ~14%), and ~78% of per-sample trainer compute is the num_anchors=256
draft expansion.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
perf(domino-disagg): env-gated profiling instrumentation for the data path
Default-off timers that produced the PERF_FINDINGS analysis. Each is gated on an
env var and adds nothing when unset.
- PROFILE_PRODUCER=N -> [prod] (backpressure-park / run_once / publish + in_flight)
in launch.py, and [prod-http] (build / HTTP RTT / parse)
in the server-capture adapter.
- PROFILE_LOADER=N -> [loader rK] queue-wait / get / clone / release / gc.
- PROFILE_STORE=N -> [store rK] get/put GB/s, rm_ok/rm_fail(-706), pending depth.
- PROFILE_DISTRIB=sec -> [dist] commit / count / inbox-publish + per-rank lag.
- PROFILE_STEPS=N -> [profile] data-wait vs compute, [profile2] fwd/bwd/opt + padded len.
- PROFILE_TORCH=N -> rank-0 torch.profiler top-ops + chrome trace.
- FSDP_SHARDING -> override the FSDP sharding strategy (e.g. NO_SHARD).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
revert(domino-disagg): drop NUM_ANCHORS/BLOCK_SIZE knob; num_anchors is not a throughput lever
Reducing num_anchors raises sequences/s but LOWERS training-signal/s
(anchor-updates/s): each anchor is a supervised target, and a fixed ~53ms/
microstep per-sequence overhead means fewer anchors amortize that cost over less
signal (256 -> ~2130 vs 64 -> ~1280 anchor-updates/s). It also forces ~4x more
captured sequences for equal signal, loading the supply bottleneck. So it is a
quality/data-efficiency setting, not a speed knob — revert the launcher override
back to the fixed --num-anchors 256 / --block-size 16 and correct PERF_FINDINGS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
docs(domino-disagg): measured MFU/FLOPs + correct the inference-ceiling analysis
Adds bench_domino_mfu.py (isolated single-GPU, FLOP-counted, CUDA-event-timed
trainer benchmark) and folds its results into PERF_FINDINGS.md:
- Trainer MFU ≈ 44% (measured, b2/b4/b8; ~45 TFLOP/sample fwd+bwd; per-sample
time flat across batch → compute-bound, not stalled). Supersedes the earlier
"MFU ~14% / occupied-but-stalled" note, which came from a cuda.synchronize-
distorted timing and was wrong.
- Inference (target prefill) ≈ 43% MFU, estimated from ~27k tok/s at ~550-tok
prompts (2·params·tokens for the 8B target).
- Corrects the "supply ceiling = capture sink" framing: at >=8 producer workers
the server is PREFILL-COMPUTE-BOUND (GPU prefills ~100% duty at ~27k tok/s);
the sink thread keeps up (~55/s) and is only the *next* wall. So an async/
parallel sink is a second-order lever, not the primary fix — the real supply
levers are higher prefill MFU (CUDA graphs / bigger prefill batches / lighter
aux-hidden capture copy), fewer aux layers (training change), or more inference
GPUs (the seesaw). Trainer-MFU work does not raise system throughput while
supply-bound.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix lint
fix lint
db0fcb4 to
0b7cd90
Compare
Contributor
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
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
Adds a 1-inference-server + DP=7-trainer launcher for Qwen3-8B domino disagg, makes
--num-epochsactually work in the online/disagg path, and adds config-only perf tuning that ~doubles single-node throughput (28.8 → 50.1 samples/s) plus the profiling instrumentation and analysis behind it. Stacks ondomino-disagg(#660).examples/disagg/run_qwen3_8b_domino_disagg_1srv_dp7.sh— single capture server (1 GPU) + DP=7 domino trainer (7 GPUs).examples/disagg/run_disagg_domino.py— the producer now replicates the prompt pool by--num-epochsbefore streaming (the online channel is consume-once).examples/disagg/PERF_FINDINGS.md— full write-up.Perf: 28.8 → 50.1 samples/s, config only (measured on 1×8 H200, ≥390 s integrated)
Best config (see PERF_FINDINGS.md for the full recipe):
Result: 50.1 samples/s, all 8 GPUs healthy (server util 98% / SM 76%; trainers util 77–100% / SM 76–85%; trainer mem ~45 GB).
The pipeline is a supply/demand seesaw on 8 GPUs, and 1:7 is the best split:
Bigger batch does not help (compute-latency-bound, MFU ~14%): b2/a8 = 50.1, b4/a4 = 47.5, b8/a2 = 47.2. Batch 8 drives trainer memory to 113 GB / 100% util but throughput falls — full util/memory ≠ fast.
Why per-sample trainer demand is "low" (
num_anchors): the DFlash draft forward expands every sample tonum_anchors × block_size= 256 × 16 = 4096 draft positions (+ full 151,936-vocab head). Per-microstep compute fits≈ 53 ms + 0.73 ms × anchors, so ~78% of compute at 256 anchors is the anchor expansion — one "sample" is ~45 TFLOP (fwd+bwd), ≈9× a normal 1.1 B forward. This is by design (denser training signal), not inefficiency, and it runs at a healthy ~44 % MFU (measured,bench_domino_mfu.py) — the trainer is compute-bound, not stalled.num_anchorsis not a throughput lever: reducing it raises sequences/s but lowers training-signal/s (anchor-updates/s), so it's a quality/data-efficiency setting only (the launcher keeps it fixed at 256).MFU / FLOPs (both sides ≈ 43–44 %, compute-bound)
cuda.synchronize-distorted timing.2·params·tokens, 8 B target).Remaining ceilings (code, not config)
Notes for reviewers
DISAGG_TOTAL_STEPSmust beceil(NUM_EPOCHS * num_filtered_prompts / (TRAIN_DP * BATCH_SIZE * ACCUM))— too small decays the LR to ~0 early (documented inline).--num-epochs > 1the producer re-captures the pool each epoch.patches/sglang/.../spec-capture.patchterritory); note the sink is not the current supply ceiling (prefill compute is), so sink work is secondary.🤖 Generated with Claude Code