Repository navigation
Remove repeated work from scheduler planning - #188
Merged
Merged
Conversation
Funded acceptance learning compared every probe candidate with the ordinary
winner slot by slot, and each comparison of a packed round re-estimated the
whole round's prefix lengths, including lane values, while the allocation
loop re-evaluated every lane's acceptance curve for each extra row. At
concurrency 32 one plan call took 10-35 ms whenever acceptance credit was
full. The worker does not poll completions while it plans, so a finished
round waited for the plan before its successor or a draining probe could
start: on DeepSeek V4.1 TP4 every few seconds, and for about 0.7 s after 32
requests arrived.
Planning also repeated linear work per lane and per shape:
- Each speculative-token bound scanned every lane of the submitted steps to
find the request's pending advance. The ceiling is now tracked on the
request where commit and completion already track its pending count.
- Packed rounds rebuilt rankings, gains, and per-lane curves for every shape
and priorities for every ordering. Shapes sharing draft and width bounds now
share one ranking, lane curves are evaluated once per call, priorities once
per shape, and only the leading cohort of each ordering is sorted.
- Padding pruning compared all candidate pairs and re-estimated round lengths
for each pair. Only candidates with the same kind, cohort, and prefill row
are compared, and each candidate's lengths are estimated once.
- Service rates and next-progress values evaluated the forecast curve for
every batch and width, and every speculative duration repeated a hashed
lookup of the full graph, which the packed round table already includes.
Selection, round lengths, and their arithmetic are unchanged. Seeded
scheduler traces over 1056 scenarios, with 1-64 requests, host and device
prefix allocation, fixed widths, mixed graphs, grammar and host-stop lanes,
queued rounds, retirements, and timing and acceptance probes, record every
plan, lane value, pruned candidate list, probe choice, and round length:
about 210 000 plans compare byte for byte with main; the first quarter also
in a debug build.
Median plan time with one round queued (release test build):
requests allocation main after acceptance probe: main after
8 device 140 us 60 us 2563 us 111 us
16 device 289 us 96 us 2153 us 201 us
32 device 669 us 196 us 5312 us 413 us
64 device 1773 us 436 us 13380 us 943 us
32 host 754 us 250 us 1363 us 497 us
64 host 1957 us 615 us 3546 us 1215 us
DeepSeek V4.1 Flash TP4 on switched GPUs 0-3 of frank1 and frank2,
concurrency 32, seven drafts, verification budget at most 128, alpha 0.6,
Engram tables in RAM, with the exposed-handoff cost change in both builds
(tokens/s, mean of ten 30 s cells, worst cell in parentheses):
host/package before after
frank1 main 2471 (2428) 2524 (2490)
frank1 B 2474 (2432) 2529 (2495)
frank2 main 2478 (2398) 2537 (2503)
frank2 B 2450 (2313) 2540 (2515)
all 40 cells 2468 2532 (+2.6%)
In a diagnostic run of the same service, the GPU busy share of the steady
window rose from 98.4-98.9% to 99.8-99.9%, and no worker iteration exceeded
10 ms.
Validation: Helios library tests (runtime-package and server features) pass
in release and debug builds except five frontend-template, package-cache,
and image-hint tests that fail identically on main for missing local assets.
Debug builds check the tracked pending ceiling against the submitted lanes on
every use. A new test covers queued rounds, completion, and retirement.
Limitations: while a winning probe waits for the queue to drain, the worker
still plans again on every iteration; each plan is now short.
Signed-off-by: Martin Vit <martin@voipmonitor.org>
Design-Signed-Off-By: Claude (Opus 5.5); design-review=1c01
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Derive pending advance from the scheduled and consumed cursors, retaining submission scans for completion reconciliation. Stream acceptance candidates into winner selection without storing all candidate length arrays. Rank monotone prefix survival once with depth and slot tie-breaking. Share the ranking with host cohort allocation and preserve request limits, fixed widths, and GPU-owned allocation ceilings. Validation: 346 scheduler and runtime phase tests pass in both debug and release builds; two tests are ignored by default. Differential tests cover host/GPU allocation, MTP/copy proposals, ties, tails, and cohort growth. A release CPU benchmark measures planning with one queued round and funded or unfunded acceptance probes. GPU serving measurements were not run. Design-Signed-Off-By: Codex (GPT-6); design-review=1c01 Signed-off-by: Luke Alonso <lalonso@gmail.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.
Problem
At C32 on DeepSeek V4.1 TP4 the serving worker stalled for 10–35 ms inside
RequestScheduler::planevery few seconds, and for ~0.7 s after 32 requests arrived. The worker does not poll completions while it plans, so a finished round's successor, or a probe waiting for the queue to drain, started late and the GPU idled.perfput the time in funded acceptance learning:acceptance_probecompared each probe candidate with the ordinary winner slot by slot, and every comparison of a packed round re-estimated the whole round's prefix lengths and lane values, re-evaluating each lane's acceptance curve for every extra row. The rest of planning also repeated per-lane and per-shape work, so its cost grew roughly with the square of the request count.Change
The same values are computed fewer times; selection and its arithmetic are unchanged.
pendingcount, instead of scanning all submitted lanes on every use. Debug builds check it against the scan.Equivalence
A local differential harness (not in this PR) records every plan, lane value, pruned candidate list, probe choice, and round length over seeded random scenarios: 1–64 requests, host/device/mixed prefix allocation, fixed widths, mixed graphs, grammar and host-stop lanes, queued rounds, retirement, refresh and acceptance probes. Across 1056 scenarios and ~210 000 plans the traces of main and this branch are byte-identical (one seed set also in a debug build).
Results
Median
plan()time with one round queued (release test build, frank1):Service at C32 on switched GPUs 0–3 of frank1 and frank2, #182 applied in both builds, two services × five 30 s cells per row, mirrored order:
In a diagnostic run on frank1 the longest plan call fell from 34.4 ms to under 1 ms, no worker iteration exceeded 10 ms, and the GPU busy share of the steady window rose from 98.4–98.9 % to 99.8–99.9 %.
Validation
Limitations
🤖 Generated with Claude Code