109 lines
3.5 KiB
Rust

use prometeu_drivers::hardware::Hardware;
use prometeu_firmware::Firmware;
use std::time::{Duration, Instant};
use winit::window::Window;
pub struct HostStats {
pub last_stats_update: Instant,
pub frames_since_last_update: u64,
pub current_fps: f64,
pub audio_load_accum_us: u64,
pub audio_load_samples: u64,
recent_host_cpu_us: [u64; 5],
recent_host_cpu_count: usize,
recent_host_cpu_cursor: usize,
}
impl Default for HostStats {
fn default() -> Self {
Self::new()
}
}
impl HostStats {
pub fn new() -> Self {
Self {
last_stats_update: Instant::now(),
frames_since_last_update: 0,
current_fps: 0.0,
audio_load_accum_us: 0,
audio_load_samples: 0,
recent_host_cpu_us: [0; 5],
recent_host_cpu_count: 0,
recent_host_cpu_cursor: 0,
}
}
pub fn record_frame(&mut self) {
self.frames_since_last_update += 1;
}
pub fn record_audio_perf(&mut self, us: u64) {
self.audio_load_accum_us += us;
self.audio_load_samples += 1;
}
pub fn record_host_cpu_time(&mut self, us: u64) {
self.recent_host_cpu_us[self.recent_host_cpu_cursor] = us;
self.recent_host_cpu_cursor =
(self.recent_host_cpu_cursor + 1) % self.recent_host_cpu_us.len();
self.recent_host_cpu_count =
self.recent_host_cpu_count.saturating_add(1).min(self.recent_host_cpu_us.len());
}
pub fn average_host_cpu_ms(&self) -> f64 {
if self.recent_host_cpu_count == 0 {
0.0
} else {
let sum: u64 = self.recent_host_cpu_us.iter().take(self.recent_host_cpu_count).sum();
(sum as f64 / self.recent_host_cpu_count as f64) / 1000.0
}
}
pub fn update(
&mut self,
now: Instant,
window: Option<&Window>,
_hardware: &Hardware,
firmware: &Firmware,
) {
let stats_elapsed = now.duration_since(self.last_stats_update);
if stats_elapsed >= Duration::from_secs(1) {
self.current_fps = self.frames_since_last_update as f64 / stats_elapsed.as_secs_f64();
if let Some(window) = window {
// Fixed comparison always against 60Hz, keep even when doing CPU stress tests
let frame_budget_us = 16666.0;
let cpu_load_core = (self.average_host_cpu_ms() * 1000.0 / frame_budget_us) * 100.0;
let cpu_load_audio = if self.audio_load_samples > 0 {
(self.audio_load_accum_us as f64 / stats_elapsed.as_micros() as f64) * 100.0
} else {
0.0
};
let title = format!(
"PROMETEU | GFX: {:.1} KB | FPS: {:.1} | Load: {:.1}% (C) + {:.1}% (A) | Frame: tick {} logical {} done {}",
0,
self.current_fps,
cpu_load_core,
cpu_load_audio,
firmware.os.tick_index,
firmware.os.logical_frame_index,
firmware
.os
.atomic_telemetry
.completed_logical_frames
.load(std::sync::atomic::Ordering::Relaxed),
);
window.set_title(&title);
}
self.last_stats_update = now;
self.frames_since_last_update = 0;
self.audio_load_accum_us = 0;
self.audio_load_samples = 0;
}
}
}