Skip to content

[FIX] make the grading anchor and the config it was measured on inseparable - #1091

Open
ZhengGong-amd wants to merge 11 commits into
mainfrom
fix/zgong/baseline-tput
Open

[FIX] make the grading anchor and the config it was measured on inseparable#1091
ZhengGong-amd wants to merge 11 commits into
mainfrom
fix/zgong/baseline-tput

Conversation

@ZhengGong-amd

Copy link
Copy Markdown
Collaborator

Branch: fix/zgong/baseline-tput, 10 commits on top of a56bf465a.

A gain only means something when both numbers were taken on the same
configuration. 05a1fd6e5 centralised the number in
resolve_grading_anchor_tput(); this branch makes the number and the config
travel together and removes the ways they came apart. Evidence is session
96925 (gemma-4-26B-A4B-it, vLLM/MI355X, code_revision 16eb8c4): reported
58.93% gain after measuring 65.65%, with six consecutive −37% to −41% EXPLORE
results from levers that never ran.

Fixes

The delegate path seeded the anchor and nothing elseb9f0711e7.
_route_delegate claimed "parity with _materialize_approved_proposal" but
injected only base_tput, omitting base_extra_args, base_extra_envs,
base_remove_args, base_unset_envs, base_args_mode. Variants therefore
launched on a bare config while being graded against the established recipe. All
five EXPLORE rounds in 96925 took that channel (base_extra_args absent as a
key in every tasks row, base_tput present and correct); with the anchor at
7725.60 tok/s and baseline at 4663.79:

variant tok/s vs baseline recorded gain
kernarg-hipblaslt 4677.88 +0.30% −39.45%
aiter-rmsnorm-on 4666.53 +0.06% −39.60%
moe-dispatch-policy-1 4693.34 +0.63% −39.25%
block-size-32 4882.77 +4.70% −36.80%
max-num-seqs-128 4691.80 +0.60% −39.27%
max-batched-tokens-32768 4577.75 −1.84% −40.75%

Six unrelated levers clustering on the raw baseline is the naked-config
signature, not six bad levers; grading the bare baseline against that anchor
gives −39.63%.

The executor's drift guard cannot catch this. It fires on
live_anchor > base_tput and both sides resolve through
resolve_grading_anchor_tput, so when the anchor is seeded correctly and only
the args are dropped the two are equal by construction — a strict > skips
exactly the case that needs it. It has to be fixed at the source.

Confirmation disagreed with the decision4aa023381. Round 1 grades
against running_base_tput, which advances with each in-batch KEEP, but the
round-2 stability floor was built from the round-start base_tput. For the 2nd+
variant the floor sat a whole KEEP below the live bar, so a variant that
regressed against the recipe it was layered on still cleared stable, had its
gain recomputed negative, and was KEPT — lowering the bar for everything after.
Floor and enable_stack_rebench now anchor on running_base_tput.

A cold candidate against a hot anchorfebe75fc2.
INFERENCE_OPTIMIZER_EXPLORE_WARM_DECISION could disable the warm decision round
while baseline_tput stays the hot round of the baseline double-run, biasing a
whole round negative. Both sides key off the same resolve_lifecycle_params
verdict; the env var is gone so that coupling is the only control.

Paired re-read8963524bd. The queued-snapshot supersede refreshed only
the anchor; it now takes args, envs and arg-mode controls from the same
current_best, all or none.

Refactors

bbeccf745 + 7ed4eea44 + 7fb6119fe: the five base_* params were seeded by
hand in six functions across six files in five different shapes, and not at all
on the delegate path. inject_stack_base_params(params, state, *, anchor, overwrite) in state/shared_state.py now owns the projection (15 insertions,
140 deletions). It also settles three inconsistencies: profile/sweep/
integrate_patch seeded args but not envs; the phases hand-rolled what
to_str_list does; the integrate_patch rebind overwrote anchor and args but
only filled absent controls.

0417d6ebf + bfb29bc0e: drop baseline_hot_tput (provably equal to
baseline_tput) and baseline_cold_tput (no runtime reader); rename the explore
ledger's cold_tput to decision_tput, since it holds the round-1 measurement
which is warm whenever warm-decision is active; delete the last_run_tput guard
that could not fire.

fd4b0b437 + 7fb6119fe are self-review passes reversing redundancy the
preceding commits added.

Commits

sha subject
0417d6ebf refactor(state): drop the baseline_hot_tput mirror of baseline_tput
bfb29bc0e refactor(explore): retire the dead last_run_tput guard, name the decision round
febe75fc2 refactor(explore): tie warm decision to lifecycle eligibility, drop the env opt-out
8963524bd fix(explore): re-read the base args with the live anchor, not just the number
4aa023381 fix(explore): confirm each in-batch KEEP against the anchor it was graded on
fd4b0b437 refactor: strip the redundancy the preceding commits introduced
bbeccf745 refactor(state): add inject_stack_base_params for the base config pair
7ed4eea44 refactor: route every base config seeding site through the shared helper
b9f0711e7 fix(explore): seed the stack, not just the anchor, on the delegate path
7fb6119fe refactor(state): tighten inject_stack_base_params and refresh its callers' docs

