Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/apr-cli/src/commands/bench_qwen35.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ fn run_qwen35_session_benchmark(

bench_log(config, &"Running warmup...".yellow().to_string());
for i in 0..config.warmup {
session.forget_prefix();
let _ = session.generate(prompt_tokens, gen_config, &mut |_| true);
bench_log_iter(config, i, Duration::ZERO, None);
}
Expand Down Expand Up @@ -64,6 +65,9 @@ fn session_timed_turn(
tracer: &TracerImpl,
budget_us: u64,
) -> Result<(realizar::session::Turn, Duration, Duration)> {
// #4445: every timed turn repeats the same prompt, which the session would
// otherwise resume from its checkpoint; forget it so the turn prefills whole.
session.forget_prefix();
let t0 = Instant::now();
let mut first: Option<Duration> = None;
let traced = tracer.trace("bench_qwen35_session_iter", budget_us, || {
Expand Down
16 changes: 16 additions & 0 deletions crates/aprender-serve/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,22 @@ impl<F: ArchForward> Session<F> {
self.processed.len()
}

/// Drop every prefix the session could resume from — the held positions
/// (and, where the session has one, the #4214 checkpoint) — so the next turn prefills its whole prompt
/// (`Turn::reused == 0`). `apr bench` needs this: it times the same prompt
/// repeatedly, and a resumed prefix would report decode as prefill (#4445).
pub fn forget_prefix(&mut self) {
// Exhaustive on purpose: a field added to Session (the car's #4214
// `checkpoint` is one) fails to compile here until it is reset too, so
// no merge can leave a resumable prefix behind silently.
let Self {
forward: _,
processed,
id: _,
} = self;
processed.clear();
}

/// `tokens` strictly extends what the state holds.
fn extends(&self, tokens: &[u32]) -> bool {
!self.processed.is_empty()
Expand Down
16 changes: 16 additions & 0 deletions crates/aprender-serve/src/session_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,19 @@ fn plain_greedy_takes_the_device_argmax_and_a_penalty_or_sampling_does_not() {
"a repeat penalty needs the logits"
);
}
// #4445: `apr bench` repeats one prompt and must time a whole prefill each time.
// An extending prompt would resume the held state; after forget_prefix it may not.
#[test]
fn forget_prefix_makes_an_extending_prompt_prefill_whole_again() {
let mut s = Session::new(Scripted::new(3, 100));
let t1 = s
.generate(&[7401, 7402], &greedy(1), &mut |_| true)
.expect("t1");
let mut p2 = t1.tokens.clone();
p2.extend([7403, 7404]);
s.forget_prefix();
assert_eq!(s.processed_len(), 0);
let t2 = s.generate(&p2, &greedy(1), &mut |_| true).expect("t2");
assert_eq!(t2.reused, 0, "resumed a prefix after forget_prefix");
assert_eq!(s.engine().calls.last(), Some(&(p2.len(), 0)));
}
20 changes: 20 additions & 0 deletions docs/roadmaps/entries/PMAT-4445.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
- id: PMAT-4445
github_issue: 4445
item_type: task
title: 'apr bench (qwen35 --fast) refuses every run with warmup+iterations > 1: one session reuses its own prefix cache'
status: inprogress
priority: high
assigned_to: aprender-bb
created: 2026-09-27T11:13:42+00:00
updated: 2026-09-27T11:13:42+00:00
spec: null
acceptance_criteria:
- 'Session::forget_prefix drops every prefix the session can resume from. On main that is the held positions (Session has no checkpoint yet); it destructures Session exhaustively, so a merge that adds the #4214 checkpoint field does not compile until forget_prefix resets it too'
- 'bench_qwen35 calls forget_prefix before every warmup turn and every timed turn, so every timed turn prefills its whole prompt; the reused != 0 guard itself is unchanged'
- 'session::tests::forget_prefix_makes_an_extending_prompt_prefill_whole_again: an extending prompt, which on main would resume (reused == 2), prefills from position 0 after forget_prefix; RED when forget_prefix does not clear (mutant measured 2026-09-27, panics at session_tests.rs:248)'
- 'When this meets car/0.70.0 (#4429), the resolution is the car-side form already reviewed on bb/4445-bench-fresh-prefill @9c34ca648d: forget_prefix also sets checkpoint = None, plus session::tests::forget_prefix_makes_the_same_prompt_prefill_whole_again (identical prompt 3x, reused == 0, no restore; RED on a forget_prefix that keeps the checkpoint, measured)'
phases: []
subtasks: []
estimated_effort: null
labels: []
notes: 'Adopted from aprender-ea orphan fix/4445-bench-fresh-prefill @65fd973170 (09-25, never PRed). The bug exists only with the #4214 checkpoint, i.e. car/0.70.0 (#4429); main before #4429 does not reuse an identical prompt. Cop ruling 2026-09-27: not folded into the car; own PR on main the moment #4429 merges, before the rc.1 tag. Superseded 2026-09-27 ~14:00Z by operator "make it faster" (via cop): open on main NOW, in parallel with the car. Until the car lands this change is inert on main (an identical prompt already prefills whole there); it pre-lands the bench wiring and the API so the car merge needs only the checkpoint line, which the exhaustive destructure forces.'
20 changes: 20 additions & 0 deletions docs/roadmaps/roadmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22091,6 +22091,26 @@ roadmap:
labels:
- kind:code
notes: 'Collapse the ~20 ci.yml jobs into 5 fat jobs; each runs every section (ci/sections.yml, verbatim old job bodies; vendored sovereign-ci verified against its upstream sha256) to completion on the biggest runner in its class via scripts/ci/fat_driver.py. Required contexts gate / workspace-test / ci / gate keep their names. scripts/ci/sigma_executed.py enforces the executed test-id set == the universe listed independently (by id, not count); a dropped test turns it RED. Train-active priority hook kept as a floor. Item 3 (rc.N = tag on queue-green main) and the #4434/#4436 release-rule docs are a follow-up PR. Scope of the driver: fat_driver.py collapses the MULTI-section Linux jobs (x86-main, gx10, yoga, determinism); mac-check is the ruling''s mac-refusal job, already ONE section on the one macOS runner (no docker there), so it keeps its steps and its context name, and as on main it is not in gate.needs.'
- id: PMAT-4445
github_issue: 4445
item_type: task
title: 'apr bench (qwen35 --fast) refuses every run with warmup+iterations > 1: one session reuses its own prefix cache'
status: inprogress
priority: high
assigned_to: aprender-bb
created: 2026-09-27T11:13:42+00:00
updated: 2026-09-27T11:13:42+00:00
spec: null
acceptance_criteria:
- 'Session::forget_prefix drops every prefix the session can resume from. On main that is the held positions (Session has no checkpoint yet); it destructures Session exhaustively, so a merge that adds the #4214 checkpoint field does not compile until forget_prefix resets it too'
- 'bench_qwen35 calls forget_prefix before every warmup turn and every timed turn, so every timed turn prefills its whole prompt; the reused != 0 guard itself is unchanged'
- 'session::tests::forget_prefix_makes_an_extending_prompt_prefill_whole_again: an extending prompt, which on main would resume (reused == 2), prefills from position 0 after forget_prefix; RED when forget_prefix does not clear (mutant measured 2026-09-27, panics at session_tests.rs:248)'
- 'When this meets car/0.70.0 (#4429), the resolution is the car-side form already reviewed on bb/4445-bench-fresh-prefill @9c34ca648d: forget_prefix also sets checkpoint = None, plus session::tests::forget_prefix_makes_the_same_prompt_prefill_whole_again (identical prompt 3x, reused == 0, no restore; RED on a forget_prefix that keeps the checkpoint, measured)'
phases: []
subtasks: []
estimated_effort: null
labels: []
notes: 'Adopted from aprender-ea orphan fix/4445-bench-fresh-prefill @65fd973170 (09-25, never PRed). The bug exists only with the #4214 checkpoint, i.e. car/0.70.0 (#4429); main before #4429 does not reuse an identical prompt. Cop ruling 2026-09-27: not folded into the car; own PR on main the moment #4429 merges, before the rc.1 tag. Superseded 2026-09-27 ~14:00Z by operator "make it faster" (via cop): open on main NOW, in parallel with the car. Until the car lands this change is inert on main (an identical prompt already prefills whole there); it pre-lands the bench wiring and the API so the car merge needs only the checkpoint line, which the exhaustive destructure forces.'
- id: PMAT-4453
github_issue: 4453
item_type: task
Expand Down
Loading