use std::collections::{HashMap, HashSet, VecDeque};
use std::io::BufRead;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize)]
pub struct TraceRecord {
pub layer_idx: usize,
pub token_idx: usize,
pub selected_ids: Vec<usize>,
#[serde(default)]
pub gate_weights: Vec<f32>,
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
#[derive(Debug)]
pub struct TraceReadError {
pub line_no: usize,
pub message: String,
}
impl std::fmt::Display for TraceReadError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "line {}: {}", self.line_no, self.message)
}
}
impl std::error::Error for TraceReadError {}
pub fn read_trace<R: BufRead>(reader: R) -> Result<Vec<TraceRecord>, TraceReadError> {
let mut records = Vec::new();
for (i, line) in reader.lines().enumerate() {
let line_no = i + 1;
let line = line.map_err(|e| TraceReadError {
line_no,
message: format!("I/O error: {e}"),
})?;
let trimmed = line.trim();
if trimmed.is_empty() {
continue;
}
let record: TraceRecord = serde_json::from_str(trimmed).map_err(|e| TraceReadError {
line_no,
message: format!("JSON parse error: {e}"),
})?;
records.push(record);
}
Ok(records)
}
pub fn group_by_layer(records: Vec<TraceRecord>) -> Vec<(usize, Vec<TraceRecord>)> {
let mut by_layer: HashMap<usize, Vec<TraceRecord>> = HashMap::new();
for r in records {
by_layer.entry(r.layer_idx).or_default().push(r);
}
let mut layers: Vec<(usize, Vec<TraceRecord>)> = by_layer.into_iter().collect();
for (_, recs) in layers.iter_mut() {
recs.sort_by_key(|r| r.token_idx);
}
layers.sort_by_key(|(layer_idx, _)| *layer_idx);
layers
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AccessOutcome {
Hit,
Miss,
}
pub trait AdmissionPolicy {
fn name(&self) -> &'static str;
fn begin_token(&mut self);
fn access(&mut self, expert_id: usize) -> AccessOutcome;
fn evictions(&self) -> usize;
}
pub struct LruPolicy {
slot_owner: Vec<Option<usize>>,
expert_to_slot: HashMap<usize, usize>,
slot_touched: Vec<bool>,
lru: VecDeque<usize>,
evictions: usize,
}
impl LruPolicy {
pub fn new(capacity: usize) -> Self {
assert!(capacity > 0, "LruPolicy requires capacity > 0");
Self {
slot_owner: vec![None; capacity],
expert_to_slot: HashMap::with_capacity(capacity),
slot_touched: vec![false; capacity],
lru: (0..capacity).collect(),
evictions: 0,
}
}
fn touch(&mut self, slot: usize) {
self.slot_touched[slot] = true;
if let Some(pos) = self.lru.iter().position(|&s| s == slot) {
self.lru.remove(pos);
}
self.lru.push_back(slot);
}
fn pick_eviction_slot(&mut self) -> usize {
let pos = self.lru.iter().position(|&s| !self.slot_touched[s]).expect(
"no untouched slot available for eviction — capacity must be >= the number of \
distinct experts one token requests (mirrors moe_expert_cache_num_slots's \
num_slots >= top_k invariant); this indicates a misconfigured \
--num-slots/--top-k pair, not a trace problem",
);
self.lru
.remove(pos)
.expect("pos was just found via position() on this same self.lru")
}
}
impl AdmissionPolicy for LruPolicy {
fn name(&self) -> &'static str {
"lru (baseline)"
}
fn begin_token(&mut self) {
self.slot_touched.iter_mut().for_each(|t| *t = false);
}
fn access(&mut self, expert_id: usize) -> AccessOutcome {
if let Some(&slot) = self.expert_to_slot.get(&expert_id) {
self.touch(slot);
return AccessOutcome::Hit;
}
let slot = self.pick_eviction_slot();
if let Some(old_owner) = self.slot_owner[slot].take() {
self.expert_to_slot.remove(&old_owner);
self.evictions += 1;
}
self.slot_owner[slot] = Some(expert_id);
self.expert_to_slot.insert(expert_id, slot);
self.touch(slot);
AccessOutcome::Miss
}
fn evictions(&self) -> usize {
self.evictions
}
}
pub struct ArcPolicy {
capacity: usize,
p: usize,
t1: VecDeque<usize>,
t2: VecDeque<usize>,
b1: VecDeque<usize>,
b2: VecDeque<usize>,
evictions: usize,
protected_this_token: HashSet<usize>,
}
impl ArcPolicy {
pub fn new(capacity: usize) -> Self {
assert!(capacity > 0, "ArcPolicy requires capacity > 0");
Self {
capacity,
p: 0,
t1: VecDeque::new(),
t2: VecDeque::new(),
b1: VecDeque::new(),
b2: VecDeque::new(),
evictions: 0,
protected_this_token: HashSet::new(),
}
}
#[cfg(test)]
fn resident_len(&self) -> usize {
self.t1.len() + self.t2.len()
}
fn remove_from(list: &mut VecDeque<usize>, id: usize) -> bool {
if let Some(pos) = list.iter().position(|&x| x == id) {
list.remove(pos);
true
} else {
false
}
}
fn evict_unprotected_from(
list: &mut VecDeque<usize>,
protected: &HashSet<usize>,
) -> Option<usize> {
let pos = list.iter().position(|id| !protected.contains(id))?;
list.remove(pos)
}
fn replace(&mut self, triggered_by_b2_hit: bool) {
let evict_from_t1 = !self.t1.is_empty()
&& (self.t1.len() > self.p || (triggered_by_b2_hit && self.t1.len() == self.p));
let victim = if evict_from_t1 {
Self::evict_unprotected_from(&mut self.t1, &self.protected_this_token)
.map(|y| (y, true))
.or_else(|| {
Self::evict_unprotected_from(&mut self.t2, &self.protected_this_token)
.map(|y| (y, false))
})
} else {
Self::evict_unprotected_from(&mut self.t2, &self.protected_this_token)
.map(|y| (y, false))
.or_else(|| {
Self::evict_unprotected_from(&mut self.t1, &self.protected_this_token)
.map(|y| (y, true))
})
};
match victim {
Some((y, from_t1)) => {
self.b2_or_b1_push(from_t1, y);
self.evictions += 1;
}
None => panic!(
"ArcPolicy::replace: no unprotected resident available for eviction — \
indicates capacity < top_k (should have been rejected by \
run_simulation) or a bug in protected_this_token bookkeeping"
),
}
}
fn b2_or_b1_push(&mut self, from_t1: bool, id: usize) {
if from_t1 {
self.b1.push_back(id);
} else {
self.b2.push_back(id);
}
}
}
impl AdmissionPolicy for ArcPolicy {
fn name(&self) -> &'static str {
"arc"
}
fn begin_token(&mut self) {
self.protected_this_token.clear();
}
fn access(&mut self, x: usize) -> AccessOutcome {
let c = self.capacity;
self.protected_this_token.insert(x);
if Self::remove_from(&mut self.t1, x) {
self.t2.push_back(x);
return AccessOutcome::Hit;
}
if self.t2.contains(&x) {
Self::remove_from(&mut self.t2, x);
self.t2.push_back(x);
return AccessOutcome::Hit;
}
if self.b1.contains(&x) {
let ratio = (self.b2.len() / self.b1.len().max(1)).max(1);
self.p = (self.p + ratio).min(c);
self.replace(false);
Self::remove_from(&mut self.b1, x);
self.t2.push_back(x);
return AccessOutcome::Miss;
}
if self.b2.contains(&x) {
let ratio = (self.b1.len() / self.b2.len().max(1)).max(1);
self.p = self.p.saturating_sub(ratio);
self.replace(true);
Self::remove_from(&mut self.b2, x);
self.t2.push_back(x);
return AccessOutcome::Miss;
}
let t1_b1 = self.t1.len() + self.b1.len();
if t1_b1 == c {
if self.t1.len() < c {
self.b1.pop_front();
self.replace(false);
} else {
match Self::evict_unprotected_from(&mut self.t1, &self.protected_this_token) {
Some(_) => self.evictions += 1,
None => panic!(
"ArcPolicy Case IV: t1 full at capacity with b1 empty, but every \
resident id is protected this token — indicates capacity < \
top_k (should have been rejected by run_simulation)"
),
}
}
} else if t1_b1 < c {
let total = self.t1.len() + self.t2.len() + self.b1.len() + self.b2.len();
if total >= c {
if total == 2 * c {
self.b2.pop_front();
}
self.replace(false);
}
}
self.t1.push_back(x);
AccessOutcome::Miss
}
fn evictions(&self) -> usize {
self.evictions
}
}
pub struct FreqAdmissionPolicy {
capacity: usize,
window: usize,
resident: HashSet<usize>,
lru: VecDeque<usize>,
last_seen_pos: HashMap<usize, usize>,
pos: usize,
evictions: usize,
}
impl FreqAdmissionPolicy {
pub fn new(capacity: usize, window: usize) -> Self {
assert!(capacity > 0, "FreqAdmissionPolicy requires capacity > 0");
assert!(window > 0, "FreqAdmissionPolicy requires window > 0");
Self {
capacity,
window,
resident: HashSet::with_capacity(capacity),
lru: VecDeque::new(),
last_seen_pos: HashMap::new(),
pos: 0,
evictions: 0,
}
}
fn touch_lru(&mut self, id: usize) {
if let Some(p) = self.lru.iter().position(|&x| x == id) {
self.lru.remove(p);
}
self.lru.push_back(id);
}
fn admit(&mut self, id: usize) {
if self.resident.len() >= self.capacity
&& let Some(victim) = self.lru.pop_front()
{
self.resident.remove(&victim);
self.evictions += 1;
}
self.resident.insert(id);
self.lru.push_back(id);
}
}
impl AdmissionPolicy for FreqAdmissionPolicy {
fn name(&self) -> &'static str {
"freq-admission"
}
fn begin_token(&mut self) {}
fn access(&mut self, id: usize) -> AccessOutcome {
self.pos += 1;
if self.resident.contains(&id) {
self.touch_lru(id);
return AccessOutcome::Hit;
}
let eligible = self
.last_seen_pos
.get(&id)
.is_some_and(|&prev| self.pos - prev < self.window);
self.last_seen_pos.insert(id, self.pos);
if eligible {
self.admit(id);
}
AccessOutcome::Miss
}
fn evictions(&self) -> usize {
self.evictions
}
}
#[derive(Debug, Clone)]
pub enum PolicySpec {
Lru,
Arc,
FreqAdmission { window: usize },
}
impl PolicySpec {
pub fn label(&self) -> String {
match self {
PolicySpec::Lru => "lru (baseline)".to_string(),
PolicySpec::Arc => "arc".to_string(),
PolicySpec::FreqAdmission { window } => format!("freq-admission(w={window})"),
}
}
pub fn build(&self, capacity: usize) -> Box<dyn AdmissionPolicy> {
match self {
PolicySpec::Lru => Box::new(LruPolicy::new(capacity)),
PolicySpec::Arc => Box::new(ArcPolicy::new(capacity)),
PolicySpec::FreqAdmission { window } => {
Box::new(FreqAdmissionPolicy::new(capacity, *window))
}
}
}
pub fn is_baseline(&self) -> bool {
matches!(self, PolicySpec::Lru)
}
}
#[derive(Debug, Clone, Copy, Default, Serialize)]
pub struct LayerStats {
pub hits: usize,
pub misses: usize,
pub evictions: usize,
}
impl LayerStats {
pub fn total(&self) -> usize {
self.hits + self.misses
}
pub fn hit_rate(&self) -> f64 {
if self.total() == 0 {
0.0
} else {
self.hits as f64 / self.total() as f64
}
}
}
pub fn simulate_layer(records: &[TraceRecord], policy: &mut dyn AdmissionPolicy) -> LayerStats {
let mut stats = LayerStats::default();
for record in records {
policy.begin_token();
for &id in &record.selected_ids {
match policy.access(id) {
AccessOutcome::Hit => stats.hits += 1,
AccessOutcome::Miss => stats.misses += 1,
}
}
}
stats.evictions = policy.evictions();
stats
}
#[derive(Debug, Clone, Copy)]
pub struct SimConfig {
pub num_slots: usize,
pub top_k: usize,
}
#[derive(Debug, Clone, Copy, Serialize)]
pub struct LayerRow {
pub layer_idx: usize,
pub stats: LayerStats,
}
#[derive(Debug, Clone, Serialize)]
pub struct PolicyReport {
pub policy: String,
pub overall: LayerStats,
pub per_layer: Vec<LayerRow>,
pub delta_vs_baseline_pp: f64,
}
pub fn run_simulation(
layers: &[(usize, Vec<TraceRecord>)],
cfg: &SimConfig,
policies: &[PolicySpec],
) -> Result<Vec<PolicyReport>, String> {
if cfg.num_slots == 0 {
return Err(
"num_slots must be > 0 — a zero-capacity cache cannot hold any \
expert"
.to_string(),
);
}
if cfg.top_k == 0 {
return Err(
"top_k must be > 0 — a token that selects zero experts is not a \
valid MoE routing trace"
.to_string(),
);
}
if cfg.num_slots < cfg.top_k {
return Err(format!(
"num_slots ({}) must be >= top_k ({}) — mirrors moe_expert_cache_num_slots's \
validated invariant; a smaller cache cannot serve one token's routed-expert set",
cfg.num_slots, cfg.top_k
));
}
for spec in policies {
if let PolicySpec::FreqAdmission { window } = spec
&& *window == 0
{
return Err(
"freq-admission window must be > 0 — a zero-width sliding window can \
never observe a repeat touch"
.to_string(),
);
}
}
if !policies.iter().any(PolicySpec::is_baseline) {
return Err("policies must include PolicySpec::Lru as the baseline".to_string());
}
for (layer_idx, records) in layers {
for r in records {
if r.selected_ids.len() > cfg.top_k {
return Err(format!(
"layer {layer_idx} token {}: selected_ids has {} entries, exceeds \
--top-k={}",
r.token_idx,
r.selected_ids.len(),
cfg.top_k
));
}
}
}
let mut reports = Vec::with_capacity(policies.len());
let mut baseline_hit_rate = 0.0;
for spec in policies {
let mut overall = LayerStats::default();
let mut per_layer = Vec::with_capacity(layers.len());
for (layer_idx, records) in layers {
let mut policy = spec.build(cfg.num_slots);
let stats = simulate_layer(records, policy.as_mut());
overall.hits += stats.hits;
overall.misses += stats.misses;
overall.evictions += stats.evictions;
per_layer.push(LayerRow {
layer_idx: *layer_idx,
stats,
});
}
if spec.is_baseline() {
baseline_hit_rate = overall.hit_rate();
}
reports.push(PolicyReport {
policy: spec.label(),
overall,
per_layer,
delta_vs_baseline_pp: 0.0,
});
}
for report in reports.iter_mut() {
report.delta_vs_baseline_pp = (report.overall.hit_rate() - baseline_hit_rate) * 100.0;
}
Ok(reports)
}
pub fn format_table(reports: &[PolicyReport]) -> String {
use std::fmt::Write as _;
let mut out = String::new();
let _ = writeln!(
out,
"NOTE: hits/misses/evictions are per single LOGICAL (layer, tensor) cache. \
Production runs TWO such caches per MoE layer (gate_up + down) replaying the \
same selected-expert sequence into both — physical event totals are these \
figures x2; hit_rate/delta_pp are unaffected (see LayerStats doc comment)."
);
let _ = writeln!(out, "=== overall (all layers) ===");
let _ = writeln!(
out,
"{:<24} {:>10} {:>8} {:>8} {:>10} {:>10}",
"policy", "hit_rate", "hits", "misses", "evictions", "delta_pp"
);
for r in reports {
let _ = writeln!(
out,
"{:<24} {:>9.2}% {:>8} {:>8} {:>10} {:>+10.2}",
r.policy,
r.overall.hit_rate() * 100.0,
r.overall.hits,
r.overall.misses,
r.overall.evictions,
r.delta_vs_baseline_pp,
);
}
let _ = writeln!(out);
let _ = writeln!(out, "=== per-layer ===");
let _ = writeln!(
out,
"{:<24} {:>8} {:>10} {:>8} {:>8} {:>10}",
"policy", "layer", "hit_rate", "hits", "misses", "evictions"
);
for r in reports {
for row in &r.per_layer {
let _ = writeln!(
out,
"{:<24} {:>8} {:>9.2}% {:>8} {:>8} {:>10}",
r.policy,
row.layer_idx,
row.stats.hit_rate() * 100.0,
row.stats.hits,
row.stats.misses,
row.stats.evictions,
);
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
fn record(layer_idx: usize, token_idx: usize, selected_ids: &[usize]) -> TraceRecord {
TraceRecord {
layer_idx,
token_idx,
selected_ids: selected_ids.to_vec(),
gate_weights: Vec::new(),
extra: HashMap::new(),
}
}
fn dq(v: &VecDeque<usize>) -> Vec<usize> {
v.iter().copied().collect()
}
#[test]
fn reads_jsonl_and_tolerates_extra_fields() {
let jsonl = "\
{\"layer_idx\": 0, \"token_idx\": 0, \"selected_ids\": [1, 2], \"gate_weights\": [0.5, 0.5]}
{\"layer_idx\": 1, \"token_idx\": 0, \"selected_ids\": [3], \"gate_weights\": [1.0], \"extra_field\": \"ignored\", \"nested\": {\"a\": 1}}
";
let records =
read_trace(jsonl.as_bytes()).expect("valid trace parses (blank line skipped)");
assert_eq!(records.len(), 2);
assert_eq!(records[0].layer_idx, 0);
assert_eq!(records[0].selected_ids, vec![1, 2]);
assert_eq!(records[1].layer_idx, 1);
assert_eq!(records[1].selected_ids, vec![3]);
assert!(records[1].extra.contains_key("extra_field"));
assert!(records[1].extra.contains_key("nested"));
}
#[test]
fn malformed_line_errors_with_line_number() {
let jsonl = "{\"layer_idx\": 0, \"token_idx\": 0, \"selected_ids\": [1]}\nnot json\n";
let err = read_trace(jsonl.as_bytes()).expect_err("malformed second line must error");
assert_eq!(err.line_no, 2);
}
#[test]
fn group_by_layer_sorts_within_layer_regardless_of_file_order() {
let records = vec![
record(0, 2, &[1]),
record(1, 0, &[9]),
record(0, 0, &[1]),
record(1, 1, &[9]),
record(0, 1, &[1]),
];
let layers = group_by_layer(records);
assert_eq!(layers.len(), 2);
assert_eq!(layers[0].0, 0);
let token_order: Vec<usize> = layers[0].1.iter().map(|r| r.token_idx).collect();
assert_eq!(token_order, vec![0, 1, 2]);
assert_eq!(layers[1].0, 1);
let token_order: Vec<usize> = layers[1].1.iter().map(|r| r.token_idx).collect();
assert_eq!(token_order, vec![0, 1]);
}
#[test]
fn lru_hand_computed_hit_miss_sequence_and_within_token_touch_guard() {
let mut policy = LruPolicy::new(2);
let mut outcomes = Vec::new();
policy.begin_token();
outcomes.push(policy.access(100)); outcomes.push(policy.access(200));
policy.begin_token();
outcomes.push(policy.access(100)); outcomes.push(policy.access(300));
policy.begin_token();
outcomes.push(policy.access(200)); outcomes.push(policy.access(300));
use AccessOutcome::{Hit, Miss};
assert_eq!(
outcomes,
vec![Miss, Miss, Hit, Miss, Miss, Hit],
"hand-computed LRU hit/miss sequence mismatch"
);
assert_eq!(
policy.evictions(),
2,
"expected exactly 2 evictions (B at token 1, A at token 2)"
);
}
#[test]
fn simulate_layer_reproduces_hand_computed_lru_sequence() {
let records = vec![
record(0, 0, &[100, 200]),
record(0, 1, &[100, 300]),
record(0, 2, &[200, 300]),
];
let mut policy = LruPolicy::new(2);
let stats = simulate_layer(&records, &mut policy);
assert_eq!(stats.hits, 2);
assert_eq!(stats.misses, 4);
assert_eq!(stats.evictions, 2);
assert!((stats.hit_rate() - (2.0 / 6.0)).abs() < 1e-9);
}
#[test]
fn arc_ties_lru_on_cache_resident_cyclic_pattern() {
let capacity = 4;
let records: Vec<TraceRecord> = (0..50)
.map(|token_idx| record(0, token_idx, &[token_idx % capacity]))
.collect();
let mut lru = LruPolicy::new(capacity);
let lru_stats = simulate_layer(&records, &mut lru);
let mut arc = ArcPolicy::new(capacity);
let arc_stats = simulate_layer(&records, &mut arc);
assert_eq!(lru_stats.evictions, 0);
assert_eq!(arc_stats.evictions, 0);
assert_eq!(lru_stats.hits, arc_stats.hits);
assert_eq!(lru_stats.misses, arc_stats.misses);
assert!((lru_stats.hit_rate() - arc_stats.hit_rate()).abs() < 1e-9);
assert!(lru_stats.hit_rate() > 0.8, "got {}", lru_stats.hit_rate());
}
#[test]
fn arc_beats_lru_on_hot_set_plus_scan_pollution() {
let capacity = 4;
let hot_set = [0usize, 1usize];
let scan_size = 8;
let rounds = 30;
let mut records = Vec::new();
let mut token_idx = 0;
let mut next_scan_id = 1000usize;
for _round in 0..rounds {
for &hot_id in &hot_set {
records.push(record(0, token_idx, &[hot_id]));
token_idx += 1;
}
for &hot_id in &hot_set {
records.push(record(0, token_idx, &[hot_id]));
token_idx += 1;
}
for _ in 0..scan_size {
records.push(record(0, token_idx, &[next_scan_id]));
next_scan_id += 1;
token_idx += 1;
}
}
let mut lru = LruPolicy::new(capacity);
let lru_stats = simulate_layer(&records, &mut lru);
let mut arc = ArcPolicy::new(capacity);
let arc_stats = simulate_layer(&records, &mut arc);
assert!(
arc_stats.hit_rate() > lru_stats.hit_rate() + 0.02,
"expected ARC to beat LRU by >2pp on hot-set+scan trace: lru={:.4} arc={:.4}",
lru_stats.hit_rate(),
arc_stats.hit_rate()
);
}
#[test]
fn arc_never_exceeds_capacity() {
let capacity = 3;
let mut arc = ArcPolicy::new(capacity);
let ids = [
1, 2, 3, 4, 1, 5, 2, 6, 7, 1, 8, 9, 2, 10, 1, 2, 3, 11, 12, 13,
];
for &id in &ids {
arc.begin_token();
arc.access(id);
assert!(
arc.resident_len() <= capacity,
"resident count exceeded capacity after accessing {id}"
);
}
}
#[test]
fn arc_never_evicts_a_same_token_touched_id() {
let capacity = 2;
let mut arc = ArcPolicy::new(capacity);
let (x, y, a, b) = (10usize, 20usize, 30usize, 40usize);
use AccessOutcome::{Hit, Miss};
arc.begin_token();
assert_eq!(arc.access(x), Miss);
assert_eq!(arc.access(y), Miss);
assert_eq!(dq(&arc.t1), vec![x, y]);
arc.begin_token();
assert_eq!(arc.access(x), Hit);
assert_eq!(arc.access(y), Hit);
assert!(
arc.t1.is_empty(),
"both promoted out of t1 by their 2nd touch"
);
assert_eq!(
dq(&arc.t2),
vec![x, y],
"both promoted to t2 (frequency-protected)"
);
arc.begin_token();
assert_eq!(arc.access(a), Miss);
assert_eq!(arc.access(b), Miss);
assert_eq!(
dq(&arc.t1),
vec![a, b],
"A must survive B's SAME-token admission — production cannot evict a slot \
resolved earlier this token"
);
assert!(arc.t2.is_empty());
assert_eq!(arc.evictions(), 2, "X and Y evicted from t2, not A");
arc.begin_token();
assert_eq!(arc.access(a), Hit);
assert_eq!(arc.access(b), Hit);
}
#[test]
fn arc_ghost_hit_adaptation_hand_computed() {
let capacity = 2;
let mut arc = ArcPolicy::new(capacity);
use AccessOutcome::{Hit, Miss};
arc.begin_token();
assert_eq!(arc.access(1), Miss);
assert_eq!(dq(&arc.t1), vec![1]);
arc.begin_token();
assert_eq!(arc.access(2), Miss);
assert_eq!(dq(&arc.t1), vec![1, 2]);
arc.begin_token();
assert_eq!(arc.access(1), Hit);
assert_eq!(dq(&arc.t1), vec![2]);
assert_eq!(dq(&arc.t2), vec![1]);
arc.begin_token();
assert_eq!(arc.access(3), Miss);
assert_eq!(dq(&arc.t1), vec![3]);
assert_eq!(dq(&arc.t2), vec![1]);
assert_eq!(dq(&arc.b1), vec![2]);
assert_eq!(arc.evictions(), 1);
assert_eq!(arc.p, 0);
arc.begin_token();
assert_eq!(arc.access(1), Hit);
arc.begin_token();
assert_eq!(arc.access(2), Miss);
assert_eq!(arc.p, 1, "B1 ghost hit must increase p toward t1/recency");
assert!(arc.b1.is_empty(), "2 must leave b1 once re-admitted");
assert_eq!(
dq(&arc.t2),
vec![2],
"2 re-admitted into t2, not t1 (ARC Case II)"
);
assert_eq!(dq(&arc.t1), vec![3], "t1 untouched by this Case II call");
assert_eq!(
dq(&arc.b2),
vec![1],
"evicted victim (1, from t2) becomes a b2 ghost"
);
assert_eq!(arc.evictions(), 2);
arc.begin_token();
assert_eq!(arc.access(1), Miss);
assert_eq!(arc.p, 0, "B2 ghost hit must decrease p toward t2/frequency");
assert!(arc.b2.is_empty(), "1 must leave b2 once re-admitted");
assert_eq!(dq(&arc.t2), vec![2, 1], "1 re-admitted into t2");
assert!(
arc.t1.is_empty(),
"t1's only resident (3) was the Case III victim"
);
assert_eq!(
dq(&arc.b1),
vec![3],
"evicted victim (3, from t1) becomes a b1 ghost"
);
assert_eq!(arc.evictions(), 3);
}
#[test]
fn freq_admission_admits_on_second_touch() {
let mut policy = FreqAdmissionPolicy::new(4, 100);
use AccessOutcome::{Hit, Miss};
assert_eq!(policy.access(42), Miss); assert_eq!(policy.access(42), Miss); assert_eq!(policy.access(42), Hit); }
#[test]
fn freq_admission_window_expiry_resets_eligibility() {
let mut policy = FreqAdmissionPolicy::new(4, 2);
use AccessOutcome::{Hit, Miss};
assert_eq!(policy.access(1), Miss); assert_eq!(policy.access(2), Miss); assert_eq!(policy.access(3), Miss); assert_eq!(policy.access(1), Miss);
assert_eq!(policy.access(1), Miss);
assert_eq!(policy.access(1), Hit);
}
#[test]
fn freq_admission_gap_equal_to_window_is_not_eligible() {
let mut policy = FreqAdmissionPolicy::new(4, 2);
use AccessOutcome::{Hit, Miss};
assert_eq!(policy.access(1), Miss); assert_eq!(policy.access(2), Miss); assert_eq!(policy.access(1), Miss);
assert_eq!(policy.access(1), Miss);
assert_eq!(policy.access(1), Hit);
}
#[test]
fn freq_admission_never_evicts_a_same_token_touched_id_without_an_explicit_guard() {
let capacity = 2;
let window = 100;
let records = vec![
record(0, 0, &[100]), record(0, 1, &[200]), record(0, 2, &[100]), record(0, 3, &[200]), record(0, 4, &[300]), record(0, 5, &[400]), record(0, 6, &[300, 400]), ];
let mut policy = FreqAdmissionPolicy::new(capacity, window);
for r in &records {
policy.begin_token();
for &id in &r.selected_ids {
policy.access(id);
}
}
assert!(
policy.resident.contains(&300) && policy.resident.contains(&400),
"A (300) and B (400), both touched in the SAME final token, must both \
survive that token"
);
assert_eq!(policy.evictions(), 2, "P and Q evicted, not A or B");
}
#[test]
fn freq_admission_evicts_lru_among_admitted() {
let mut policy = FreqAdmissionPolicy::new(2, 100);
for id in [1, 2, 1, 2] {
policy.access(id);
}
assert_eq!(policy.evictions(), 0);
policy.access(3);
policy.access(3);
assert_eq!(policy.evictions(), 1);
assert_eq!(policy.access(1), AccessOutcome::Miss);
}
#[test]
fn run_simulation_rejects_num_slots_below_top_k() {
let layers = vec![(0usize, vec![record(0, 0, &[1, 2, 3])])];
let cfg = SimConfig {
num_slots: 2,
top_k: 3,
};
let err = run_simulation(&layers, &cfg, &[PolicySpec::Lru]).unwrap_err();
assert!(err.contains("num_slots"), "unexpected error: {err}");
}
#[test]
fn run_simulation_rejects_zero_num_slots() {
let layers = vec![(0usize, vec![record(0, 0, &[])])];
let cfg = SimConfig {
num_slots: 0,
top_k: 0,
};
let err = run_simulation(&layers, &cfg, &[PolicySpec::Lru]).unwrap_err();
assert!(err.contains("num_slots"), "unexpected error: {err}");
}
#[test]
fn run_simulation_rejects_zero_top_k() {
let layers = vec![(0usize, vec![record(0, 0, &[])])];
let cfg = SimConfig {
num_slots: 4,
top_k: 0,
};
let err = run_simulation(&layers, &cfg, &[PolicySpec::Lru]).unwrap_err();
assert!(err.contains("top_k"), "unexpected error: {err}");
}
#[test]
fn run_simulation_rejects_zero_num_slots_and_top_k_together() {
let layers = vec![(0usize, vec![record(0, 0, &[])])];
let cfg = SimConfig {
num_slots: 0,
top_k: 0,
};
let err = run_simulation(&layers, &cfg, &[PolicySpec::Lru]).unwrap_err();
assert!(err.contains("num_slots"), "unexpected error: {err}");
}
#[test]
fn run_simulation_rejects_zero_freq_admission_window() {
let layers = vec![(0usize, vec![record(0, 0, &[1])])];
let cfg = SimConfig {
num_slots: 4,
top_k: 1,
};
let err = run_simulation(
&layers,
&cfg,
&[PolicySpec::Lru, PolicySpec::FreqAdmission { window: 0 }],
)
.unwrap_err();
assert!(err.contains("window"), "unexpected error: {err}");
}
#[test]
fn overall_stats_are_per_single_logical_cache_not_physical_two_cache_totals() {
let layers = vec![(0usize, vec![record(0, 0, &[42])])];
let cfg = SimConfig {
num_slots: 1,
top_k: 1,
};
let reports = run_simulation(&layers, &cfg, &[PolicySpec::Lru]).unwrap();
assert_eq!(
reports[0].overall.misses, 1,
"logical single-cache count, not the physical x2 production performs"
);
assert_eq!(reports[0].overall.hits, 0);
assert_eq!(
reports[0].overall.evictions, 0,
"first-ever access into an empty slot pool is never an eviction"
);
let layers2 = vec![(0usize, vec![record(0, 0, &[1]), record(0, 1, &[2])])];
let reports2 = run_simulation(&layers2, &cfg, &[PolicySpec::Lru]).unwrap();
assert_eq!(reports2[0].overall.evictions, 1);
}
#[test]
fn run_simulation_rejects_missing_baseline() {
let layers = vec![(0usize, vec![record(0, 0, &[1])])];
let cfg = SimConfig {
num_slots: 4,
top_k: 1,
};
let err = run_simulation(&layers, &cfg, &[PolicySpec::Arc]).unwrap_err();
assert!(err.contains("baseline"), "unexpected error: {err}");
}
#[test]
fn run_simulation_rejects_selected_ids_exceeding_top_k() {
let layers = vec![(0usize, vec![record(0, 0, &[1, 2, 3])])];
let cfg = SimConfig {
num_slots: 4,
top_k: 2,
};
let err = run_simulation(&layers, &cfg, &[PolicySpec::Lru]).unwrap_err();
assert!(err.contains("exceeds --top-k"), "unexpected error: {err}");
}
#[test]
fn run_simulation_delta_vs_baseline_is_zero_for_baseline_itself() {
let layers = vec![(0usize, vec![record(0, 0, &[1, 2])])];
let cfg = SimConfig {
num_slots: 4,
top_k: 2,
};
let reports = run_simulation(&layers, &cfg, &[PolicySpec::Lru]).unwrap();
assert_eq!(reports.len(), 1);
assert!((reports[0].delta_vs_baseline_pp).abs() < 1e-9);
}
#[test]
fn format_table_includes_every_policy_and_layer() {
let layers = vec![
(0usize, vec![record(0, 0, &[1, 2])]),
(1usize, vec![record(1, 0, &[3])]),
];
let cfg = SimConfig {
num_slots: 4,
top_k: 2,
};
let reports = run_simulation(&layers, &cfg, &[PolicySpec::Lru, PolicySpec::Arc]).unwrap();
let table = format_table(&reports);
assert!(table.contains("lru (baseline)"));
assert!(table.contains("arc"));
assert!(table.contains("layer"));
}
}