diff options
Diffstat (limited to 'src/metrics.rs')
| -rw-r--r-- | src/metrics.rs | 290 |
1 files changed, 0 insertions, 290 deletions
diff --git a/src/metrics.rs b/src/metrics.rs deleted file mode 100644 index 369aff8..0000000 --- a/src/metrics.rs +++ /dev/null @@ -1,290 +0,0 @@ -use std::time::{Duration, Instant}; -use std::collections::VecDeque; - -/// Rolling average calculator for smooth metric display -pub struct RollingAverage { - values: VecDeque<f64>, - capacity: usize, - sum: f64, -} - -impl RollingAverage { - pub fn new(capacity: usize) -> Self { - Self { - values: VecDeque::with_capacity(capacity), - capacity, - sum: 0.0, - } - } - - pub fn push(&mut self, value: f64) { - if self.values.len() >= self.capacity { - if let Some(old) = self.values.pop_front() { - self.sum -= old; - } - } - self.values.push_back(value); - self.sum += value; - } - - pub fn average(&self) -> f64 { - if self.values.is_empty() { - 0.0 - } else { - self.sum / self.values.len() as f64 - } - } - - pub fn min(&self) -> f64 { - self.values.iter().copied().fold(f64::INFINITY, f64::min) - } - - pub fn max(&self) -> f64 { - self.values.iter().copied().fold(f64::NEG_INFINITY, f64::max) - } - - pub fn latest(&self) -> f64 { - self.values.back().copied().unwrap_or(0.0) - } -} - -/// Frame timing breakdown -#[derive(Debug, Clone)] -pub struct FrameTiming { - pub total_ms: f64, - pub update_ms: f64, - pub render_ms: f64, - pub vertex_count: usize, - pub line_count: usize, -} - -/// Performance metrics collector with rolling averages -pub struct PerformanceMetrics { - // Rolling averages (default: 60 frames) - frame_time: RollingAverage, - update_time: RollingAverage, - render_time: RollingAverage, - vertex_count: RollingAverage, - line_count: RollingAverage, - - // Session-wide statistics - pub total_frames: u64, - session_start: Instant, - - // Current frame timing - frame_start: Option<Instant>, - update_start: Option<Instant>, - render_start: Option<Instant>, - - // Historical data for export - history: VecDeque<FrameTiming>, - history_capacity: usize, -} - -impl PerformanceMetrics { - pub fn new(rolling_window: usize, history_capacity: usize) -> Self { - Self { - frame_time: RollingAverage::new(rolling_window), - update_time: RollingAverage::new(rolling_window), - render_time: RollingAverage::new(rolling_window), - vertex_count: RollingAverage::new(rolling_window), - line_count: RollingAverage::new(rolling_window), - total_frames: 0, - session_start: Instant::now(), - frame_start: None, - update_start: None, - render_start: None, - history: VecDeque::with_capacity(history_capacity), - history_capacity, - } - } - - // Frame timing markers - pub fn begin_frame(&mut self) { - self.frame_start = Some(Instant::now()); - } - - pub fn begin_update(&mut self) { - self.update_start = Some(Instant::now()); - } - - pub fn end_update(&mut self) -> f64 { - if let Some(start) = self.update_start.take() { - let duration = start.elapsed(); - duration.as_secs_f64() * 1000.0 - } else { - 0.0 - } - } - - pub fn begin_render(&mut self) { - self.render_start = Some(Instant::now()); - } - - pub fn end_render(&mut self) -> f64 { - if let Some(start) = self.render_start.take() { - let duration = start.elapsed(); - duration.as_secs_f64() * 1000.0 - } else { - 0.0 - } - } - - pub fn end_frame(&mut self, update_ms: f64, render_ms: f64, vertex_count: usize, line_count: usize) { - if let Some(start) = self.frame_start.take() { - let total_ms = start.elapsed().as_secs_f64() * 1000.0; - - // Update rolling averages - self.frame_time.push(total_ms); - self.update_time.push(update_ms); - self.render_time.push(render_ms); - self.vertex_count.push(vertex_count as f64); - self.line_count.push(line_count as f64); - - // Record to history - let timing = FrameTiming { - total_ms, - update_ms, - render_ms, - vertex_count, - line_count, - }; - - if self.history.len() >= self.history_capacity { - self.history.pop_front(); - } - self.history.push_back(timing); - - self.total_frames += 1; - } - } - - // Getters for current metrics - pub fn fps(&self) -> f64 { - let avg_frame_time = self.frame_time.average(); - if avg_frame_time > 0.0 { - 1000.0 / avg_frame_time - } else { - 0.0 - } - } - - pub fn avg_frame_time_ms(&self) -> f64 { - self.frame_time.average() - } - - pub fn avg_update_time_ms(&self) -> f64 { - self.update_time.average() - } - - pub fn avg_render_time_ms(&self) -> f64 { - self.render_time.average() - } - - pub fn avg_vertex_count(&self) -> f64 { - self.vertex_count.average() - } - - pub fn avg_line_count(&self) -> f64 { - self.line_count.average() - } - - pub fn min_fps(&self) -> f64 { - let max_frame_time = self.frame_time.max(); - if max_frame_time > 0.0 && max_frame_time.is_finite() { - 1000.0 / max_frame_time - } else { - 0.0 - } - } - - pub fn max_fps(&self) -> f64 { - let min_frame_time = self.frame_time.min(); - if min_frame_time > 0.0 && min_frame_time.is_finite() { - 1000.0 / min_frame_time - } else { - 0.0 - } - } - - pub fn session_duration(&self) -> Duration { - self.session_start.elapsed() - } - - // Export functionality - pub fn export_to_csv(&self, path: &str) -> std::io::Result<()> { - use std::io::Write; - let mut file = std::fs::File::create(path)?; - - // Write header - writeln!(file, "frame,total_ms,update_ms,render_ms,vertex_count,line_count,fps")?; - - // Write data - for (i, timing) in self.history.iter().enumerate() { - let fps = if timing.total_ms > 0.0 { - 1000.0 / timing.total_ms - } else { - 0.0 - }; - writeln!( - file, - "{},{},{},{},{},{},{}", - i, - timing.total_ms, - timing.update_ms, - timing.render_ms, - timing.vertex_count, - timing.line_count, - fps - )?; - } - - Ok(()) - } - - pub fn format_summary(&self) -> String { - format!( - "FPS: {:.1} (min: {:.1}, max: {:.1}) | Frame: {:.2}ms | Update: {:.2}ms | Render: {:.2}ms | Vertices: {:.0} | Lines: {:.0}", - self.fps(), - self.min_fps(), - self.max_fps(), - self.avg_frame_time_ms(), - self.avg_update_time_ms(), - self.avg_render_time_ms(), - self.avg_vertex_count(), - self.avg_line_count() - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_rolling_average() { - let mut avg = RollingAverage::new(3); - avg.push(10.0); - avg.push(20.0); - avg.push(30.0); - assert_eq!(avg.average(), 20.0); - - avg.push(40.0); - assert_eq!(avg.average(), 30.0); // (20 + 30 + 40) / 3 - } - - #[test] - fn test_metrics_lifecycle() { - let mut metrics = PerformanceMetrics::new(60, 1000); - - metrics.begin_frame(); - metrics.begin_update(); - let update_ms = metrics.end_update(); - metrics.begin_render(); - let render_ms = metrics.end_render(); - metrics.end_frame(update_ms, render_ms, 1000, 10); - - assert_eq!(metrics.total_frames, 1); - assert!(metrics.fps() > 0.0); - } -} |
