Repository navigation
perf(rollout): select generation and prefill buckets with a tunable cost model - #8786
SuperGoodGame wants to merge 12 commits into
Conversation
Codex Review Summary: 🔄 RunningThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7cb9828038
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Hi @SuperGoodGame thanks for your PR. I have a question about estimation of prefill ratio in rollout e2e. What is typical rollout decode length and prompt length for RL rollout? I'm trying to understand the scope where this optimization will be most effective. @nathon-lee @LiRunGuo if you have any inputs. |
|
Thanks @delock. Prefill's share of rollout E2E depends on the checkpoint and task, including the prompt and response distributions. There is no single task-independent “typical” RL length. Motivation: prompt lengths vary within a batch. Too few buckets waste padded computation; too many repeatedly pay per-forward/kernel-launch overhead. Cost-based DP balances these costs. The same calibrated policy adapts across successive batches, compares eligible no-CB with CB, and replans new admissions within CB. Coefficients are adjustable for the model, GPU, precision, and backend. Additional measurements: same Qwen2.5-3B-Instruct FP32/SDPA setup, unchanged coefficients, 1×512 + 31×16 prompts. EOS was disabled to isolate output-length effects:
E2E values average three interleaved runs after warmup; fractions use a separate profiling call. Outputs matched independent per-request HF generation. An EOS-enabled example with eight math/coding prompts (43–56 input tokens, 512-token cap) produced 2–512 output tokens: six ended at EOS, two hit the cap. Prefill was only 0.57% of no-CB E2E; Auto selected no-CB and matched it (12.836 s vs 12.987 s). These are controlled examples, not representative RL traces. The largest gains are expected when padding waste and Prefill's time share are substantial. When Decode dominates, Auto can retain no-CB. Future EOS length is unknown, so selection uses the configured generation budget and estimated costs. The feature remains opt-in, single-process, greedy, and single-sample. Here E2E covers the complete generation call, excluding tokenization, loading, reward computation, and training updates. |
|
Thanks for the detailed explanation and thorough benchmarking. My main concern is keeping the default OPSD path simple and maintainable. I'd like to take some more time to evaluate this approach before making a decision. I'll take a closer look and share my thoughts later. |
|
Thanks @nathon-lee for sharing your concern. I agree that keeping the default conservative makes sense. Auto is already disabled by default ( The goal of Auto is to retain baseline performance when bucketing offers little benefit, and capture the gains when it does. It evaluates each batch and selects ordinary batch generation when that is estimated to be the better choice. Related community practice also exists: verl’s batching utilities implement token-budgeted dynamic micro-batching with sequence-length-based workload estimates. This provides a practical precedent for workload-aware batch composition, which this PR applies to rollout prefill as an opt-in policy. I also ran a small real-question A/B check with Qwen3-32B, BF16, on a single GPU, using greedy decoding and aligned natural-EOS stopping behavior:
The timing differences were below 0.2%, and all eight responses were token-identical. Auto selected ordinary batch generation in both cases, as intended. These results complement the prefill-heavy improvements reported in the PR by checking baseline alignment on a larger model with real questions. Would you consider this default-off, opt-in scope, with baseline alignment as the acceptance target, suitable for the PR? If further validation would help, could you suggest the specific workloads or baselines most relevant to your target deployments? |
|
Hi, @SuperGoodGame Thanks for the additional Qwen3-32B results. It is useful to see that Auto falls back to No-CB and remains close to the baseline on real questions. I agree that default-off meaningfully limits compatibility risk. However, these two cases both select No-CB, so they do not yet validate the more important part of the policy: whether the fixed-cost model reliably selects bucketed CB when it predicts a benefit. I ran a small independent smoke test with the default coefficients on an RTX A4500 using a randomly initialized small Qwen2 model. This is not representative of the intended deployment, but it found Auto selecting bucketed CB and regressing by 18% for This does not change my view that the opt-in scope is reasonable. At the same time, No-CB selections alone provide limited evidence about how well the cost model is calibrated when Auto selects bucketed CB. To build confidence in that part of the policy, it would be helpful to document the coefficients as configuration-specific and provide a reproducible sweep that includes workloads where Auto selects both routes. Reporting |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 359b3d5002
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Thanks @nathon-lee for the independent smoke test. I agree that the default coefficients are starting estimates, not portable deployment settings. Users enabling Auto should calibrate for their model, GPU, precision and attention backend, and for the prompt-length/batch-size range they actually use. Auto remains disabled by default. Recommended calibration: choose a small set of feasible (batch size, prompt length) pairs covering the deployment's short, typical and long prompts, together with small and typical batches. For example, a workload spanning 128–8192 input tokens should include representative points around 128, 512, 2048 and 8192, subject to memory and model context limits. Fit once, save the coefficients, and validate on separate mixed-length batches with representative generation lengths. Compare Auto against all available manual paths and report the worst regression before enabling it. Why exact DP is practical here: for per-group batches around 128–256 requests, there are only 8,256–32,896 candidate segments. The O(n²) DP can therefore compute the exact optimum for the calibrated cost model over length-sorted contiguous partitions, rather than requiring heuristic search. Here n is the number of requests, not the number of tokens. A small n makes exact solving practical; prediction of measured GPU latency still depends on calibration. Calibration is deployment setup work: run the supplied script during deployment preparation or warmup, save the coefficients in The current script's built-in calibration grid reaches only 768 input tokens. Those measurements do not establish long-context accuracy; longer deployments need an expanded grid. At present this means changing the There were also two distinct causes of the reported regressions:
The separate calibrated sweep reports Auto E2E / fastest manual baseline E2E (ordinary, equal-width CB or aligned CB):
All used SDPA on a single GPU. Each configuration uses one coefficient set fitted on separate uniform shapes. The two larger models choose ordinary generation for 128×16 and bucketed CB for the other three workloads; the tiny model chooses ordinary throughout. Auto's output IDs match ordinary generation in all twelve cases. These are controlled, EOS-disabled, two-token measurements exposing routing overhead, not long-context or production rollout validation. Results average three interleaved runs after warmup, or ten for the tiny model. Reproduce the built-in short-context calibration and sweep with: python benchmarks/rollout_prefill.py --model Qwen/Qwen3-32B --dtype bfloat16 --repeats 3 --calibrate costs.json
python benchmarks/rollout_prefill.py --model Qwen/Qwen3-32B --dtype bfloat16 --cost-config costs.json --repeats 3 --output sweep.jsonThe saved JSON records the configuration, and the sweep rejects mismatched metadata. 108 related tests and changed-file pre-commit checks pass. |
|
@SuperGoodGame Thanks for adding the calibration workflow, reproducible sweep, and the routing-overhead optimization. This addresses my earlier concern about configuration-specific performance evidence, and the default-off experimental scope now looks much clearer. Before I can approve, could we please resolve the remaining route-invariance and compatibility issues:
The calibration benchmark is useful, but it is deployment evaluation tooling rather than DeepSpeed library runtime With those items addressed, I have no further concerns. @delock, do you have any remaining feedback before we merge? |
|
Thanks @nathon-lee. Addressed in 65a9115: the resolved config now reaches continuous Prefill, Decode and refill, and manual generation omits 27 targeted tests pass, including regressions for both routes/cache APIs and the older generation interface. Both independent local reviews returned no findings. The calibration script and fitting test moved to DeepSpeedExamples #1018; the docs now link there. The migrated script is unchanged, and its calibration/saved-config sweep smoke check passes. The Examples companion should merge first so the documentation link is available. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ecacbce12c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
The final fixes and validation are now in d4def3d. Independent review found a BF16 repetition-penalty rounding discrepancy; it now uses FP32 like HF. Unknown public generation switches are also rejected, with regressions for both stored and prepared configurations. The Examples CLI requires complete saved-calibration metadata. I recalibrated Qwen3-32B BF16/SDPA on the final implementation, then ran the same four held-out workloads against all three manual baselines. Worst mean regression: +0.07428%; all four Auto outputs match no-CB. Auto chooses no-CB for 128 short requests and 2/6/2 prefill buckets for the mixed cases. These remain controlled two-token, EOS-disabled measurements; the PR description now includes the complete current-version table and source fingerprint. Both independent final reviews returned no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d4def3db03
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a0588b7dea
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| legacy_settings = getattr(module.config, "_get_non_default_generation_parameters", None) | ||
| needs_prepare = needs_prepare or not callable(legacy_settings) or bool(legacy_settings()) | ||
| if needs_prepare: | ||
| generation_config, _ = prepare_config(None) |
There was a problem hiding this comment.
Resolve generation config with the request overrides
For a custom/remote model whose _prepare_generation_config derives settings from generation kwargs (for example, enabling no_repeat_ngram_size based on max_new_tokens), this call sees none of the kwargs that _generate_batched later supplies to module.generate. Fresh evidence after the earlier prepared-config propagation fix is that the final code still calls prepare_config(None) without those overrides, so validation can accept the config while the batched route enables the processor during its second preparation and the bucketed direct-forward route never does, making token IDs depend on routing; prepare and validate with the same max-token and sampling kwargs used for generation.
Useful? React with 👍 / 👎.
|
Hi @SuperGoodGame @nathon-lee . I think even when we set it to default off, the complexity is still there. I would suggest we focus on improve decode performance right now (we have segKI and graph capture WIP), then come back to prefill part when the decode part is settle. In that way we can make decode and prefill work more seamlessly. Let's say we revisit it one month from now, that's mid November. At that time we should know how batch segKI and graph capture works with CB and have better image to know how to put prefill optimization in. |
|
Thanks @delock. I understand the priority of stabilizing the decode path first. I’ll keep this PR open for follow-up and revisit the integration around mid-November, once the CB, segKI, and graph capture direction is clearer. The implementation and benchmark results will remain available for that discussion. Thanks for taking the time to review. |
|
I see prefill bucketing and decode optimizations as complementary. Our measurements show meaningful end-to-end generation gains when padding and prefill overhead are substantial. I understand that the cache and scheduling interfaces need to align. If useful, I’d be happy to discuss how the prefill policy can work with CB, segKI, and graph capture, and help with the integration. |
a0588b7 to
d9a2cc3
Compare
|
Refreshed onto current master ( Changes absorbed from upstream since the last revision:
Scope is unchanged. Auto and graph capture remain mutually exclusive because the graph uses fixed physical slots while Auto requires aligned, bucketed prefill. Joint Auto/Graph routing is deferred until the graph path and SegKI settle; SegKI (#8602) is not part of this PR. Validation on one GPU of an 8×H20Z node (PyTorch 2.9.1+cu128, CUDA 12.8, Transformers 4.57.1):
Covered: real graph replay, resolved generation-config propagation on both routes (FP32/BF16), DP bucket/refill oracles, Auto/Graph rejection, manual graph dispatch. The performance tables are unchanged and still attributed to their original revisions; I have not relabeled them as new-HEAD measurements. A refreshed calibration run can follow if the new baselines are wanted for review. |
Hi @SuperGoodGame thank you for keeping an eye on this. The idea of this PR looks good. Currently it support eager mode only. Does it indicates CB should decouple prefill and decode (so prefill can run in eager and decode can run in graph capture)? |
|
Thanks @delock. Yes, prefill and decode can be decoupled. I’ve pushed the implementation in 8a9641b. Eager prefill groups newly admitted prompts by length and writes their KV entries into the slots assigned by the graph scheduler. Surviving requests keep their slots as decode replays the captured graph. Both columns below use CUDA Graph decode on a single H200, with BF16, SDPA, and 32 requests. Values are mean end-to-end generation latency over three interleaved runs after warmup. Output lengths were fixed with EOS disabled for timing. Qwen2.5-3B-Instruct
Qwen3-32B
Generated token IDs matched across paths in 9 of 10 cases. In the last 32B row, the 31 identical short prompts first diverged at output token 107. Equal-width prefill produced a BF16 tie between tokens 198 and 220 (both 32.75). With two buckets, their scores were 32.50 and 32.75. Forcing a single bucket reproduced the equal-width output exactly. A separate GPU regression test covered early EOS and slot refill. Each response matched Hugging Face token for token, and two rollout calls reused one graph capture. With both options enabled, the caller selects graph decode and the adaptive policy chooses the prefill buckets. Does that match the separation you had in mind? |
|
Hi @SuperGoodGame , the separation of prefill and decode sounds good. It allows your PR compatible with graph capture in decode. Now it has conflict with merged #8939 which introduced greedy sampling. Can you take a look at the conflict? Also #8390 introduced early stopping that may affect cost model. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 32cd9619c3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f2ae71be4b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5d134f5abb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7ce82f24e2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
353d014 to
edfbf88
Compare
|
Hi @delock, the previous CI run failed due to a Transformers version compatibility issue. This is now fixed, and the targeted tests pass locally with PyTorch 2.10 CPU and Transformers 5.23 (147 passed). I've also rebased onto the latest master; the current head is Could you please approve the CI workflows again for the latest push? They are currently marked |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: edfbf883ff
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| def test_adaptive_generation_uses_resolved_penalty_on_both_routes(cache_support, capacity, dtype): | ||
| from transformers import GenerationConfig | ||
|
|
||
| model = _make_small_qwen().to(dtype=dtype) |
There was a problem hiding this comment.
Skip the BF16 cases on unsupported accelerators
On MPS running macOS 13, MPS_Accelerator.is_bf16_supported() returns false, but _make_small_qwen() places the model on MPS and this case unconditionally converts it to BF16. The test therefore raises an unsupported-dtype error before exercising rollout; the new BF16-mask test above has the same problem. Gate both cases on the selected accelerator's BF16 capability, following the explicit unavailable-hardware skip requirement in the checklist mandated by AGENTS.md.
AGENTS.md reference: AGENTS.md:L40-L40
Useful? React with 👍 / 👎.
|
Hi @SuperGoodGame can you address the latest codex comments (MPS and prepare called twice)? I'd prefer a small change size fix for these two comments, thanks! |
|
@codex review Fixed both findings in
Validation: PyTorch 2.10 CPU / Transformers 5.23: 147 passed, 1 skipped, 4 deselected; Transformers 4.57 CPU targeted tests: 64 passed; single H200 targeted tests: 10 passed. Pre-commit passed. macOS/MPS was not available for hardware validation. |
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…costs Signed-off-by: SuperGoodGame <985236470@qq.com>
Signed-off-by: SuperGoodGame <985236470@qq.com>
Auto forces aligned prefill regardless of align_decode_fronts, so the graph-path check now rejects explicit aligned fronts only when Auto is disabled. Cover both flag values in the accelerator graph test, sync the graph documentation, and test natural-EOS overrides on both Auto routes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: SuperGoodGame <985236470@qq.com>
A custom _prepare_generation_config() can re-enable do_sample after Auto passes greedy overrides. The batched route would then sample inside generate() while the CB routes take argmax, so the route choice could change outputs. Reject such a prepared config before routing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: SuperGoodGame <985236470@qq.com>
…arer Generalize the previous do_sample check. Auto passes the request's budget, EOS, PAD and greedy settings as overrides, and the native preparer applies them last. If a custom preparer changes any of them, the batched route would honor the change inside generate() while the CB routes keep the request values, so reject the config before routing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: SuperGoodGame <985236470@qq.com>
… masks Effective prompt lengths summed a BF16/FP16 mask in its own dtype, so a 257-token prompt counted as 256 and no longer matched the boolean token selection in aligned prefill. Count nonzero entries instead. A custom _prepare_generation_config() can also return a different attention mask. generate() would use it on the batched route while CB routes keep the request mask, so Auto rejects a replaced mask. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: SuperGoodGame <985236470@qq.com>
Effective lengths are read before preparation. A custom preparer that edits the request mask in place keeps the tensor identity, so the identity check accepted it and CB planned with stale lengths. Snapshot the mask before preparation and reject any edit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: SuperGoodGame <985236470@qq.com>
The previous test compared the profile with wall-clock time around generate(), which can fail on a loaded worker. Advance a frozen clock only during the first planning step and require the profile to report exactly that time on both Auto routes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: SuperGoodGame <985236470@qq.com>
Do not mock the rollout's own validation helper. Advance the frozen clock inside the model's generation-config preparer, which Auto calls while planning, and require the profile to cover all elapsed time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: SuperGoodGame <985236470@qq.com>
…ntics Signed-off-by: SuperGoodGame <985236470@qq.com>
Signed-off-by: SuperGoodGame <985236470@qq.com>
810fb39 to
3e651b9
Compare
|
Thanks @delock for the approval. The failed
I rebased onto current master ( If this looks good, please feel free to merge. If you would like to rerun CI first, please let me know and I will rebase onto the latest master right before it runs, so the selection stays scoped to this PR. Note that the merge queue runs the full v1 suite, so it can hit the same failures if it lands on an AVX512-FP16 runner. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3e651b9c37
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Hi @SuperGoodGame I'll take a look tomorrow. Also please use merge instead of rebase, this will help track what had been changed from last approval. Thanks! |
…tdown (deepspeedai#9009) ## Summary Keep the continuous-decode graph alive across RL rollout rounds, and add an explicit way to release it. | Change | Before | After | | --- | --- | --- | | Graph signature | Includes `prompt_len` and every parameter's `(data_ptr, _version)`. | Keeps the decode batch size, cache length, device and dtype, plus each parameter's and buffer's address, device, dtype, shape and strides. Captured kernels read these tensors through the address and layout fixed at capture, so in-place value updates are replayed correctly. Replacing a parameter or buffer (for example a re-registered rotary `inv_freq` or quant scale), or changing its layout at the same address (for example `transpose_()`), triggers a recapture. An unindexed device is normalized to the current device index. | | Width changes | Every new prompt width recaptures, even when `continuous_cache_capacity` pins the cache length. | With a pinned capacity, one graph serves all widths that fit. The capacity check still runs on every call. | | Rebuild order | The new static cache and graph pool are allocated while the old state is still alive. | Drop the old state before allocating its replacement, avoiding overlapping ownership of both states. | | `HybridEngineRollout.shutdown()` | No API; the state lives until the rollout object is collected. | Synchronizes and releases the graph and static cache. The rollout stays usable and recaptures on the next graph call. | `shutdown()` implements the existing `RolloutEngine.shutdown()` lifecycle hook. It matters for TP>1: in the NCCL reproducer below, a persistent graph holding captured collectives makes `destroy_process_group()` hang in `ProcessGroupNCCL.shutdown()`. Call `shutdown()` on each rank before destroying the process group. The docs describe reuse and release. ## Why dropping `_version` is safe - With bf16, DeepSpeed's optimizer writes updated weights through flat buffers that the parameters view via `.data`, which does not bump `param._version`. On master, single-width bf16 rollouts already reused the graph after `engine.step()`, and the replayed outputs changed with the weights. The version check gave no protection there. - On paths where a plain torch optimizer updates parameters in place (for example fp32 ZeRO-0), `_version` changes on every step, so master recaptured on every rollout round. - The cases where storage really moves (AutoTP gather/partition or a `.data =` swap) change `data_ptr`, which stays in the signature. - A same-address layout change also invalidates the captured kernels. Shape and strides are in the signature, so this recaptures too. This also covers `param.data = param.data.t()`, which keeps both `data_ptr` and `_version` and was therefore missed by the old signature. ## Related work / scope - Depends on deepspeedai#9008 for TP>1 continuous graph. Without it, TP>1 continuous graph fails at the KV copy before this code matters. The two PRs touch neighbouring lines in `_get_continuous_graph_state`; whichever merges second needs a trivial rebase. TP2 results below use deepspeedai#9008 + this PR. - Builds on deepspeedai#8732 (persistent continuous graph), reusing its existing fixed-capacity setting rather than adding another configuration option. - deepspeedai#8853 only measures graph capture and keeps the version check. Its `test_continuous_graph_first_call_benchmark_on_cuda` asserts `capture.call_count == 2` because an in-place SGD step currently forces a recapture. With this PR that step reuses the graph, so whichever of the two merges second needs that expectation changed to 1 (and the benchmark's post-update number no longer includes a recapture). deepspeedai#8786 buckets prefill and does not change graph reuse or release. - Not covered: ZeRO-3, offload, HybridEngine kernel injection, LoRA fuse/unfuse inside rollout. ## Validation ### After merging master Merge `dedd6c840` includes master `a4c989b76`. On 1× NVIDIA L20 (driver 580.173.02, CUDA 13.0, torch 2.14.1+cu130, Transformers 5.17.0), the tested files matched the merged worktree by SHA-256: ```bash unset DEEPSPEED_PRETRAINED_ROLLOUT_MODEL CUDA_VISIBLE_DEVICES=0 DS_ACCELERATOR=cuda OMP_NUM_THREADS=1 MKL_NUM_THREADS=1 \ HF_HUB_OFFLINE=1 timeout 600 python -m pytest -q -p no:cacheprovider -o addopts= \ tests/unit/v1/test_hybrid_engine_rollout_v1.py \ tests/unit/runtime/rollout/test_hybrid_engine_rollout.py tests/unit/utils/test_static_cache.py # 104 passed, 2 skipped: optional pretrained model and native inference extension CUDA_VISIBLE_DEVICES=0 DS_ACCELERATOR=cuda OMP_NUM_THREADS=1 MKL_NUM_THREADS=1 \ HF_HUB_OFFLINE=1 DEEPSPEED_PRETRAINED_ROLLOUT_MODEL=Qwen/Qwen3-0.6B \ timeout 300 python -m pytest -q -p no:cacheprovider -o addopts= \ tests/unit/v1/test_hybrid_engine_rollout_v1.py::test_continuous_graph_matches_pretrained_model_when_enabled # 1 passed, using cached Qwen3-0.6B weights ``` On CPU (AMD EPYC 9575F, 256 logical CPUs visible; Python 3.12.3, torch 2.14.0.dev20260804+xpu): ```bash DS_ACCELERATOR=cpu OMP_NUM_THREADS=1 MKL_NUM_THREADS=1 python -m pytest -q -p no:cacheprovider -o addopts= \ tests/unit/runtime/rollout/test_hybrid_engine_rollout.py tests/unit/utils/test_static_cache.py \ tests/unit/v1/test_hybrid_engine_rollout_v1.py # 78 passed, 28 skipped (accelerator-only cases and the optional pretrained test) ``` Pre-commit passed on the four PR files after resolving the conflict. ### Earlier validation **CUDA:** 8× NVIDIA L20 available (1/2/4 devices used below), driver 580.173.02, CUDA 13.0, torch 2.14.1+cu130, Transformers 5.17.0. Base: `d8241a9ba`. The three tested Python files on L20 have identical SHA-256 hashes to the then-current PR head `55384d86d`. With `DEEPSPEED_PRETRAINED_ROLLOUT_MODEL` unset: ```bash CUDA_VISIBLE_DEVICES=0 python -m pytest -q -p no:cacheprovider \ tests/unit/v1/test_hybrid_engine_rollout_v1.py \ tests/unit/runtime/rollout/test_hybrid_engine_rollout.py tests/unit/utils/test_static_cache.py # 61 passed, 2 skipped; exit 0 # Skips: optional pretrained model and native inference kernel unavailable in this invocation. # Without the layout fix in 55384d8: the two lifecycle tests fail (unit: state reused after # transpose_(); v1: graph tokens differ from eager after transpose_()). ``` The earlier run (before the layout fix) with the optional pretrained model enabled and the native inference kernel available: ```bash CUDA_VISIBLE_DEVICES=0 DEEPSPEED_PRETRAINED_ROLLOUT_MODEL=<Qwen3-0.6B> python -m pytest --forked \ tests/unit/v1/test_hybrid_engine_rollout_v1.py tests/unit/runtime/rollout/test_hybrid_engine_rollout.py \ tests/unit/utils/test_static_cache.py # master + this PR's test files: 4 failed, 59 passed (3 incompatible/new regression tests + 1 pre-existing) # this PR: 1 failed, 62 passed (pre-existing only) # this PR + deepspeedai#9008: 1 failed, 71 passed (pre-existing only) ``` The pre-existing failure on baseline `d8241a9ba` was the opt-in `test_continuous_graph_matches_pretrained_model_when_enabled` with Transformers 5.17 (`'DeepSpeedStaticCache' object has no attribute 'get_query_offset'`, see deepspeedai#8852). The fix is now in master and the opt-in test passes after the merge, as shown above; the test remains skipped in CI without the model. The unit test covers in-place updates, a same-address `transpose_()`, parameter replacement, capacity changes and `shutdown()` with graph capture mocked. On a real device the new test runs a tiny Llama with a fixed capacity and widths 8 → 8 → 12 → 8. It applies an in-place weight change before round 2 and a same-address `lm_head.weight.transpose_()` before round 4. Each round matches plain eager token for token, the output changes after the weight update, and there are exactly 2 captures (initial + after the layout change). `shutdown()` frees at least the cache size. **Review follow-up (`2313079fa`, rebased on master `84481c333`).** Buffers are now in the signature. The unit test also re-registers a buffer, and the device test adds a fifth round that re-registers `model.model.rotary_emb.inv_freq` at half its values: the output still matches eager, the tokens change, and there are 3 captures. On 1× NVIDIA L20 (torch 2.14.1+cu130): `tests/unit/v1/test_hybrid_engine_rollout_v1.py` + `tests/unit/runtime/rollout/test_hybrid_engine_rollout.py` give 102 passed, 6 skipped. With buffers removed from the signature, the device test fails on the token comparison after the buffer swap. On 1× Arc Pro B70 the same files give 71 passed, 37 skipped (graph-capture cases skip on this XPU stack). Multi-GPU TP and the RL loop below were not rerun for this change, which only adds buffers to the signature. **RL loop on L20.** Qwen3-0.6B, TP1, 8 prompts, 4 slots, 32 new tokens, greedy, 6 rounds. Each round does a graph rollout, then a real `engine.backward()` + `engine.step()` with AdamW (lr 1e-4). Times are wall-clock per rollout, including prefill. | Setup | Captures (6 rounds) | Rollout ms (rounds 2–6) | Peak MiB (rounds 2–6) | | --- | --- | --- | --- | | fp32 ZeRO-0, width 64 — master | 6 | 677–703 | 7069 → 7107 | | fp32 ZeRO-0, widths 64/96, capacity 160 — this PR | 1 | 546–553 | 7107 / 7070 alternating | | bf16, widths 64/96, capacity 160 — master | 6 | 625–1331 | 8188 → 8220 | | bf16, widths 64/96, capacity 160 — this PR | 1 | 401–542 | 8155 / 8137 alternating | | bf16, width 64, no capacity — master / this PR | 1 / 1 | 386–388 / 390–396 | unchanged | After the layout fix, the patched fp32 TP1, bf16 TP1 and fp32 TP2×DP2 runs were repeated: still 1 capture, the same per-round token-match rates and the same `shutdown()` release. Optimizer steps do not change parameter shape or strides. These are exploratory short runs, not a controlled end-to-end speedup claim. In particular the two fp32 rows use different prompt schedules and cache capacities. No long-run convergence or training-throughput claim is made. **Correctness against plain eager generation.** - **fp32:** every round is token-identical in the TP1 master and patched runs, and in the patched TP2×DP2 run (with deepspeedai#9008). - **bf16, TP1:** rounds 4–6 differ from plain eager after training steps. The per-round token-match rates are the same on master and this PR (0.9961 / 0.8984 / 0.9336). This is consistent with precision-sensitive generation, but does not prove the root cause or bitwise equivalence of the two graph runs. - **bf16, TP2×DP2:** the patched run also differs from eager (minimum match 0.5742 / 0.9805 / 0.9883 / 0.8047). There is no matched unpatched TP2×DP2 run in this experiment, so this cell is **not validated for token-exact correctness**. **Tiny Llama fp32 runs:** - ZeRO-2, widths 16/24: 1 capture, token-identical on every round. **Release with TP2** (tiny Llama, deepspeedai#9008 + this PR): | Exit path | Ranks that returned from `destroy_process_group()` | | --- | --- | | No `shutdown()` | 0/2 (killed by the 600 s timeout) | | `shutdown()` first | 2/2 | `shutdown()` released 116.5 MiB (Qwen3-0.6B bf16, TP1, capacity 160) and 43.7 MiB on rank 0 (TP2×DP2). **Intel XPU** (1× Arc Pro B70, Intel compute runtime package 26.27.39122.11, Level Zero loader 1.28.2, torch 2.14.1+xpu, Transformers 5.22.1, on top of deepspeedai#9007, which adds XPU graph capture): ```bash DS_ACCELERATOR=xpu python -m pytest tests/unit/v1/test_hybrid_engine_rollout_v1.py \ tests/unit/runtime/rollout/test_hybrid_engine_rollout.py # deepspeedai#9007 + this PR: 52 passed, 3 skipped; exit 0 # Without the layout fix, the v1 lifecycle test fails: graph tokens differ from eager after transpose_(). ``` The earlier torch 2.15.0+xpu run also reported 52 passed / 3 skipped, but **aborted during interpreter teardown (exit 134)**. A minimal `torch.ones(16, device="xpu"); torch.xpu.synchronize()` program reproduces that abort without importing DeepSpeed. It exits normally on torch 2.14.1+xpu; the clean-exit test run above uses that version. The earlier deepspeedai#9007-only comparison reached the expected assertion failure (3 captures rather than 1), but its process also used the affected 2.15 runtime. **CPU:** Python 3.12.3, torch 2.14.0.dev20260804+xpu selected with `DS_ACCELERATOR=cpu`. ```bash DS_ACCELERATOR=cpu python -m pytest tests/unit/runtime/rollout/test_hybrid_engine_rollout.py \ tests/unit/utils/test_static_cache.py tests/unit/v1/test_hybrid_engine_rollout_v1.py # 57 passed, 6 skipped pre-commit run --files <changed files> # passed ``` **Compatibility:** fp32 ZeRO-0 at TP1/TP2/TP2×DP2 and fp32 ZeRO-2 at TP1 are token-exact on CUDA. Single-device fp16 graph inference matches eager for the tested Qwen3 and tiny Llama cases after the merge. Single-device fp32 graph tests pass on XPU with deepspeedai#9007. bf16 runs establish capture/release behavior only; their eager-output discrepancies are reported above. **Not validated:** ZeRO-1, ZeRO-3, offload, fp16 training, autocast, quantization, HybridEngine kernel injection, multi-device XPU graph, pipeline/expert/sequence parallelism, or training convergence. AI assistance: GitHub Copilot helped with implementation, documentation, tests, review and validation. The original signed code commit is preserved; this PR also includes signed documentation and layout-signature follow-ups. --------- Signed-off-by: Jin, Youzhi <youzhi.jin@intel.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Hi @SuperGoodGame can you help resolve the conflicts? Thanks! |
Resolves the conflict with deepspeedai#9009 (rollout graph lifecycle) and applies the latest Codex finding. - Keep both new imports (`itertools` from deepspeedai#9009, `math` from this branch). - Documentation: keep deepspeedai#9009's graph-lifecycle text, and state that manual aligned decode fronts are rejected only with Auto disabled while cache trimming is rejected in both graph modes. - Auto now also rejects a custom generation preparer that drops the `attention_mask` key. Previously the missing key fell back to the request mask, so generate() would infer an all-ones mask while the CB routes used the request mask. The mask test covers replaced, in-place edited and dropped masks. Validation (1 x H200, PyTorch 2.9.1+cu128, Transformers 4.57.1): 230 passed, 9 skipped, 1 deselected across the runtime rollout, continuous-batching, interface, static-cache and v1 accelerator suites. Pre-commit passed. Co-Authored-By: Claude Code <noreply@anthropic.com>
November 11 update
Rebased onto master
b9100c5, which includes #8390 and #9008; new head82ac56e.Uses #8939's shared sampling kwargs, token selector and FP32 repetition-penalty helper. Manual graph and continuous-batching paths retain upstream temperature/top-k/top-p sampling. Adaptive prefill retains its single-sample greedy scope, including fixed-slot graph decode. #9004's pre-built 4-D graph mask is preserved.
align_decode_fronts=Trueonly when Auto is disabled, because Auto always uses aligned bucketed prefill. The accelerator graph test covers both flag values. The documentation states that Auto takes precedence overalign_decode_frontson the graph path; cache trimming is still rejected._continuous_cache_layer()helper, like the equal-width path._prepare_generation_config()runs, Auto rejects the prepared config if it changes any request override (token budget, EOS, PAD or greedy settings). Otherwise the batched route would honor the change insidegenerate()while the CB routes keep the request values. A preparer that replaces or edits the attention mask is rejected for the same reason.count_nonzero, so BF16/FP16 masks longer than their exact-integer range no longer round the bucket width.Validation on an 8 × H200 node, PyTorch 2.9.1+cu128, CUDA 12.8, Transformers 4.57.1: 232 passed, 3 skipped, 2 deselected across the runtime rollout, scheduler, interface, static-cache and v1 accelerator suites, including #8390's 4-rank subgroup and 2-GPU ZeRO-3 synchronized-stop tests. Skips require the newer cache query-offset API; deselections are the native shared-prefill kernel and optional pretrained-model test. Pre-commit passed on all changed files. A small natural-EOS check (Qwen2.5-3B-Instruct, four short questions) ended every response at EOS, with Auto matching ordinary generation. This update used AI assistance.
The performance tables below retain their original revision attribution; large-model throughput and peak memory were not remeasured for this rebase.
Summary
Closes #8785. Related tracking: #8197, #8462.
Performance follow-up to #8497. Aligned CB avoids padding on long-tail prompts, but one prefill Forward per request is expensive for short prompts. A padding-ratio threshold cannot distinguish 128/4 from 512/16, despite identical ratios and different fastest baselines.
This change adds one opt-in automatic policy that compares ordinary no-CB generation with aligned CB using DP-selected prefill buckets. For 1×512 + 31×16, the selected buckets are
[1,512]and[31,16], reducing prefill Forwards from 32 to 2.Auto is disabled by default. Existing manual modes and positional configuration arguments are preserved.
Selection and configuration
A length-sorted O(n²)-time / O(n)-space DP minimizes the additive estimated cost of contiguous buckets. It explores one batch, singleton batches and intermediate partitions without running the GPU for candidate evaluation. Each bucket uses ordinary left padding and a 2D attention mask; no varlen kernel is needed. Model geometry is read once per plan.
prefill_fixed_cost_msprefill_token_cost_msprefill_attention_cost_msprefill_kv_cost_mscontinuous_decode_cost_msprefill_max_tokensNoneremoves this limitAll cost coefficients must be finite and non-negative. These are starting estimates, not universal GPU constants; calibrate them for the model, device, precision and attention backend. Head dimension, query/KV heads, layers and parameter element size are read automatically. The DP is optimal for the configured estimates, not guaranteed globally optimal measured latency.
Ordinary generation is eligible when every row fits
continuous_batch_size, the physical input fits the prefill/context limits, and neither explicit static capacity nor trimming is requested. Its estimated cost omits CB cache-copy traffic; CB addscontinuous_decode_cost_ms × (max_new_tokens - 1). The first output token comes from Prefill.For CB, every admission/refill replans the newly admitted requests. Effective KV spans are copied into the existing right-aligned cache; surviving rows retain their layout. The policy does not change caller configuration or active-row bounds. Disabling Auto restores manual selection. Model/OOM errors propagate without trying another path.
Correctness
Experiments
Related work: TurboTransformers, §5 (PPoPP 2021) already uses length sorting, profiled batch costs and an O(n²) DP to partition variable-length inference requests. DynaPipe, §4 applies cost-based DP partitioning to training micro-batches. This PR applies that established scheduling approach to HybridEngine rollout, with ordinary-generation comparison, refill planning and existing aligned-cache semantics; it makes no claim of a new DP algorithm.
Single GPU; Qwen/Qwen2.5-3B-Instruct; FP32 / SDPA; PyTorch 2.9.1+cu128; Transformers 4.57.1. Each candidate receives one warmup and five interleaved timed runs, 32 requests and 16 output tokens per request. CB capacity is 32; trimming is disabled, cache capacity unset, TF32 disabled. The default cost coefficients above are unchanged across workloads.
Inputs repeat non-special token ID 14990. #8497 did not publish complete short-prompt sequences, so that case reconstructs its documented shape. Every timed response matches independent single-request eager generation; each workload produces 512 effective output tokens.
GPU-synchronized wall-clock timing includes the full
generate()call, including Auto planning and normalization. Model loading and oracle work are outside timing; profiling is disabled during timed runs. All reported E2E values are arithmetic means of five runs.All five workloads meet the 5% acceptance tolerance. Auto chooses ordinary generation for both short cases; their small timing differences are not claimed as a kernel speedup. Relative to the fastest legacy baseline, mean latency falls by 50.06% for 1×512 + 31×16, 29.27% for 1×128 + 31×4, 15.10% for 16, 32, …, 512. These improvements come from fewer prefill Forwards and reduced padded work.
Throughput and peak allocated memory for every path
Throughput is 512 divided by mean latency. Memory is peak PyTorch allocated memory during timed calls, including model weights.
Separate profiling breakdown
One additional profiling call per candidate, outside acceptance timing. These diagnostics are not averages. Cache management is part of the generation overhead, not an additional independent total.
The 128/4 and 512/16 workloads reduce prefill Forwards from 32 on aligned CB to 2 on Auto. Spread uses 6 buckets. All CB paths in these performance runs have zero trims and zero moved bytes; ordinary generation has no static-cache statistics. This makes no new trimming-speedup claim.
Validation and limits
A separate microbenchmark measures planner overhead, without model Prefill: for 128/256 requests of 65,536 tokens, CPU DP takes 0.48/1.82 ms on average with the default per-bucket token limit. It still checks all 8,256/32,896 candidate segments; over-limit segments skip cost evaluation. For 32 requests, DP takes 0.089 ms at length512 and 0.040 ms at length65,536 (0.078 ms with no token limit). GPU mask validation/length extraction for 32×65,536 takes 0.83 ms separately. Measurements use ten repeated timing samples after warmup. These are not 64k model Prefill timings or the complete Auto-path overhead.
The original validation passed 105 related rollout/cache tests, including independent exhaustive partition comparisons for DP, device-backed tiny-Qwen tests for grouped prefill and refill, both cache APIs, effective generation-config/legacy refresh, repetition history, EOS/PAD masks, capacity bounds and external-wall-time checks for profiling. Existing tests cover retirement, compaction and trimming. Independent mixed-bucket checks also exercised live-survivor refill and trimming on/off against padded per-request HF generation.
One pre-existing native shared-prefill extension test is excluded because the host has no CUDA compiler; all added tests ran. Changed-file pre-commit and
git diff --checkpass. Repeated local review ended with no actionable findings.python -m pytest -q \ tests/unit/runtime/rollout/test_hybrid_engine_rollout.py \ tests/unit/runtime/rollout/test_continuous_batching.py \ tests/unit/runtime/rollout/test_rollout_interface.py \ tests/unit/utils/test_static_cache.py \ -k 'not native_repeat_kv_cache_fp16_reverse_copy'The prefill token limit does not bound allocated decode KV memory. A single prompt over that limit raises an explicit error; there is no chunked prefill. 64k prompts require a model context limit covering prompt plus output budget, sufficient KV capacity and temporary memory. The measured checkpoint is configured for 32k. Planner/position-limit boundaries are tested; real 64k inference performance is not claimed.
Performance evidence uses unsharded HF models behind
HybridEngineRollout; the additional calibrated and real-question checks are listed below. Other model/device configurations, FP16, native kernel injection, ZeRO/TP training integration and production arrival/EOS distributions remain unmeasured. Controlled performance runs do not exercise staggered EOS or trimming; those have correctness coverage.No new dependency, kernel, online learner or trimming redesign. Related foundation: #8368; profiling: #8494.
Reviewer follow-up
Commit 65a9115 propagates the resolved generation configuration through continuous Prefill, Decode and refill, and omits
output_logitsfrom legacy manual generation. 27 targeted tests pass, including six new cases covering both Auto routes, both cache APIs and manual equal-width/aligned compatibility. The new tests reproduced four failures before the fix. The compatibility test uses a strict generation wrapper that rejects the unsupported keyword.Calibration and evaluation tooling moved to DeepSpeedExamples #1018, with its fitting regression test and usage documentation. Merge the Examples companion before this PR so the documentation link is available. The Examples companion includes MHA-head fallback and validates a source fingerprint covering rollout, planning and static-cache code. A seeded tiny-model GPU smoke check completed calibration and all four saved-config sweep workloads with matching output IDs on every path. Two independent local reviews returned no findings.
The calibrated sweep from the preceding routing-overhead fix is separate from the original 16-token experiments above. It uses two EOS-disabled output tokens, SDPA and one GPU, with independent uniform calibration shapes and one unchanged coefficient set per configuration:
Values are Auto E2E / fastest manual baseline E2E. The two larger models select no-CB for 128×16 and bucketed CB for the other three cases; the tiny model selects no-CB throughout. Auto matches ordinary output IDs in all twelve cases. Target-model means use three interleaved repetitions after warmup; the tiny test uses ten. Full sweep details and calibration limits.
A separate Qwen3-32B real-question check selected no-CB on both workloads: MATH-500 averaged 31.452 s / 31.393 s for ordinary/Auto over three runs; ARC-AGI-2 measured 237.560 s / 237.888 s in one paired run. All eight responses matched. These checks cover complete generation calls, excluding tokenization, loading, rewards and training.
A real tiny-OPT calibration additionally exposed a missing HF cache capability flag. Commit ecacbce adds
is_compileable=Trueto the static-cache container, matching its existing static layers. Six targeted GPU checks pass, including new OPT manual/Auto comparisons with padded prompts and refill against the HF oracle, plus existing Qwen bucket/cache-path checks. The three Examples regression tests cover fitting, complete OPT calibration and saved-source compatibility. Both local reviews found no issues in this follow-up.Final correctness and performance acceptance
Commit d4def3d includes the final fixes: non-default repetition penalties are calculated in FP32 like HF, and unknown public generation switches are rejected before routing. The default-penalty path retains its early return. Five focused BF16 checks and six unknown-setting CPU cases pass. The Examples CLI now requires complete metadata for saved calibration files. Both independent correctness and performance reviews returned no findings after these fixes.
A new calibration and sweep were run against measured commit
d4def3d. Qwen3-32B, BF16, SDPA, one GPU; two EOS-disabled output tokens; one warmup plus three interleaved timed runs per path. Calibration and held-out evaluation use separate shapes. The calibration file, sweep and that measured revision's rollout/planner/static-cache sources have the same combined SHA256:f9d79a43d2e6c0e3fef164ef11e81a26c643820beb1a0d3f1a86f41a46dbdd0c.All four pass the 5% acceptance tolerance; worst measured regression is +0.07428%. Auto output IDs match ordinary generation in every case, and both routes are exercised. Means and ratios were independently recomputed from raw samples. The legacy aligned spread baseline retains its previously recorded second-token difference on one row; Auto matches no-CB there. Fixed output length prevents this numerical-sensitive baseline difference from changing the amount of timed work.
The fitted coefficients are fixed=28.791679 ms, token=0.093362064 ms, attention=0.010090454 ms/GFLOP, KV=0.056288540 ms/MiB and additional decode=17.144541 ms/step. The earlier tables remain historical measurements on their original versions. This final check does not establish long-context, natural-EOS, 256-request E2E or dynamic-arrival performance. Auto remains disabled by default.
Commit a0588b7 then fixes manual aligned prefill to retain the original padded repetition history. Its focused GPU regression reproduced the mismatch and now passes. Auto already passed this same mapping, and the measured default-penalty paths do not read it; independent correctness and performance delta reviews returned no findings. The table remains attributed to
d4def3d, with no timings or hashes relabeled as a new-HEAD measurement. The Examples benchmark explicitly requires Transformers >=4.56; the library's existing compatibility scope is unchanged.Review invitation
cc @nathon-lee @delock — this follows your continuous-batching, profiling, and aligned-cache work in #8368, #8494, and #8497. Could you review the automatic route selection, bucket/refill cache semantics, and cost defaults?
November refresh
Rebased onto
b62afa8and squashed to one commit; the PR is now mergeable. The refresh keeps #8732 graph state, #8839 last-position prefill logits, #8933 accelerator-neutral graph calls and #8852DeepSpeedStaticCache.get_query_offset(). #8980's explicit accelerator opt-in is respected: a backend withoutis_graph_capture_supported()falls back to eager before any routing decision.Superseded by 8a9641b: Auto now combines eager bucketed prefill with fixed-slot graph decode (see the November 11 update). SegKI (#8602) is not part of this PR.
Validation, 8×H200-class node with one GPU in use (NVIDIA H20Z, PyTorch 2.9.1+cu128, CUDA 12.8, Transformers 4.57.1):
Graph replay, resolved-config propagation on both routes (FP32/BF16), DP bucket/refill oracles, Auto/Graph rejection (since replaced by joint routing) and manual graph dispatch all pass. No new performance numbers are claimed: the tables above were measured before #8839/#8732, so refreshed baselines need a separate calibration run if wanted.
AI assistance was used for the rebase, conflict resolution, test execution and drafting of this description; the submitting human reviewed the diff and the results above.
🤖 Generated with Claude Code