use std::fmt::Arguments; use std::sync::atomic::{AtomicU8, Ordering}; static LEVEL: AtomicU8 = AtomicU8::new(1); pub fn set_level(level: u8) { LEVEL.store(level.min(3), Ordering::Relaxed); } pub fn level() -> u8 { LEVEL.load(Ordering::Relaxed) } pub fn l1(args: Arguments) { emit(1, args); } pub fn l2(args: Arguments) { emit(2, args); } fn emit(min: u8, args: Arguments) { if level() >= min { eprintln!("{args}"); } } pub struct BatchInfo { pub batch_idx : u64 , pub accepted_total : u32 , pub max_splines : u32 , pub accepted_now : u32 , pub batch_size : u32 , pub remaining : u32 , pub consecutive_stagnant : u32 , pub max_stagnant_batches : u32 , pub elapsed_s : f64 } pub struct BatchLogger { rate_avg : Option , accept_ratio_avg : Option , alpha : f64 , last_elapsed : f64 } impl BatchLogger { pub fn new() -> Self { Self { rate_avg: None, accept_ratio_avg: None, alpha: 0.25, last_elapsed: 0.0, } } pub fn log_batch(&mut self, info: BatchInfo) { let stop = info.consecutive_stagnant >= info.max_stagnant_batches; let delta = (info.elapsed_s - self.last_elapsed).max(0.0); self.last_elapsed = info.elapsed_s; let rate_sample = if delta > 0.0 { info.accepted_now as f64 / delta } else { 0.0 }; let ratio_sample = if info.batch_size > 0 { info.accepted_now as f64 / info.batch_size as f64 } else { 0.0 }; self.rate_avg = Some(self.update_ema(self.rate_avg, rate_sample)); self.accept_ratio_avg = Some(self.update_ema(self.accept_ratio_avg, ratio_sample)); let rate_avg = self.rate_avg.unwrap_or(0.0); let accept_avg = self.accept_ratio_avg.unwrap_or(0.0); self.emit(&info, ratio_sample, rate_avg, accept_avg, stop); } fn update_ema(&self, current: Option, sample: f64) -> f64 { match current { Some(prev) => prev * (1.0 - self.alpha) + sample * self.alpha, None => sample, } } fn emit(&self, info: &BatchInfo, batch_ratio: f64, rate_avg: f64, accept_avg: f64, stop: bool) { let lv = level(); let stop_note = if stop { " stop:stagnant" } else { "" }; if lv >= 3 { eprintln!( "b:{} t:{:.1}s acc:{}/{} (+{}, {:.3}) stagnant:{}/{} rem:{} avg_rate:{:.2}/s avg_accept:{:.3}{}", info.batch_idx, info.elapsed_s, info.accepted_total, info.max_splines, info.accepted_now, batch_ratio, info.consecutive_stagnant, info.max_stagnant_batches, info.remaining, rate_avg, accept_avg, stop_note ); } else if lv >= 2 { eprintln!( "b:{} t:{:.1}s acc:{}/{} (+{}, {:.3}) stagnant:{}/{} avg_rate:{:.2}/s avg_accept:{:.3}{}", info.batch_idx, info.elapsed_s, info.accepted_total, info.max_splines, info.accepted_now, batch_ratio, info.consecutive_stagnant, info.max_stagnant_batches, rate_avg, accept_avg, stop_note ); } else if lv >= 1 && (info.accepted_now > 0 || stop) { eprintln!( "{}/{} (+{}) stagnant:{}/{}{}", info.accepted_total, info.max_splines, info.accepted_now, info.consecutive_stagnant, info.max_stagnant_batches, stop_note ); } } }