summaryrefslogtreecommitdiff
path: root/src/metrics.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/metrics.rs')
-rw-r--r--src/metrics.rs290
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);
- }
-}