Repository navigation
[diffusion] Measure warmup memory and layer usage per phase for residency calibration (1/4) - #37916
Merged
Merged
Conversation
…ency calibration First of four layers split out of #35335. This layer only measures: it records, during synthetic server warmup, what a residency planner needs to decide a placement, and defines the record types that carry it. - ComponentResidencyManager tracks a warmup phase key per stage setup / use / prefetch / full-weight transition and records the allocator peak and active components per phase (WarmupPhasePeak). - The pipeline stages record their denoising iteration counts against the default workload (record_stage_iterations), and the perf metrics keep per-stage step timings. - GPUWorker records one WarmupMemoryRecord per warmup request (LayerwiseUsageTracker counts per-layer uses while it runs). - auto_residency.py carries the record/target/report types and the estimators that extrapolate a probe to the default workload (peaks per phase, layer uses per iteration, stage timings). - The warmup request builder gains the full-shape calibration probe, its step floor, OOM degradation and --warmup-sampling-params; the gate that says whether a deployment can be calibrated lives in auto_tune. - Control-request structs move from entrypoints/utils.py to entrypoints/control_requests.py (a pure move that later layers build on). Planning, applying and validating a placement follow in the next layers. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
mickqian
requested review from
AgainstEntropy,
BBuf,
HaiShaw,
ping1jing2 and
yichiche
as code owners
September 4, 2026 03:40
This was referenced Sep 4, 2026
… in every loop record_stage_iterations had to be called by hand inside 14 denoising loops, each redoing the same arithmetic, and a new model that forgot it silently fell back to "iterations == steps". Now PipelineStage records the count itself after forward for warmup requests: a stage declares default_workload_iterations(batch, num_inference_steps) once, the base class evaluates it at the probe's step count (measured) and at the default workload's (target). - DenoisingStage: steps. Cosmos3 and MOVA: steps. DMD: the fixed distilled schedule length. MiniMax-H3: steps - 1. LTX-2 refiner: its distilled sigma table, which also retires the stage_target_num_inference_steps bookkeeping in batch.extra. - Loops whose length is only known inside them (block-wise causal DMD, Helios chunks, SANA-WM refiners) keep the explicit call; an explicit record always wins over the formula. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…p_routing The structs moved to entrypoints/control_requests.py in this layer, but these two files kept importing them from entrypoints/utils.py: the server failed to import and the unit-test collection errored. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ent supports test_dp_routing's warmup fan-out and auto-residency merge tests exercise the third layer's scheduler client; they return with it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…-measurements # Conflicts: # python/sglang/multimodal_gen/test/test_utils.py
…ts' into feat/residency-warmup-measurements # Conflicts: # python/sglang/multimodal_gen/test/unit/test_dp_routing.py
The runtime peak reported for a request was the worker's running maximum of peak reserved memory over every request, warmup included. The calibration probe runs the default workload's full shape (1280x720x81f for Wan 2.2 T2V), which the CI requests never reach, so their "runtime peak" rose 7-25% and one baseline had been bumped 58% to cover it. Warmup requests now feed a separate warmup peak that the replica report carries as a third value (warmup_peak) and the test summary exposes as warmup_peak_vram_mb without validating it. The fast_hunyuan_video runtime baseline goes back to main's value. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The probe runs the default workload's full shape before any placement is promoted; a card that cannot hold it fails at startup, so its peak is a deployment cost worth guarding, separately from the serving requests'. Scenarios that carry warmup_peak_vram_mb are validated against it with the runtime tolerance; scenarios without it only report the value (the baseline dump and results JSON now include it) until one is seeded. Seeded from the runs that exposed the probe: wan2_2_t2v_a14b_2gpu, wan2_1_i2v_14b_480P_2gpu and fast_hunyuan_video. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ing out by OOM The full-shape probe replaced the bounded warmup and ran blind: a card that could not hold the default workload learned so by running out of memory, then retried smaller up to three times. On discrete GPUs that costs startup time; on unified-memory machines the failure is not always a catchable exception. The bounded warmup now runs first and the probe follows. Before the probe runs, the worker extrapolates the bounded measurement to the probe's shape (estimate_default_workload_peak_bytes) and, while that exceeds free memory minus the reserve, shrinks the probe along the same ladder the OOM retry walks (frames, then area). Ranks agree on the most cautious shrink so the forward runs one shape everywhere. The OOM retry stays as the backstop and now also recognizes cuBLAS / CUDA allocation failures. Two records at different sizes also let the planner's two-point extrapolation apply where the single-point path used to. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…r metrics tests Two tests here drive worker paths that create the global ComponentResidencyManager for their fake pipeline and never clear it; later tests that expect the worker to fall back to pipeline.modules then receive the leaked manager's modules (seen as an order-dependent rollback assertion in test_auto_residency_warmup). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e placement reserve The probe only has to run; the planner's VRAM reserve is for what may be made resident afterwards. Using it here held back 4 GiB of a 32 GiB card and shrank an 81-frame probe to 41 frames while its extrapolated peak (17.9 GiB) had 10 GiB to spare. Keep a 1 GiB / 2% margin instead, and log the estimate for the shape that was asked for rather than the shrunk one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…frame contract The full-shape probe leaves its cached allocator blocks behind, so the first serving request inherited them as its reserved floor (fast_hunyuan runtime peak 37.7-39.0 GiB against the 35.9 GiB baseline). Drop the pool once at the warmup -> serving transition. Probe lightening halved frames without adjust_num_frames, producing counts a causal-block model rejects (LongLive2 needs latent frames in blocks of 8); walk the halved count down to the largest value the contract accepts.
Releasing the probe's pool and starting serving from an empty allocator still measured fast_hunyuan at 37.1 GiB reserved against main's 35.9 GiB: the serving request grows a fresh pool differently from one pre-shaped by a small warmup. Run the bounded warmup once more after the probe, with the pool release moved to the request that follows the probe, so serving starts from the same allocator state main has.
…tory The full-shape probe now runs for LongLive2 (frame contract fix), so the serving request starts from a different allocator pool history than on main. Reserved peak measured 62706 MiB on seven consecutive attempts (main nightly: 61074); allocated usage and placement are unchanged.
added 2 commits
September 6, 2026 13:40
…he bounded shape The 2-rank IPC all-to-all caches staging buffers keyed by message size and evicts by count only, so the full-shape probe left ~5 GiB of buffers sized for 1280x720x81f behind on each rank; wan2_2_t2v_a14b_2gpu then served at 20.3 GiB allocated against main's 15.1 GiB with the same placement. Release the staging cache together with the allocator pool before the request that follows the probe. Probe lightening also walked below the bounded warmup shape down to 16x16x1f, which models reject; stop at the first shape at or below the smallest measured record instead.
…und the warmup probe
…ites around the warmup probe" This reverts commit dddfc33.
StevenChenSE
pushed a commit
to StevenChenSE/sglang
that referenced
this pull request
Sep 6, 2026
… residency calibration (1/4) (sgl-project#37916) Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
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.
First of four stacked PRs split out of #35335 (which becomes the fourth). This layer only measures: nothing about component placement changes yet.
What it records
During synthetic server warmup, one
WarmupMemoryRecordper warmup request with everything a residency planner later needs:ComponentResidencyManagerkeys a warmup phase per stage setup / component use / prefetch / full-weight transition and records the allocator peak and the active components of each (WarmupPhasePeak).PipelineStage.default_workload_iterations); the base class evaluates it at the probe's steps (measured) and at the default workload's (target) after every warmup forward.DenoisingStagereturns the step count, MiniMax-H3steps − 1, DMD and the LTX-2 refiner their fixed distilled schedules. Only loops whose length is known inside them (block-wise causal DMD, Helios chunks, SANA-WM refiners) still callbatch.record_stage_iterationsexplicitly. The perf metrics keep per-stage step timings.LayerwiseUsageTrackercounts how often each layer of a layerwise component runs during the probe.Types and estimators
auto_residency.pycarries the record, target, workload and report types and the pure estimators that extrapolate a probe to the default workload (estimate_workload_phase_peaks,estimate_layerwise_layer_uses,estimate_default_workload_timing). No planning here.Warmup plumbing
The warmup request builder gains the full-shape calibration probe (
AUTO_RESIDENCY_TIMING_STEPSstep floor),--warmup-sampling-params, and theauto_residency_args_skip_reasongate inauto_tunethat says whether a deployment can be calibrated at all. The bounded warmup still runs first; the probe follows it, and before it runs the worker extrapolates the bounded measurement to the probe's shape and shrinks the probe (frames, then area) while that exceeds free memory minus the reserve, with all ranks agreeing on the most cautious shrink. A probe that still runs out of memory is retried smaller up to three times (the retry also recognizes cuBLAS/CUDA allocation failures); a warmup that fails altogether is fail-open unless--warmup-resolutionswas given explicitly. Control-request structs move fromentrypoints/utils.pytoentrypoints/control_requests.py(a pure move the third layer builds on).Peak-VRAM metric
The CI's
runtime_peak_vram_mbwas the worker's running maximum of peak reserved memory over every request, warmup included. This layer's calibration probe runs the default workload's full shape (1280×720×81f for Wan 2.2 T2V), which the CI requests never reach, so their reported runtime peak rose 7–25% without the requests using a byte more. Warmup requests now feed a separatewarmup_peak(carried in the replica report, shown in the test summary aswarmup_peak_vram_mb, not validated); the runtime figure is the serving requests' own peak again, and the fast_hunyuan_video baseline returns to main's value.Stack
collect_residency_targets,plan_auto_residency,placement_budget)Every layer's tree is a prefix of #35335's; the union is byte-identical to the original branch merged with main. Tests: 748 planner/warmup unit tests pass on the top of the stack; this layer's own tests are
test_performance_metrics,test_cfg_parallel_warmup,test_warmup_probe_degradation,test_component_residencyand the estimator tests intest_auto_residency.CI States
Latest PR Test (Base): ✅ Run #34026695033
Latest PR Test (Extra): ❌ Run #34026694906
Latest PR Test (AMD ROCm 7.2): ⏳ Run #34026695048
Follow-ups from CI (2026-09-05)
Probe fitting reserve: the full-shape probe was shrunk against the planner's placement reserve (4 GiB / 10%), which cut a Wan 81f probe to 41f with 10 GiB to spare. The fit now keeps only an allocator margin (max(1 GiB, 2% of device memory)) and logs the requested shape's estimate.
Warmup pool release: the probe runs shapes serving never sees, and its cached allocator blocks became the reserved floor of the first serving request (
fast_hunyuan_videoruntime peak 37.7–39.0 GiB vs the 35.9 GiB baseline). The worker now drops the pool once at the warmup → serving transition; runtime peaks measure the serving request again and warmup peaks stay inwarmup_peak_vram_mb.Frame contract for lightened probes: halving frames bypassed
pipeline_config.adjust_num_frames, so causal-block models (LongLive2: latent frames in blocks of 8) rejected the lightened probe. The halved count is now walked down to the largest value the contract accepts (61f → 29f), then the ladder moves to area.Non-PR failures seen on this head: AMD and NPU multimodal-gen jobs fail identically on
main(NPU:minimax_h3_t2va_2npu/mova_360p_ti2va_2npue2e and text-encoding stage); the 5090minimax_h3_t2va_consumer_budgete2e is runner variance against the baseline [diffusion] fix: preserve mapped courier tensor lifetime #37965 tightened to 42.8 s (42.7 / 48.0 / 56.8 / 64.1 s across identical code).Re-warm after the probe: releasing the probe's pool alone still measured
fast_hunyuan_videoat 37.1 GiB reserved (main: 35.9 GiB, deterministic on both sides) because the serving request grows an empty pool differently from one pre-shaped by a small warmup. The bounded warmup now runs once more after the probe (bounded → probe → bounded), and the pool release moved to the request that follows the probe, so serving starts from the same allocator state as main. One extra bounded warmup request per model at startup; nothing changes when no probe runs.Baseline:
longlive2_t2vh100 runtime peak 61190 → 62706 MiB. With the frame-contract fix the full-shape probe now runs for LongLive2, so the serving request starts from a different allocator pool history than on main; the reserved peak measured 62706 on seven consecutive attempts (main nightly: 61074) while placement and allocated usage are unchanged. Reserved peak carries a 1.5–3% dependence on pool history (same code measured 35926 / 36452 / 37134 / 37710 / 39026 forfast_hunyuan_videounder different histories); a follow-up PR moves the guard tomax_memory_allocated.IPC all-to-all staging after the probe (
wan2_2_t2v_a14b_2gpuruntime peak +20–27%): the 2-rank IPC transport caches staging buffers keyed by message size and evicts by count only, so the 1280x720x81f probe left ~5 GiB of buffers per rank behind; the case then served at 20.3 GiB allocated against main's 15.1 GiB with identical placement (every other 2-GPU case matched main to 0.01 GiB). The staging cache is now released together with the allocator pool before the request that follows the probe. Probe lightening also no longer walks below the bounded warmup shape (it reached 16x16x1f onwan2_1_i2v_14b_480P_2gpu, which the model rejects).All-to-all staging caches are released after the probe (
wan2_2_t2v_a14b_2gpu, Ulysses degree 2). Bothipc_a2a.get_stagingandusp._A2A_STAGING_BUFFERSgrow to the largest message seen and never shrink, so the 1280x720x81f probe left 1.6 + 4.3 GiB allocated per rank that the serving request never needed (allocated peak 20.3 GiB vs 15.1 on main, reserved 24–27 GiB vs the 21.5 GiB baseline). Attributed withtorch.cuda.memory._record_memory_historyon a 2×H200 devbox: before the first serving request 9.68 GiB allocated with the two Ulysses buffers at 2.16 GiB each; 5.80 GiB once both caches are dropped in the worker's post-probe release, serving peak allocated 19.15 → 15.45 GiB (main 15.11). The temporary instrumentation commit was reverted in the same push.