Tests

  • test_critic_verdict_map.py::test_delegate_explore_seeds_the_stack_with_the_anchor
    — verified by reverting _route_delegate, which reproduces the session
    signature: KeyError: 'base_extra_args'.
  • test_explore_executor.py — paired re-read, and the rebench floor following
    the in-batch anchor (old floor lands the regressing variant as KEEP with a
    negative gain_pct).
  • test_shared_state_units.py::TestInjectStackBaseParams — 7 cases: anchor
    on/off, setdefault vs overwrite, clearing a superseded layer, fields
    current_best lacks, baseline_tput fallback, None tolerance.
  • Cold-path cases now patch resolve_lifecycle_params instead of setting the
    removed env var.

717 passed / 1 skipped across the 17 affected test files. ruff check and
pylint --errors-only show no new findings vs. the pre-change baseline.

Breaking changes

None. SharedState.from_dict filters to known __dataclass_fields__, so an old
state.json carrying the two removed fields still loads. cold_tput is a
diagnostic ledger key with no runtime reader; current_best["cold_tput"], which
is read, is untouched. The removed env var appeared in no doc, script or workflow.

Not in this branch

  • The conc sweep still drops the champion's envs. executors/sweep.py::_build_grid
    builds variant_envs from scratch and never merges base_extra_envs, so the
    sweep runs the champion's args with none of its envs — in 96925 the final
    sweep ran without the six AITER variables. This branch makes the fix a one-line
    merge, but it changes what the sweep measures, so it needs its own before/after.
  • writeback.py::_enqueue_internal_stack_rebench keeps hand-rolled seeding:
    revalidation puts the stack in the grid variant, so the helper would
    double-apply it.

ZhengGong-amd and others added 10 commits August 4, 2026 03:42
baseline_hot_tput was assigned float(tput) in the same branch that assigned
baseline_tput the identical value, so the two fields were provably equal and
the mirror carried no information. Nothing in the runtime ever read it; only
tests asserted on it.

baseline_cold_tput stays: it is the only durable record of the discarded cold
round, since current_best.cold_tput is overwritten by the first KEEP.

Co-authored-by: Cursor <cursoragent@cursor.com>
…sion round

Only last_run_tput's None-ness was ever read, and every path that appended to
winners assigned it first, so the guard it gated could not fire. Fold it into
the plain `winners` check.

cold_tput held the round-1 measurement, which is warm whenever warm-decision is
active, so the name asserted the opposite of what it carried. Rename it (and its
ledger key) to decision_tput, leaving cold_tput to mean the genuinely cold round
the baseline double-run discards.

Co-authored-by: Cursor <cursoragent@cursor.com>
…he env opt-out

INFERENCE_OPTIMIZER_EXPLORE_WARM_DECISION could turn off the warm decision round
on its own, while the baseline deliberately exposes no control over its cold+hot
double-run for exactly this reason. Setting it therefore graded cold candidates
against a hot anchor -- a systematic negative bias across a whole round, with
nothing reporting it.

Both sides already key off the same resolve_lifecycle_params verdict, so they
measure hot together or cold together. Keep that coupling and remove the only way
to break it. lifecycle_eligible stays: it is a capability gate, not redundancy --
scriptable frameworks boot no server, server_lifecycle is local-only, the reuse
protocol lives in the Magpie built-in scripts, and torch_profiler is incompatible.

Tests that need the single-round cold path now state that precondition directly
instead of flipping the env var.

Co-authored-by: Cursor <cursoragent@cursor.com>
…e number

base_tput and base_extra_args are seeded side by side from the same current_best
when the proposal is materialized, so they are a matched pair by construction.
The executor-side drift guard refreshed only the anchor, so once a KEEP landed
while the task sat queued, a candidate was launched on the snapshotted stack and
graded against the newer number -- a variant that was merely neutral then read
as a regression.

Add resolve_grading_base(), which hands back the anchor together with the args,
envs and arg-mode controls it was measured on, and have explore replace the
whole triple or none of it. It returns None when current_best carries no
positive throughput: the anchor is then baseline_tput, whose args live in the
baseline record rather than on state, so the dispatch-time snapshot stays
authoritative. That case keeps its own anchor-only recovery branch, without
which a params omission grades every variant against zero.

Co-authored-by: Cursor <cursoragent@cursor.com>
…aded on

The round-1 KEEP decision compares a variant against running_base_tput, which
advances with every KEEP in the batch, but the round-2 confirmation floor was
built from the round-start base_tput. For the 2nd and later variants the floor
therefore sat a whole KEEP below the live bar, so a variant that regressed
against the very recipe it was layered on still cleared "stable", had its gain
recomputed into a negative number, and was KEPT -- dragging running_base_tput
down and lowering the bar for everything after it.

Anchor the floor and the enable check on running_base_tput so confirmation and
decision agree. The added test reproduces the old outcome: with the previous
floor the regressing variant lands as KEEP with a negative gain_pct instead of
KEEP_UNSTABLE.

