use metrale_model_engine::traits::SequenceState;
use super::model::{GARBAGE, ModelCfg, RecordingModel};
use super::pipeline_tests::{async_run, client_lines, count, sync_run};
use super::runner::{EOS, ReqSpec, RunOptions, Scenario};
use super::scenarios;
fn ep_recurrent(rows: Option<usize>) -> ModelCfg {
ModelCfg {
ep: true,
has_ssm_layers: true,
recurrent_fed_rows: rows,
..ModelCfg::default()
}
}
fn c1(name: &'static str, cfg: ModelCfg) -> Scenario {
let mut eos = ReqSpec::new(1, 5, (10..22).chain([EOS]).collect());
eos.max_tokens = 30;
let mut budget = ReqSpec::new(2, 7, (30..50).collect());
budget.max_tokens = 9;
Scenario {
name,
cfg,
opts: RunOptions {
max_batch_size: 1,
..RunOptions::default()
},
reqs: vec![eos, budget],
}
}
fn fed_rows_per_launch(lines: &[String]) -> Vec<usize> {
lines
.iter()
.filter_map(|l| l.split_once("decode_batch_fed(").map(|(_, rest)| rest))
.map(|rest| rest.matches("len=").count())
.collect()
}
fn around(lines: &[String], needle: &str) -> String {
let at = lines.iter().position(|l| l.contains(needle)).unwrap_or(0);
lines[at.saturating_sub(12)..=at.min(lines.len().saturating_sub(1))].join("\n")
}
#[test]
fn a_recurrent_multi_rank_model_runs_one_row_ahead_with_the_synchronous_streams() {
let sc = c1("ep_recurrent_c1", ep_recurrent(Some(1)));
let expected = client_lines(&sync_run(&sc));
let live = async_run(&sc);
assert_eq!(
client_lines(&live),
expected,
"the async router changed a stream"
);
assert!(count(&live, "fx launch DecodeFed") > 0, "never ran ahead");
assert_eq!(
count(&live, "consumed again"),
0,
"recurrent state was reused"
);
assert!(fed_rows_per_launch(&live).iter().all(|&n| n == 1));
}
#[test]
fn the_plain_lanes_keep_their_streams_and_never_feed_two_rows() {
for name in [
"plain_decode",
"chunked_prefill",
"mixed_prefill",
"batched_prefill_waves",
"batched_mixed",
"preempt_requeue",
"spill_swap_out_in",
"request_timeout",
"slai_policy",
"host_logits_paths",
] {
let mut sc = scenarios::all()
.into_iter()
.find(|s| s.name == name)
.unwrap_or_else(|| panic!("no scenario {name}"));
sc.cfg = ModelCfg {
ep: true,
has_ssm_layers: true,
recurrent_fed_rows: Some(1),
..sc.cfg
};
let expected = sync_run(&sc);
let live = async_run(&sc);
assert_eq!(client_lines(&live), client_lines(&expected), "{name}");
assert_eq!(
count(&expected, "consumed again"),
0,
"{name} (sync):\n{}",
around(&expected, "consumed again")
);
assert_eq!(
count(&live, "consumed again"),
0,
"{name}:\n{}",
around(&live, "consumed again")
);
assert!(
fed_rows_per_launch(&live).iter().all(|&n| n == 1),
"{name} fed more than one row"
);
}
}
#[test]
fn the_same_model_under_redo_never_runs_ahead() {
let live = async_run(&c1("ep_recurrent_redo", ep_recurrent(None)));
assert_eq!(count(&live, "fx launch DecodeFed"), 0);
}
#[test]
fn the_recurrent_oracle_flags_a_position_consumed_twice() {
let model = RecordingModel::new(ep_recurrent(Some(1)));
let mut seq = SequenceState::host_only(0);
seq.session_hash = 7;
assert!(model.recurrent_consume(&seq, 0, 5));
assert!(model.recurrent_consume(&seq, 5, 1));
assert!(
!model.recurrent_consume(&seq, 5, 1),
"a re-run went unnoticed"
);
assert!(
!model.recurrent_consume(&seq, 6, 1),
"corruption must persist"
);
assert_eq!(model.recurrent_out(false, 42), GARBAGE);
assert_eq!(model.take_trace().len(), 1);
}
#[test]
fn the_c1_comparison_fails_when_the_over_run_discard_is_off() {
let sc = c1("ep_recurrent_c1_control", ep_recurrent(Some(1)));
let expected = client_lines(&sync_run(&sc));
let mut control = sc.clone();
control.opts.pipeline_faults = crate::scheduler::PipelineFaults { keep_overrun: true };
let live = async_run(&control);
assert!(count(&live, "fx launch DecodeFed") > 0);
assert_ne!(client_lines(&live), expected);
}
#[test]
fn armed_device_argmax_steps_keep_the_synchronous_streams() {
let cfg = ModelCfg {
device_argmax: true,
..ep_recurrent(Some(1))
};
let sc = c1("ep_recurrent_c1_device_argmax", cfg);
let expected = client_lines(&sync_run(&sc));
let live = async_run(&sc);
assert_eq!(client_lines(&live), expected);
assert!(
count(&live, "device_argmax_to_host") > 0,
"no step was armed"
);
assert_eq!(
count(&live, "argmax_batch_to_feed"),
0,
"an armed run still ran the argmax over the logits"
);
assert_eq!(count(&live, "consumed again"), 0);
}