Skip to content

Fix prefill delayer wait histograms always observing 0#25975

Merged
hnyls2002 merged 1 commit into
sgl-project:mainfrom
kingjameschan:fix/prefill-delayer-wait-histogram
Jun 14, 2026
Merged

Fix prefill delayer wait histograms always observing 0#25975
hnyls2002 merged 1 commit into
sgl-project:mainfrom
kingjameschan:fix/prefill-delayer-wait-histogram

Conversation

@kingjameschan

@kingjameschan kingjameschan commented May 21, 2026

Copy link
Copy Markdown
Contributor

Motivation

The sglang:prefill_delayer_wait_forward_passes and sglang:prefill_delayer_wait_seconds histograms increment their _count but their _sum (and every percentile) stays at 0 forever, regardless of how long the prefill delayer actually held prefills. The prefill_delayer_outcomes_total counter is unaffected.

Fixes #25949.

Root cause

_record_single_pass_result derived the wait length from output.next_state:

  • next_state is None on every release path (wait_success, no_wait, wait_timeout, token_watermark, ""), so the wait values fell to 0.
  • The histograms are only observed on release (output_allow and actual_execution).
  • delay outcomes do carry the accumulated count via next_state, but they skip the observation because output_allow=False.

These two conditions are mutually exclusive, so the histograms only ever saw observe(0).

Modifications

  • Add wait_forward_passes / wait_seconds fields to _NegotiateOutput and populate them from prev_state on every release path (delay paths keep the default 0, since the wait isn't finished and isn't observed).
  • _record_single_pass_result now observes these surfaced fields instead of recomputing from next_state.
  • Extend the existing CPU/gloo negotiate unit test with an expected_wait_forward_passes expectation and assert it on the no_wait, wait_success, wait_timeout, and queue-trigger release outcomes (regression guard — these would all observe 0 before this change).

No behavior change to scheduling decisions: the set of observed outcomes is unchanged; only the recorded magnitude is corrected from 0 to the real accumulated wait.

Accuracy Tests

N/A — observability-only change; no kernel or model-forward code is touched.

Speed Tests and Profiling

N/A — no inference hot path is affected.

Checklist

🤖 Generated with Claude Code


CI States

Latest PR Test (Base): ❌ Run #26215523528
Latest PR Test (Extra): ❌ Run #26215523120

The sglang:prefill_delayer_wait_{forward_passes,seconds} histograms
incremented their _count but kept _sum (and every percentile) at 0. The
wait length was derived from output.next_state, which is None on every
release path, while the histogram is only observed on release
(output_allow and actual_execution). Delay outcomes do carry the
accumulated count via next_state but skip the observation because
output_allow is False, so the histograms only ever saw observe(0).

Surface the accumulated wait (forward passes and seconds) explicitly
through _NegotiateOutput so the release paths carry the real value, and
observe those fields in _record_single_pass_result. Extend the
negotiate unit test to assert the surfaced wait on release outcomes.

Fixes sgl-project#25949

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances the prefill delayer by explicitly tracking and reporting accumulated wait metrics, specifically wait_forward_passes and wait_seconds, within the _NegotiateOutput structure. This change ensures that metrics are accurately captured during prefill release paths. Corresponding tests were updated to include assertions for these new fields. A review comment suggests an optimization to use a dictionary literal and avoid unnecessary time calculations when no previous state exists.

Comment on lines +186 to +191
wait_info = dict(
wait_forward_passes=prev_state.delayed_count if prev_state else 0,
wait_seconds=(
(time.perf_counter() - prev_state.start_time) if prev_state else 0.0
),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Optimization: Use a dictionary literal and only calculate wait metrics if prev_state exists. This avoids unnecessary time.perf_counter() calls and dictionary allocations when no prefill is being delayed. Since _NegotiateOutput has default values for these fields (0 and 0.0), an empty dictionary is sufficient when there is no previous state to report.

        wait_info = {
            "wait_forward_passes": prev_state.delayed_count,
            "wait_seconds": time.perf_counter() - prev_state.start_time,
        } if prev_state else {}

@hnyls2002 hnyls2002 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@hnyls2002

Copy link
Copy Markdown
Collaborator

/rerun-test test/registered/scheduler/test_prefill_delayer.py

@hnyls2002

Copy link
Copy Markdown
Collaborator

/tag-and-rerun-ci

@github-actions

github-actions Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

🚀 8-gpu-h200 (1 test): ✅ View workflow run

cd test/ && python3 registered/scheduler/test_prefill_delayer.py

@hnyls2002 hnyls2002 merged commit b796338 into sgl-project:main Jun 14, 2026
139 of 169 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sglang:prefill_delayer_wait_{forward_passes,seconds} histograms always observe 0

2 participants