Co-authored-by: Cursor <cursoragent@cursor.com>
Those commits were meant to delete redundant throughput state, but added more
than they removed. Reverse that:

- Drop resolve_grading_base(). It was a near-duplicate of
  resolve_grading_anchor_tput plus _first_positive_tput whose only work was
  copying current_best fields into a dict, so explore now reads current_best
  directly and no new public API is introduced.
- Drop the base_tput <= 0 fallback branch. live_anchor > base_tput already
  holds when base_tput is 0, so the branch could never be the deciding one.
- Delete baseline_cold_tput, which no runtime code reads, along with the
  warmup_anchor if/else that existed only to write it -- both arms assigned
  baseline_tput the same value. The cold round is still recorded on
  current_best["cold_tput"].
- Cut the comments and docstrings back to the constraint being stated instead
  of narrating why the change is correct.

No behaviour change: the grading anchor and its stack are still refreshed as a
pair, and the rebench floor still follows the in-batch anchor.

Co-authored-by: Cursor <cursoragent@cursor.com>
The anchor a candidate is graded against and the args/envs it is launched on top
of are one unit, but seeding them was open-coded at seven call sites with four
different shapes: setdefault-everything in proposals, write-if-non-empty in the
phases, and an overwrite rebind in integrate_patch. Nothing held them together,
so a site could seed one half and silently omit the other.

Project the base_* params from current_best in one place instead, keyed on the
fields current_best actually carries. anchor= opts into base_tput so a grading
caller takes both halves from the same snapshot; overwrite= is for an
execution-time rebind, and is also what lets an empty value clear a superseded
layer rather than read as "no config".

No call site is rewired yet.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replaces the six open-coded copies -- four action branches in
_materialize_approved_proposal plus the mn-auto-materialize, framework config
exploration, internal sweep, internal analysis and integrate_patch rebind sites
-- with inject_stack_base_params, deleting ~130 lines including two
byte-identical blocks in phases/explore.py and phases/framework.py.

Three inconsistencies go with them: profile, sweep and integrate_patch seeded
args but not envs where explore seeded both; the phases hand-rolled the
list-control coercion that to_str_list already does; and the integrate_patch
rebind overwrote the anchor and args while only filling absent controls, so a
superseded layer's controls survived the rebind.

Co-authored-by: Cursor <cursoragent@cursor.com>
_route_delegate claimed parity with _materialize_approved_proposal but injected
only base_tput, so an LLM-driven delegate explore launched every variant on a
bare config while grading it against the established recipe. A 24h gemma-4-26B
run shows the cost: with the anchor at 7725 tok/s, six unrelated variants across
two rounds all measured 4577-4882 -- the raw baseline, within 0.7% for five of
them -- and were recorded at -37% to -41%. The rounds read as "every lever
regresses" when the levers had never been layered on anything.

The executor-side drift guard cannot cover this. It fires on live_anchor >
base_tput, and both sides come from resolve_grading_anchor_tput, so a correctly
seeded anchor with missing args compares equal -- exactly the case that needs
the re-read is the one it skips.

Seed both halves through inject_stack_base_params.

Co-authored-by: Cursor <cursoragent@cursor.com>
…lers' docs

Self-review of the preceding three commits:

- Fold the two single-use normalizers into _STACK_BASE_FIELDS. Naming two of the
  five and inlining the third was inconsistent, and the table is the only reader.
- Type the normalizer slot as Callable[[Any], Any] rather than Any.
- Drop the isinstance guard on extra_envs for the (v or {}) idiom the seeding
  sites already used; the guard was defensive, not load-bearing, and it was what
  pushed that entry to 119 columns.
- _materialize_approved_proposal still advertised "grid executors get current
  best tput as base_tput", which has understated the contract since the anchor
  and its config became one unit.
- Restate the delegate-path comment as the invariant it guards. "Parity with
  _materialize_approved_proposal: direct delegates need the same knobs" named no
  knobs, and was already there while the parity it asserted did not hold.
- Cut the remaining comments to the constraint, dropping a stale parenthetical
  about resolution order at the integrate_patch rebind.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ZhengGong-amd
ZhengGong-amd requested a review from a team as a code owner August 4, 2026 06:14
The executor's anchor-drift rebind hand-copied the same five current_best fields
inject_stack_base_params already normalizes, so _STACK_BASE_FIELDS had two
readers and a field added to one would silently miss the other.

Extract stack_base_params(current_best) as the single projection and have both
use it. The executor now rebinds params before reading its locals out of them,
which leaves one read path instead of a read followed by a conditional
re-assignment of every local. params is a shallow copy of task.params, so the
in-place update never reaches the persisted row.

One edge changes: a current_best carrying positive throughput but no
extra_server_args key no longer clears the params snapshot, because the
projection omits absent fields rather than defaulting them. Only current_best
records written by _lift_to_current_best reach that branch and those always carry
the key, so the case is unreachable in practice; preserving the snapshot is the
safer reading of "the field says nothing".

Co-authored-by: Cursor <cursoragent@cursor.com>
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