1use core::time::Duration;
9use std::collections::VecDeque;
10
11const WINDOW: Duration = Duration::from_secs(1);
13
14#[derive(Clone, Copy, Debug)]
16pub struct Frame {
17 pub at: Duration,
18 pub kernel: Duration,
19 pub paint: Duration,
20}
21
22#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
24pub struct Metered {
25 pub frames: usize,
27 pub kernel: Duration,
29 pub paint: Duration,
31 pub slowest: Duration,
33}
34
35#[derive(Default)]
36pub struct FrameMeter {
37 frames: VecDeque<Frame>,
38}
39
40impl FrameMeter {
41 pub fn record(&mut self, frame: Frame) -> Metered {
44 self.frames.push_back(frame);
45 while self
46 .frames
47 .front()
48 .is_some_and(|oldest| oldest.at + WINDOW <= frame.at)
49 {
50 self.frames.pop_front();
51 }
52 Metered {
53 frames: self.frames.len(),
54 kernel: frame.kernel,
55 paint: frame.paint,
56 slowest: self
57 .frames
58 .iter()
59 .map(|f| f.kernel + f.paint)
60 .max()
61 .unwrap_or_default(),
62 }
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 fn frame(at_ms: u64, kernel_ms: u64, paint_ms: u64) -> Frame {
71 Frame {
72 at: Duration::from_millis(at_ms),
73 kernel: Duration::from_millis(kernel_ms),
74 paint: Duration::from_millis(paint_ms),
75 }
76 }
77
78 #[test]
79 fn the_rate_counts_the_frames_of_the_last_second() {
80 let mut meter = FrameMeter::default();
81 let mut last = Metered::default();
82 for n in 0..60 {
83 last = meter.record(frame(n * 16, 5, 3));
84 }
85 assert_eq!(last.frames, 60, "a busy second at 60 Hz");
86 let later = meter.record(frame(59 * 16 + 1_000, 5, 3));
87 assert_eq!(
88 later.frames, 1,
89 "a second later only the frame just drawn is in the window"
90 );
91 }
92
93 #[test]
94 fn the_reading_is_the_last_frames_cost_and_the_seconds_slowest() {
95 let mut meter = FrameMeter::default();
96 meter.record(frame(0, 40, 10));
97 let reading = meter.record(frame(16, 4, 2));
98 assert_eq!(reading.kernel, Duration::from_millis(4));
99 assert_eq!(reading.paint, Duration::from_millis(2));
100 assert_eq!(reading.slowest, Duration::from_millis(50));
101 }
102}