use super::model::ModelCfg;
use super::runner::{EOS, ReqSpec, RunOptions, Scenario, run_scenario};
use super::tests::SERIAL;
fn script(n: usize, base: u32) -> Vec<u32> {
let mut g: Vec<u32> = (0..n as u32).map(|i| base + i).collect();
g.push(EOS);
g
}
fn scenario(rows: Option<usize>, lever: bool, late: bool) -> Scenario {
let mut reqs = vec![
ReqSpec::new(1, 12, script(6, 10)),
ReqSpec::new(2, 9, script(3, 20)),
ReqSpec::new(3, 15, script(5, 30)),
];
if late {
for r in &mut reqs[1..] {
r.arrive_at_tick = Some(2);
}
}
Scenario {
name: "ep_prefill_burst",
cfg: ModelCfg {
ep: true,
ep_prefill_batch: rows,
..ModelCfg::default()
},
opts: RunOptions {
max_prefill_tokens: 64,
ep_prefill_batch: lever,
..RunOptions::default()
},
reqs,
}
}
fn trace(sc: &Scenario) -> Vec<String> {
let _g = SERIAL.lock().unwrap_or_else(|e| e.into_inner());
run_scenario(sc)
}
fn outputs(t: &[String]) -> Vec<&String> {
t.iter().filter(|l| l.starts_with("out s")).collect()
}
fn lines<'a>(t: &'a [String], prefix: &str) -> Vec<(usize, &'a String)> {
t.iter()
.enumerate()
.filter(|(_, l)| l.starts_with(prefix))
.collect()
}
fn announced(t: &[String]) -> usize {
t.iter().filter(|l| l.contains("cmd=0xfffffff0")).count()
}
#[test]
fn a_burst_is_one_batched_prefill_with_no_per_request_announcement() {
let on = trace(&scenario(Some(512), true, false));
let off = trace(&scenario(Some(512), false, false));
let batched = lines(&on, "prefill_batch_chunk(");
assert_eq!(batched.len(), 1, "one batched prefill expected:\n{on:#?}");
for len in ["len=12", "len=9", "len=15"] {
assert!(
batched[0].1.contains(len),
"{len} missing from {}",
batched[0].1
);
}
assert_eq!(
announced(&on),
0,
"a deferred chunk 0 was announced:\n{on:#?}"
);
assert!(lines(&on, "prefill_chunk(").is_empty());
assert_eq!(announced(&off), 3);
assert_eq!(lines(&off, "prefill_chunk(").len(), 3);
assert!(lines(&off, "prefill_batch_chunk(").is_empty());
assert_eq!(outputs(&on).len(), 3);
assert_eq!(outputs(&on), outputs(&off), "a client's output changed");
}
#[test]
fn arrivals_behind_an_active_decode_are_batched_before_the_decode() {
let on = trace(&scenario(Some(512), true, true));
let off = trace(&scenario(Some(512), false, true));
let batched = lines(&on, "prefill_batch_chunk(");
assert_eq!(batched.len(), 1, "one batched prefill expected:\n{on:#?}");
assert!(batched[0].1.contains("len=9") && batched[0].1.contains("len=15"));
assert!(!batched[0].1.contains("len=12"));
assert_eq!(
announced(&on),
1,
"only the lone first request is announced"
);
let next_decode = on[batched[0].0..]
.iter()
.find(|l| l.starts_with("decode_batch("))
.expect("a decode after the batched prefill");
let seqs = next_decode
.split("seqs=[")
.nth(1)
.and_then(|r| r.split(']').next())
.expect("seqs in the decode line");
assert_eq!(seqs.split(", ").count(), 3, "{next_decode}");
assert_eq!(announced(&off), 3);
assert_eq!(outputs(&on), outputs(&off), "a client's output changed");
}
#[test]
fn a_step_takes_the_streams_that_fit_its_rows() {
let on = trace(&scenario(Some(22), true, false));
let off = trace(&scenario(Some(22), false, false));
let batched = lines(&on, "prefill_batch_chunk(");
assert_eq!(batched.len(), 1, "{on:#?}");
assert!(batched[0].1.contains("len=12") && batched[0].1.contains("len=9"));
assert!(!batched[0].1.contains("len=15"));
let single = lines(&on, "prefill_chunk(");
assert_eq!(single.len(), 1);
assert!(single[0].1.contains("len=15") && single[0].0 > batched[0].0);
assert_eq!(announced(&on), 1);
assert_eq!(outputs(&on), outputs(&off), "a client's output changed");
}
#[test]
fn the_lever_is_inert_on_a_model_without_support() {
for late in [false, true] {
assert_eq!(
trace(&scenario(None, true, late)),
trace(&scenario(Some(512), false, late))
);
}
}