Skip to content

[Fix] dspark: Produce correct SPS cost tables when profiling a server without a table - #42711

Open
ormandj wants to merge 2 commits into
sgl-project:mainfrom
ormandj:dspark-forced-budget-verify-all
Open

ormandj wants to merge 2 commits into
sgl-project:mainfrom
ormandj:dspark-forced-budget-verify-all

Conversation

@ormandj

@ormandj ormandj commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

Without this change, an SPS cost table profiled on a server that has no table yet records full-width verify costs for every budget, so the planner that uses the table plans from wrong costs.

python -m sglang.benchmark.dspark_sps_profiler run --fracs ... profiles the off-diagonal SPS cost T(bs, M) by pinning dspark_force_budget_frac (through /set_internal_state) on a server running SGLANG_RAGGED_VERIFY_MODE=compact. A server started without --speculative-dspark-sps-table-path has the flat, uninitialized table, so DSparkVerifyPlanner is verify-all. This is the state when profiling the off-diagonal costs without a seed table. schedule_layout then returns the cached full-width layout before it looks at the budget. The budget planner does compute the pinned budget, but the layout ignores it. Pinned cells still run full-width verify, while the profiler records them under the requested M; its validation does not reject the mismatch.

I observed this on DeepSeek-V4.1-Flash, TP4 on 4x RTX PRO 6000 Blackwell (SM120), gamma=5: a --batch-size 1 2 4 8 --fracs 0.2 0.4 0.6 0.8 1.0 sweep on a server with no SPS table recorded only full-width steps (bs=4 always verified 24 tokens). The same sweep on a server started with a 1D table applied the budgets, for example bs=8 ran at 44.3 steps/s with 16 verify tokens vs 33.8 steps/s with 48.

#40567 changes how profiler control reaches the planner; it leaves this verify-all shortcut unchanged.

Modifications

  • DSparkVerifyPlanner.schedule_layout: the verify-all shortcut (cached uniform layout) now applies only while no budget fraction is pinned. Clearing the pin (dspark_force_budget_frac=None through /set_internal_state) brings back the cached layout.
  • /set_internal_state rejects pinning dspark_force_budget_frac while simulated acceptance is on (SGLANG_SIMULATE_ACC_LEN above 0), unless the length is exactly 1.0 with SGLANG_SIMULATE_ACC_METHOD=match-expected (the default), which always accepts exactly one token. multinomial samples the accept length from a normal distribution around SGLANG_SIMULATE_ACC_LEN, so even 1.0 can accept two or more tokens, past a trimmed compact verify window and onto target KV that verify never wrote. Now that a pin trims verify under verify-all, a constant simulated accept length could exceed the trimmed budget, which the DSpark worker already rejects at startup for profiled tables. Clearing the pin is still allowed.
  • New TestForcedBudgetUnderVerifyAll (test/registered/spec/dspark/test_dspark_scheduler.py, CPU): with the uninitialized table, schedule_layout gives the full-width layout without a pin, a trimmed layout at frac=0.4 (12 verify tokens instead of 24 at bs=4, on main 24), and the cached layout again after the pin is cleared.
  • New TestForcedBudgetRejectsSimulatedAcceptLength (same file) drives SchedulerInternalStateController.set_internal_state. With SGLANG_SIMULATE_ACC_LEN=3, or 1.0 with SGLANG_SIMULATE_ACC_METHOD=multinomial, the pin is rejected and the worker's budget setter is not called. Clearing the pin, and pinning with the variable set to -1.0 (disabled, with either method) or to 1.0 with match-expected, still work. On main, the rejection case fails.

Serving is unchanged unless a fraction is pinned. The pin is only set through /set_internal_state, which the profiler uses.

Accuracy Tests

This changes pinned layout selection and rejects incompatible simulated-accept-length settings; model outputs are unchanged when no fraction is pinned.
test_dspark_scheduler.py: 29 passed on CPU, including the four new tests.

Speed Tests and Profiling

No GPU speed measurements for this diff; serving is unchanged unless a fraction is pinned.

Checklist

Review and Merge Process

  1. Ping Merge Oncalls to start the process. See the PR Merge Process.
  2. Get approvals from CODEOWNERS and other reviewers.
  3. Trigger CI tests with comments or contact authorized users to do so.
    • Common commands include /tag-and-rerun-ci, /tag-run-ci-label, /rerun-failed-ci
  4. After green CI and required approvals, ask Merge Oncalls or people with Write permission to merge the PR.

Developed with AI assistance.


CI States

Latest PR Test (Base): ❌ Run #40961582812
Latest PR Test (Extra): ❌ Run #40961582767
Latest PR Test (AMD ROCm 10): ❌ Run #40961582732

…lized

dspark_sps_profiler --fracs pins dspark_force_budget_frac on a compact
server to profile the off-diagonal SPS cost T(bs, M). Before a profiled
table exists the planner is verify-all, and schedule_layout returned the
cached full-width layout before consulting the budget, so every pinned
cell measured full-width verify and the fitted 2D table was flat in M.
Serve the cached layout only while no fraction is pinned.

Since a pin now trims verify under verify-all, reject pinning it while
SGLANG_SIMULATE_ACC_LEN is above 1, as the DSpark worker already does at
startup for profiled tables.
SGLANG_SIMULATE_ACC_METHOD=multinomial draws the accept length from a
normal around SGLANG_SIMULATE_ACC_LEN, so a configured 1.0 can still
accept past a trimmed compact verify window. Allow the pin only when the
simulated length is exactly 1.0 with match-expected sampling.
@ormandj
ormandj force-pushed the dspark-forced-budget-verify-all branch from 8c443d9 to 0c2039f Compare October 29, 2026 21:53

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant