const COHORT_BAND: f64 = 0.15;
const DOMINANCE_MARGIN: f64 = 0.10;
const TRUST_WINDOW_CAP: usize = 5;
const MAX_SPEED_RATIO: f64 = 64.0;
const BATCH_COUNTS_WINDOW_CAP: usize = 10;
const GROWTH_REARM_STABLE: usize = 5;
const GROWTH_STEP_CAP: f64 = 2.0;
const WARMUP_GROWTH_MARGIN: f64 = GROWTH_STEP_CAP;
#[derive(Debug, Clone)]
struct RingBuffer {
samples: Vec<f64>,
capacity: usize,
}
impl RingBuffer {
fn new(capacity: usize) -> Self {
Self { samples: Vec::with_capacity(capacity), capacity }
}
fn push(&mut self, value: f64) {
if self.samples.len() >= self.capacity {
self.samples.remove(0);
}
self.samples.push(value);
}
fn mean(&self) -> f64 {
if self.samples.is_empty() {
return 0.0;
}
self.samples.iter().sum::<f64>() / self.samples.len() as f64
}
fn is_empty(&self) -> bool {
self.samples.is_empty()
}
fn clear(&mut self) {
self.samples.clear();
}
}
#[derive(
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord,
serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum Phase {
Probe,
Warmup,
Stable,
Mature,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum AnchorVerdict {
Stable {
relax_up: bool,
},
SuppressGrowth,
NudgeDown {
factor: f64,
},
}
#[derive(Debug, Clone)]
pub struct WindowReport {
pub wall_ms: Vec<f64>,
pub steps: Vec<usize>,
pub delivered_ms: Vec<f64>,
pub delivered_batches: Vec<usize>,
pub fill_ms: Vec<f64>,
pub delivered_coherent: bool,
pub sync_ms: f64,
}
impl WindowReport {
pub fn select_feed(&self) -> (Vec<f64>, Vec<usize>) {
if !self.delivered_coherent {
return (self.wall_ms.clone(), self.steps.clone());
}
let mut ms = Vec::with_capacity(self.wall_ms.len());
let mut batches = Vec::with_capacity(self.wall_ms.len());
for r in 0..self.wall_ms.len() {
let has_sample =
self.delivered_batches[r] > 0 && self.delivered_ms[r] > 0.0;
if has_sample {
ms.push(self.delivered_ms[r]);
batches.push(self.delivered_batches[r]);
} else {
ms.push(self.wall_ms[r]);
batches.push(self.steps[r]);
}
}
(ms, batches)
}
}
pub struct ElChe {
world_size: usize,
anchor: usize,
batch_counts: Vec<usize>,
ms_per_batch_window: Vec<RingBuffer>,
consecutive_zero_reports: Vec<usize>,
batch_counts_window: std::collections::VecDeque<Vec<usize>>,
calibrated: bool,
overhead_target: f64,
min_anchor: usize,
max_anchor: usize,
max_total_batches: Option<usize>,
window_cap_binding: bool,
max_batch_diff: Option<usize>,
phase: Phase,
anchor_rank: Option<usize>,
calibration_count: u64,
pending_callback_slack_ms: Vec<f64>,
proposed_anchor: Option<ProposedAnchor>,
pending_window_fill_ms: Vec<f64>,
growth_enabled: bool,
consecutive_stable: usize,
window_growth_applicable: bool,
}
#[derive(Debug, Clone, Copy)]
enum ProposedAnchor {
Grow(usize),
}
impl ElChe {
pub fn new(world_size: usize, anchor: usize) -> Self {
assert!(world_size >= 2, "El Che requires at least 2 devices");
assert!(anchor >= 1, "anchor must be >= 1");
ElChe {
world_size,
anchor,
batch_counts: vec![anchor; world_size],
ms_per_batch_window: (0..world_size)
.map(|_| RingBuffer::new(TRUST_WINDOW_CAP))
.collect(),
consecutive_zero_reports: vec![0; world_size],
batch_counts_window: std::collections::VecDeque::with_capacity(
BATCH_COUNTS_WINDOW_CAP,
),
calibrated: false,
overhead_target: 0.05,
min_anchor: anchor,
max_anchor: 1000,
max_total_batches: None,
window_cap_binding: false,
max_batch_diff: None,
phase: Phase::Probe,
anchor_rank: None,
calibration_count: 0,
pending_callback_slack_ms: vec![0.0; world_size],
proposed_anchor: None,
pending_window_fill_ms: vec![0.0; world_size],
growth_enabled: true,
consecutive_stable: 0,
window_growth_applicable: true,
}
}
pub fn phase(&self) -> Phase {
self.phase
}
pub fn anchor_rank(&self) -> Option<usize> {
self.anchor_rank
}
pub fn to_state(&self) -> crate::distributed::ElCheState {
let smoothed_ms_per_batch: Vec<f64> = (0..self.world_size)
.map(|r| self.smoothed_ms(r))
.collect();
crate::distributed::ElCheState {
anchor: self.anchor,
anchor_rank: self.anchor_rank,
smoothed_ms_per_batch,
phase: self.phase,
calibration_count: self.calibration_count,
trend_history: None,
}
}
pub fn restore_from_state(
&mut self,
state: &crate::distributed::ElCheState,
) -> crate::tensor::Result<()> {
if state.smoothed_ms_per_batch.len() != self.world_size {
return Err(crate::tensor::TensorError::new(&format!(
"ElChe::restore_from_state: snapshot world_size {} != \
current world_size {}; resume must use the same world \
size as the saved run",
state.smoothed_ms_per_batch.len(),
self.world_size,
)));
}
self.anchor = state.anchor;
self.anchor_rank = state.anchor_rank;
self.phase = state.phase;
self.calibration_count = state.calibration_count;
for (rank, &smoothed) in state.smoothed_ms_per_batch.iter().enumerate() {
self.ms_per_batch_window[rank].clear();
if smoothed > 0.0 {
self.ms_per_batch_window[rank].push(smoothed);
}
}
self.calibrated = state
.smoothed_ms_per_batch
.iter()
.any(|&v| v > 0.0);
Ok(())
}
fn smoothed_ms(&self, rank: usize) -> f64 {
self.ms_per_batch_window
.get(rank)
.map(|w| w.mean())
.unwrap_or(0.0)
}
fn slow_cohort(&self) -> Vec<usize> {
let max_ms = (0..self.world_size)
.map(|r| self.smoothed_ms(r))
.fold(0.0_f64, f64::max);
if max_ms <= 0.0 {
return Vec::new();
}
let threshold = max_ms * (1.0 - COHORT_BAND);
(0..self.world_size)
.filter(|&r| self.smoothed_ms(r) >= threshold)
.collect()
}
fn elect_anchor(&self) -> Option<usize> {
let cohort = self.slow_cohort();
if cohort.is_empty() {
return None;
}
if cohort.len() == 1 {
return Some(cohort[0]);
}
if let Some(c) = self.anchor_rank {
if cohort.contains(&c) {
let cur = self.smoothed_ms(c);
let challenger = cohort
.iter()
.copied()
.filter(|&r| r != c)
.map(|r| (r, self.smoothed_ms(r)))
.max_by(|(_, a), (_, b)| {
a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)
});
if let Some((other, other_ms)) = challenger {
if other_ms > cur * (1.0 + DOMINANCE_MARGIN) {
return Some(other);
}
}
return Some(c);
}
}
cohort.into_iter().min()
}
fn slow_ms(&self) -> f64 {
self.anchor_rank
.map(|r| self.smoothed_ms(r))
.unwrap_or(0.0)
}
pub fn with_overhead_target(mut self, target: f64) -> Self {
self.overhead_target = target.clamp(0.01, 0.50);
self
}
pub fn with_window_growth_applicable(mut self, applicable: bool) -> Self {
self.window_growth_applicable = applicable;
self
}
pub fn with_max_anchor(mut self, max: usize) -> Self {
self.max_anchor = max.max(1);
if self.min_anchor > self.max_anchor {
self.min_anchor = self.max_anchor;
self.anchor = self.anchor.clamp(self.min_anchor, self.max_anchor);
}
self
}
pub fn set_max_total_batches(&mut self, max_total: usize) {
self.max_total_batches = if max_total == 0 {
None
} else {
Some(max_total)
};
}
pub fn with_min_anchor(mut self, min: usize) -> Self {
self.min_anchor = min.max(1);
if self.min_anchor > self.max_anchor {
self.min_anchor = self.max_anchor;
}
if self.anchor < self.min_anchor {
self.anchor = self.min_anchor;
}
self
}
pub fn with_max_batch_diff(mut self, max: usize) -> Self {
self.max_batch_diff = Some(max);
self
}
pub fn max_batch_diff(&self) -> Option<usize> {
self.max_batch_diff
}
pub fn with_speed_ratio(mut self, slow_rank: usize, ratio: f64) -> Self {
assert!(
slow_rank < self.world_size,
"slow_rank ({slow_rank}) out of bounds for world_size ({})",
self.world_size,
);
let ratio = ratio.max(1.0);
for rank in 0..self.world_size {
if rank == slow_rank {
self.batch_counts[rank] = self.anchor;
} else {
self.batch_counts[rank] =
(self.anchor as f64 * ratio).round().max(1.0) as usize;
}
}
self.anchor_rank = Some(slow_rank);
self
}
pub fn with_initial_anchor(mut self, slow_rank: usize) -> Self {
assert!(
slow_rank < self.world_size,
"slow_rank ({slow_rank}) out of bounds for world_size ({})",
self.world_size,
);
self.anchor_rank = Some(slow_rank);
self
}
pub fn with_device_indices(mut self, device_indices: &[i32]) -> Self {
if self.anchor_rank.is_some() {
return self;
}
if device_indices.len() != self.world_size {
return self;
}
if let Some(slow) = spec_prior::slowest_rank(device_indices) {
self.anchor_rank = Some(slow);
}
self
}
pub fn batches(&self, rank: usize) -> usize {
self.batch_counts[rank]
}
pub fn batch_counts(&self) -> &[usize] {
&self.batch_counts
}
pub fn apply_callback_slack(&mut self, slack_ms: &[f64]) {
if slack_ms.len() != self.world_size {
return;
}
self.pending_callback_slack_ms.clone_from_slice(slack_ms);
}
pub fn pending_callback_slack_ms(&self) -> &[f64] {
&self.pending_callback_slack_ms
}
pub fn set_window_fill_ms(&mut self, fill_ms: &[f64]) {
if fill_ms.len() != self.world_size {
return;
}
self.pending_window_fill_ms.clone_from_slice(fill_ms);
}
pub fn pending_window_fill_ms(&self) -> &[f64] {
&self.pending_window_fill_ms
}
pub fn growth_enabled(&self) -> bool {
self.growth_enabled
}
pub fn total_batches(&self) -> usize {
self.batch_counts.iter().sum()
}
pub fn anchor(&self) -> usize {
self.anchor
}
pub fn anchor_wall_ms(&self) -> f64 {
if !self.calibrated {
return 0.0;
}
self.anchor as f64 * self.slow_ms()
}
pub fn nudge_anchor_down(&mut self, factor: f64) {
if !factor.is_finite() {
return;
}
let new = (self.anchor as f64 * factor.clamp(0.1, 1.0)).ceil() as usize;
self.anchor = new.max(1).min(self.anchor);
let slow_ms = self.slow_ms();
if slow_ms > 0.0 {
self.recompute_batch_counts(slow_ms);
}
}
pub fn relax_anchor_up(&mut self) {
if self.anchor >= self.max_anchor {
return;
}
if let Some(max_diff) = self.max_batch_diff {
let smoothed: Vec<f64> = (0..self.world_size)
.map(|r| self.smoothed_ms(r))
.collect();
let max_ms = smoothed.iter().copied().fold(0.0_f64, f64::max);
let min_ms = smoothed.iter().copied()
.filter(|&m| m > 0.0)
.fold(f64::MAX, f64::min);
if max_ms > 0.0 && min_ms.is_finite() && min_ms > 0.0 {
let new_anchor = self.anchor + 1;
let projected_fast =
(new_anchor as f64 * max_ms / min_ms).round().max(1.0) as usize;
if projected_fast.saturating_sub(new_anchor) > max_diff {
return;
}
}
}
self.anchor += 1;
let slow_ms = self.slow_ms();
if slow_ms > 0.0 {
self.recompute_batch_counts(slow_ms);
}
}
pub fn commit_proposed_anchor(&mut self) {
self.consecutive_stable = self.consecutive_stable.saturating_add(1);
if self.consecutive_stable >= GROWTH_REARM_STABLE {
self.growth_enabled = true;
}
if let Some(ProposedAnchor::Grow(n)) = self.proposed_anchor.take() {
self.anchor = n;
let slow_ms = self.slow_ms();
if slow_ms > 0.0 {
self.recompute_batch_counts(slow_ms);
}
}
}
pub fn veto_proposed_growth(&mut self) {
self.proposed_anchor = None;
self.consecutive_stable = 0;
self.growth_enabled = false;
}
pub fn discard_proposed_anchor(&mut self) {
self.proposed_anchor = None;
self.consecutive_stable = 0;
self.growth_enabled = false;
}
pub fn apply_verdict(&mut self, verdict: AnchorVerdict) {
match verdict {
AnchorVerdict::Stable { relax_up } => {
self.commit_proposed_anchor();
if relax_up {
self.relax_anchor_up();
}
}
AnchorVerdict::SuppressGrowth => {
self.veto_proposed_growth();
}
AnchorVerdict::NudgeDown { factor } => {
self.discard_proposed_anchor();
self.nudge_anchor_down(factor);
}
}
}
pub fn is_calibrated(&self) -> bool {
self.calibrated
}
pub fn has_speed_hint(&self) -> bool {
self.batch_counts.windows(2).any(|w| w[0] != w[1])
}
pub fn ms_per_batch(&self) -> Vec<f64> {
(0..self.world_size).map(|r| self.smoothed_ms(r)).collect()
}
pub fn smoothed_ms_per_batch(&self, rank: usize) -> Option<f64> {
self.ms_per_batch_window
.get(rank)
.filter(|w| !w.is_empty())
.map(|w| w.mean())
}
pub fn report_window(&mut self, report: &WindowReport) {
self.set_window_fill_ms(&report.fill_ms);
let (ms, batches) = report.select_feed();
if ms.iter().any(|&m| m > 0.0) {
self.report_timing(&ms, &batches, report.sync_ms);
}
}
pub fn report_timing(&mut self, wall_ms: &[f64], actual_batches: &[usize], sync_ms: f64) {
assert_eq!(
wall_ms.len(),
self.world_size,
"wall_ms length must match world_size",
);
assert_eq!(
actual_batches.len(),
self.world_size,
"actual_batches length must match world_size",
);
for (rank, &wall) in wall_ms.iter().enumerate() {
let n = actual_batches.get(rank).copied().unwrap_or(0);
if n > 0 && wall > 0.0 && wall.is_finite() {
let new_ms = wall / n as f64;
self.ms_per_batch_window[rank].push(new_ms);
self.consecutive_zero_reports[rank] = 0;
} else {
self.consecutive_zero_reports[rank] += 1;
if self.consecutive_zero_reports[rank] >= TRUST_WINDOW_CAP {
self.ms_per_batch_window[rank].clear();
}
}
}
let allow_election =
self.anchor_rank.is_none() || self.phase >= Phase::Stable;
if allow_election {
if let Some(elected) = self.elect_anchor() {
self.anchor_rank = Some(elected);
}
}
let anchor_rank = match self.anchor_rank {
Some(r) => r,
None => return,
};
let mut slow_ms = self.smoothed_ms(anchor_rank);
if slow_ms <= 0.0 {
if self.consecutive_zero_reports[anchor_rank] >= TRUST_WINDOW_CAP {
if let Some(elected) = self.elect_anchor() {
self.anchor_rank = Some(elected);
slow_ms = self.smoothed_ms(elected);
}
}
if slow_ms <= 0.0 {
return;
}
}
self.proposed_anchor = None;
if self.phase >= Phase::Stable
|| (self.phase == Phase::Warmup && self.calibration_count >= 1)
{
self.proposed_anchor = self.propose_anchor(sync_ms);
}
for f in &mut self.pending_window_fill_ms {
*f = 0.0;
}
self.recompute_batch_counts(slow_ms);
if self.batch_counts_window.len() >= BATCH_COUNTS_WINDOW_CAP {
self.batch_counts_window.pop_front();
}
self.batch_counts_window.push_back(self.batch_counts.clone());
self.calibrated = true;
self.calibration_count += 1;
crate::verbose!(
" ddp-diag: ms_per_batch={:?} batch_counts={:?} anchor_rank={:?} anchor={}",
self.ms_per_batch().iter().map(|m| (m * 10.0).round() / 10.0).collect::<Vec<_>>(),
self.batch_counts,
self.anchor_rank,
self.anchor,
);
self.advance_phase();
}
pub fn recent_batch_share(&self) -> Vec<f64> {
if self.batch_counts_window.is_empty() {
let total: usize = self.batch_counts.iter().sum();
if total == 0 {
return vec![1.0 / self.world_size as f64; self.world_size];
}
return self
.batch_counts
.iter()
.map(|&c| c as f64 / total as f64)
.collect();
}
let mut sums = vec![0.0_f64; self.world_size];
let mut total = 0.0_f64;
for snap in &self.batch_counts_window {
for (r, &c) in snap.iter().enumerate() {
sums[r] += c as f64;
total += c as f64;
}
}
if total <= 0.0 {
return vec![1.0 / self.world_size as f64; self.world_size];
}
sums.into_iter().map(|s| s / total).collect()
}
fn advance_phase(&mut self) {
let next = match self.phase {
Phase::Probe => Phase::Warmup,
Phase::Warmup if self.calibration_count >= 5 => Phase::Stable,
Phase::Stable if self.calibration_count >= 20 => Phase::Mature,
p => p,
};
if next != self.phase {
crate::verbose!(
" ddp: ElChe phase {:?} -> {:?} (calibration #{}, anchor=rank {})",
self.phase, next, self.calibration_count,
self.anchor_rank.map(|r| r as i64).unwrap_or(-1),
);
self.phase = next;
}
}
pub fn clamp_total(&self, max_total: usize) -> Vec<usize> {
let current_total = self.total_batches();
if current_total <= max_total {
return self.batch_counts.clone();
}
let scale = max_total as f64 / current_total as f64;
let mut clamped: Vec<usize> = self
.batch_counts
.iter()
.map(|&n| (n as f64 * scale).floor().max(1.0) as usize)
.collect();
let sum: usize = clamped.iter().sum();
let mut remainder = max_total.saturating_sub(sum);
for c in &mut clamped {
if remainder == 0 {
break;
}
*c += 1;
remainder -= 1;
}
clamped
}
fn propose_anchor(&self, sync_ms: f64) -> Option<ProposedAnchor> {
if !self.window_growth_applicable {
return None;
}
if !self.growth_enabled {
return None;
}
if self.window_cap_binding {
crate::verbose!(
" ddp: window-pressure growth suppressed — window cap binding \
(epoch is the ceiling at this size)"
);
return None;
}
let b = self.anchor_rank?;
let marginal_b = self.smoothed_ms(b);
if marginal_b <= 0.0 {
return None;
}
let fill_b = self.pending_window_fill_ms.get(b).copied().unwrap_or(0.0).max(0.0);
let reduce_ms = sync_ms.max(0.0);
let window_compute = self.anchor as f64 * marginal_b;
let fixed = reduce_ms + fill_b;
let denom = window_compute + fixed;
if denom <= 0.0 || fixed <= 0.0 {
return None;
}
let overhead = fixed / denom;
let fire_at = if self.phase >= Phase::Stable {
self.overhead_target
} else {
self.overhead_target * WARMUP_GROWTH_MARGIN
};
if overhead <= fire_at {
return None;
}
let scale = (overhead / self.overhead_target).min(GROWTH_STEP_CAP);
let new_anchor = (self.anchor as f64 * scale).ceil() as usize;
let clamped = new_anchor.clamp(self.min_anchor, self.max_anchor);
if clamped > self.anchor {
return Some(ProposedAnchor::Grow(clamped));
}
None
}
fn recompute_batch_counts(&mut self, slow_ms: f64) {
for rank in 0..self.world_size {
let ms = self.smoothed_ms(rank);
let target_no_slack = if ms <= 0.0 || (ms - slow_ms).abs() < 1e-6 {
self.anchor
} else {
let ratio = (slow_ms / ms).min(MAX_SPEED_RATIO);
(self.anchor as f64 * ratio).round().max(1.0) as usize
};
let slack_ms = self.pending_callback_slack_ms[rank];
let slack_batches = if slack_ms > 0.0 && ms > 0.0 {
(slack_ms / ms).ceil() as usize
} else {
0
};
let target = target_no_slack.saturating_sub(slack_batches).max(1);
let current = self.batch_counts[rank];
let diff = (target as f64 - current as f64).abs();
let slack_active = slack_batches > 0;
if diff > current as f64 * 0.05 || !self.calibrated || slack_active {
let clamped = match self.max_batch_diff {
Some(max) if self.calibrated => {
if target > current {
current.saturating_add(max).min(target)
} else {
current.saturating_sub(max).max(target).max(1)
}
}
_ => target,
};
self.batch_counts[rank] = clamped;
}
}
self.window_cap_binding = false;
if let Some(max_total) = self.max_total_batches {
let total: usize = self.batch_counts.iter().sum();
if total > max_total && max_total > 0 {
self.window_cap_binding = true;
let scale = max_total as f64 / total as f64;
for c in &mut self.batch_counts {
*c = ((*c as f64) * scale).floor().max(1.0) as usize;
}
let used: usize = self.batch_counts.iter().sum();
if let Some(rem) = max_total.checked_sub(used) {
if rem > 0 {
if let Some(fastest) = (0..self.world_size)
.max_by_key(|&r| self.batch_counts[r])
{
self.batch_counts[fastest] += rem;
}
}
}
}
}
for s in &mut self.pending_callback_slack_ms {
*s = 0.0;
}
}
}
mod spec_prior {
fn score(device_index: i32, gpus: &[crate::sys::GpuInfo]) -> Option<f64> {
let gpu = gpus.iter().find(|g| g.index as i32 == device_index)?;
let vram_gb = gpu.vram_bytes() as f64 / 1_073_741_824.0;
Some((gpu.sm_major as f64) * 100.0 + (gpu.sm_minor as f64) * 10.0 + vram_gb)
}
pub(super) fn slowest_rank(device_indices: &[i32]) -> Option<usize> {
let gpus = crate::sys::detect_gpus();
let scores: Option<Vec<(usize, f64)>> = device_indices
.iter()
.enumerate()
.map(|(rank, &idx)| score(idx, &gpus).map(|s| (rank, s)))
.collect();
let scores = scores?;
scores
.into_iter()
.min_by(|(ra, a), (rb, b)| {
a.partial_cmp(b)
.unwrap_or(std::cmp::Ordering::Equal)
.then(ra.cmp(rb))
})
.map(|(rank, _)| rank)
}
}
#[cfg(test)]
mod meta_nudge_tests {
use super::*;
#[test]
fn nudge_then_discard_survives_a_later_commit() {
let mut el = ElChe::new(2, 10);
el.proposed_anchor = Some(ProposedAnchor::Grow(20));
el.nudge_anchor_down(0.5); assert_eq!(el.anchor(), 5);
el.discard_proposed_anchor(); el.commit_proposed_anchor(); assert_eq!(
el.anchor(),
5,
"meta nudge must survive: discard drops the pre-nudge grow so \
commit has nothing to apply"
);
}
#[test]
fn nudge_without_discard_is_clobbered_by_commit() {
let mut el = ElChe::new(2, 10);
el.proposed_anchor = Some(ProposedAnchor::Grow(20));
el.nudge_anchor_down(0.5); assert_eq!(el.anchor(), 5);
el.commit_proposed_anchor(); assert_eq!(
el.anchor(),
20,
"documents the H12 bug: an un-discarded grow overwrites the nudge"
);
}
}
#[cfg(test)]
mod verdict_seam_tests {
use super::*;
#[test]
fn verdict_nudge_down_discards_and_nudges() {
let mut el = ElChe::new(2, 10);
el.proposed_anchor = Some(ProposedAnchor::Grow(20));
el.apply_verdict(AnchorVerdict::NudgeDown { factor: 0.5 });
assert_eq!(el.anchor(), 5);
el.apply_verdict(AnchorVerdict::Stable { relax_up: false });
assert_eq!(
el.anchor(),
5,
"the verdict's built-in discard must survive a later Stable commit"
);
assert!(!el.growth_enabled(), "NudgeDown latches growth off");
}
#[test]
fn verdict_stable_commits_pending_grow() {
let mut el = ElChe::new(2, 10);
el.proposed_anchor = Some(ProposedAnchor::Grow(20));
el.apply_verdict(AnchorVerdict::Stable { relax_up: false });
assert_eq!(el.anchor(), 20);
}
#[test]
fn verdict_stable_relax_up_drifts_anchor() {
let mut el = ElChe::new(2, 10);
el.apply_verdict(AnchorVerdict::Stable { relax_up: true });
assert_eq!(el.anchor(), 11, "relax_up drifts +1 toward max_anchor");
let mut el = ElChe::new(2, 10);
el.apply_verdict(AnchorVerdict::Stable { relax_up: false });
assert_eq!(el.anchor(), 10, "without relax_up the anchor holds");
}
#[test]
fn verdict_suppress_growth_drops_proposal_and_latches() {
let mut el = ElChe::new(2, 10);
el.proposed_anchor = Some(ProposedAnchor::Grow(20));
el.apply_verdict(AnchorVerdict::SuppressGrowth);
assert_eq!(el.anchor(), 10, "SuppressGrowth holds the anchor");
assert!(!el.growth_enabled());
el.apply_verdict(AnchorVerdict::Stable { relax_up: false });
assert_eq!(el.anchor(), 10, "the vetoed proposal is gone for good");
}
}
#[cfg(test)]
mod report_window_tests {
use super::*;
fn report(
wall: &[f64],
steps: &[usize],
dms: &[f64],
dbatches: &[usize],
coherent: bool,
) -> WindowReport {
WindowReport {
wall_ms: wall.to_vec(),
steps: steps.to_vec(),
delivered_ms: dms.to_vec(),
delivered_batches: dbatches.to_vec(),
fill_ms: vec![0.0; wall.len()],
delivered_coherent: coherent,
sync_ms: 1.0,
}
}
#[test]
fn coherent_report_feeds_the_delivered_scale() {
let mut el = ElChe::new(2, 4);
el.report_window(&report(
&[40.0, 100.0],
&[4, 4],
&[80.0, 220.0],
&[4, 4],
true,
));
assert!(el.is_calibrated());
assert!((el.smoothed_ms_per_batch(0).unwrap() - 20.0).abs() < 1e-9);
assert!((el.smoothed_ms_per_batch(1).unwrap() - 55.0).abs() < 1e-9);
}
#[test]
fn incoherent_report_feeds_the_compute_scale() {
let mut el = ElChe::new(2, 4);
el.report_window(&report(
&[40.0, 100.0],
&[4, 4],
&[80.0, 0.0],
&[4, 0],
false,
));
assert!((el.smoothed_ms_per_batch(0).unwrap() - 10.0).abs() < 1e-9);
assert!((el.smoothed_ms_per_batch(1).unwrap() - 25.0).abs() < 1e-9);
}
#[test]
fn all_zero_window_reports_nothing() {
let mut el = ElChe::new(2, 4);
el.report_window(&report(&[0.0, 0.0], &[0, 0], &[0.0, 0.0], &[0, 0], true));
assert!(
!el.is_calibrated(),
"a fully-idle window must not poison the trust windows"
);
}
}
#[cfg(test)]
mod window_growth_policy_tests {
use super::*;
#[test]
fn sync_policy_exempt_from_window_pressure_growth() {
let mut el = ElChe::new(2, 10);
el.anchor_rank = Some(0);
el.ms_per_batch_window[0].push(1.0);
assert!(
matches!(el.propose_anchor(10.0), Some(ProposedAnchor::Grow(n)) if n > 10),
"windowed policy should propose growth in this high-overhead state"
);
let el_sync = el.with_window_growth_applicable(false);
assert!(
el_sync.propose_anchor(10.0).is_none(),
"Sync must never propose window-pressure growth"
);
}
#[test]
fn warmup_proposes_growth_from_the_second_calibration() {
let mut el = ElChe::new(2, 10);
let bc = el.batch_counts().to_vec();
el.report_timing(&[1000.0, 1000.0], &bc, 5000.0);
assert_eq!(el.phase, Phase::Warmup);
assert!(
el.proposed_anchor.is_none(),
"the first report must never propose growth"
);
let bc = el.batch_counts().to_vec();
el.report_timing(&[1000.0, 1000.0], &bc, 5000.0);
assert_eq!(el.phase, Phase::Warmup);
assert!(
matches!(el.proposed_anchor, Some(ProposedAnchor::Grow(20))),
"second calibration must propose capped growth, got {:?}",
el.proposed_anchor,
);
el.commit_proposed_anchor();
assert_eq!(el.anchor(), 20);
}
#[test]
fn warmup_growth_still_dies_on_a_guard_veto() {
let mut el = ElChe::new(2, 10);
let bc = el.batch_counts().to_vec();
el.report_timing(&[1000.0, 1000.0], &bc, 5000.0);
let bc = el.batch_counts().to_vec();
el.report_timing(&[1000.0, 1000.0], &bc, 5000.0);
assert!(matches!(el.proposed_anchor, Some(ProposedAnchor::Grow(_))));
el.veto_proposed_growth();
assert_eq!(el.anchor(), 10, "a vetoed warmup proposal must not land");
}
#[test]
fn borderline_warmup_pressure_waits_for_stable() {
let mut el = ElChe::new(2, 10).with_overhead_target(0.10);
for i in 0..5 {
let bc = el.batch_counts().to_vec();
el.report_timing(&[1000.0, 1000.0], &bc, 150.0);
assert!(
el.proposed_anchor.is_none(),
"borderline pressure proposed during warmup (report #{})",
i + 1,
);
}
assert_eq!(el.phase, Phase::Stable);
let bc = el.batch_counts().to_vec();
el.report_timing(&[1000.0, 1000.0], &bc, 150.0);
assert!(
matches!(el.proposed_anchor, Some(ProposedAnchor::Grow(_))),
"the same pressure must fire once Stable, got {:?}",
el.proposed_anchor,
);
}
}