use std::cell::RefCell;
use crate::api::apr_q4k_scheduler::q4k_decode;
use crate::generate::CancelToken;
#[derive(Default)]
struct StepLog {
positions: RefCell<Vec<usize>>,
}
impl StepLog {
fn count(&self) -> usize {
self.positions.borrow().len()
}
}
fn run(
first_token: u32,
prompt_len: usize,
max_tokens: usize,
eos_ids: &[u32],
cancel: &CancelToken,
log: &StepLog,
) -> Vec<u32> {
q4k_decode(
first_token,
prompt_len,
max_tokens,
eos_ids,
cancel,
|token, position, _step| {
log.positions.borrow_mut().push(position);
Ok(token.wrapping_add(1))
},
)
.expect("the fake decode step never fails")
}
#[test]
fn q4k_scheduler_decode_stops_at_the_cancel_point_not_max_tokens() {
const PROMPT_LEN: usize = 5;
const FIRST_TOKEN: u32 = 100;
const MAX_TOKENS: usize = 64;
const BUDGET: usize = 8;
let control_log = StepLog::default();
let uncancelled = run(
FIRST_TOKEN,
PROMPT_LEN,
MAX_TOKENS,
&[],
&CancelToken::never(),
&control_log,
);
assert_eq!(
uncancelled.len(),
MAX_TOKENS,
"control: with no cancellation the Q4K loop must emit its full {MAX_TOKENS}-token \
budget (the prefill token plus {} decode steps)",
MAX_TOKENS - 1
);
assert_eq!(
control_log.count(),
MAX_TOKENS - 1,
"control: the uncancelled loop must perform one forward pass per decode step"
);
assert_eq!(
*control_log.positions.borrow(),
(PROMPT_LEN..PROMPT_LEN + MAX_TOKENS - 1).collect::<Vec<_>>(),
"control: decode positions must continue contiguously from the end of the prompt"
);
let token = CancelToken::with_budget(BUDGET);
let cancelled_log = StepLog::default();
let cancelled = run(
FIRST_TOKEN,
PROMPT_LEN,
MAX_TOKENS,
&[],
&token,
&cancelled_log,
);
assert_eq!(
cancelled.len(),
BUDGET + 1,
"the Q4K loop must stop at the cancel point ({BUDGET} decode steps after the \
prefill token), not run to max_tokens ({MAX_TOKENS}); it emitted {} tokens",
cancelled.len()
);
assert_eq!(
cancelled_log.count(),
BUDGET,
"the cancelled run must perform exactly {BUDGET} GPU forward passes; it \
performed {}",
cancelled_log.count()
);
assert_eq!(
token.polls(),
BUDGET + 1,
"the loop must poll exactly once per decode step ({BUDGET} polls that returned \
false, plus the one that returned true and broke the loop)"
);
assert_eq!(
cancelled,
uncancelled[..cancelled.len()].to_vec(),
"a cancelled run must be a strict prefix of the uncancelled run: cancelling \
stops work, it does not change the tokens already produced"
);
}
#[test]
fn q4k_scheduler_decode_cancelled_before_start_does_no_forward_passes() {
const PROMPT_LEN: usize = 3;
const FIRST_TOKEN: u32 = 42;
const MAX_TOKENS: usize = 64;
let control_log = StepLog::default();
let uncancelled = run(
FIRST_TOKEN,
PROMPT_LEN,
MAX_TOKENS,
&[],
&CancelToken::new(),
&control_log,
);
assert_eq!(
control_log.count(),
MAX_TOKENS - 1,
"control: an uncancelled request must perform all {} forward passes",
MAX_TOKENS - 1
);
assert_eq!(
uncancelled.len(),
MAX_TOKENS,
"control: an uncancelled request must emit the full budget"
);
let token = CancelToken::new();
token.cancel();
let log = StepLog::default();
let out = run(FIRST_TOKEN, PROMPT_LEN, MAX_TOKENS, &[], &token, &log);
assert_eq!(
log.count(),
0,
"an already-cancelled request must perform no forward passes at all; it \
performed {}",
log.count()
);
assert_eq!(
out,
vec![FIRST_TOKEN],
"the response may still carry the token already sampled from the prefill \
logits, and nothing more"
);
}
#[test]
fn q4k_scheduler_decode_still_stops_at_eos() {
const PROMPT_LEN: usize = 2;
const FIRST_TOKEN: u32 = 10;
const MAX_TOKENS: usize = 64;
const EOS: u32 = 14;
let log = StepLog::default();
let out = run(
FIRST_TOKEN,
PROMPT_LEN,
MAX_TOKENS,
&[EOS],
&CancelToken::never(),
&log,
);
assert_eq!(
out,
vec![10, 11, 12, 13, 14],
"the loop must stop once EOS is produced, with EOS as the final token"
);
assert_eq!(
log.count(),
4,
"reaching EOS from token 10 takes exactly 4 decode steps"
);
}
#[test]
fn every_apr_q4k_submission_site_forwards_the_request_cancel_token() {
const SITES: [(&str, usize); 3] = [
("src/api/cuda_chat_backend.rs", 1),
("src/api/gpu_completions_handler.rs", 1),
("src/api/batch.rs", 1),
];
let crate_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
for (rel, expected) in SITES {
let path = crate_root.join(rel);
let src = std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("read {}: {e}", path.display()));
let bodies: Vec<&str> = src
.split("AprQ4kRequest {")
.skip(1)
.map(|rest| {
let end = rest.find("})").unwrap_or(rest.len());
&rest[..end]
})
.collect();
assert_eq!(
bodies.len(),
expected,
"{rel} must construct AprQ4kRequest exactly {expected} time(s); found {}. \
If a submission site moved, update this list — a search that matches \
nothing must not pass as clean.",
bodies.len()
);
for body in bodies {
assert!(
body.contains("cancel: cancel.clone()"),
"{rel} submits an AprQ4kRequest without forwarding the request's \
CancelToken (aprender#2465(1)). The Q4K scheduler decodes on its own \
thread, so a dropped response future cannot reach it and there is no \
per-token send to fail — the token is the only thing that stops it. \
Offending literal:\n{body}"
);
}
}
}