1use std::collections::VecDeque;
2use std::time::{Duration, Instant};
3
4use crate::model::GpuSample;
5
6#[derive(Debug, Clone)]
7pub struct History {
8 retention: Duration,
9 samples: VecDeque<GpuSample>,
10}
11
12impl History {
13 pub fn new(retention: Duration) -> Self {
14 Self {
15 retention,
16 samples: VecDeque::new(),
17 }
18 }
19
20 pub fn push(&mut self, sample: GpuSample) {
21 let newest = sample.at;
22 self.samples.push_back(sample);
23 self.prune(newest);
24 }
25
26 pub fn latest(&self) -> Option<&GpuSample> {
27 self.samples.back()
28 }
29
30 pub fn len(&self) -> usize {
31 self.samples.len()
32 }
33
34 pub fn is_empty(&self) -> bool {
35 self.samples.is_empty()
36 }
37
38 pub fn iter_window(
39 &self,
40 now: Instant,
41 window: Duration,
42 ) -> impl DoubleEndedIterator<Item = &GpuSample> {
43 self.samples
44 .iter()
45 .filter(move |sample| sample.at <= now && now.duration_since(sample.at) <= window)
46 }
47
48 pub fn retention(&self) -> Duration {
49 self.retention
50 }
51
52 fn prune(&mut self, now: Instant) {
53 while let Some(front) = self.samples.front() {
54 if front.at <= now && now.duration_since(front.at) > self.retention {
55 self.samples.pop_front();
56 } else {
57 break;
58 }
59 }
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 use crate::model::GpuSample;
67
68 #[test]
69 fn prunes_samples_older_than_retention() {
70 let t0 = Instant::now();
71 let mut history = History::new(Duration::from_secs(2));
72 history.push(sample_at(t0));
73 history.push(sample_at(t0 + Duration::from_secs(1)));
74 history.push(sample_at(t0 + Duration::from_secs(3)));
75 assert_eq!(history.len(), 2);
76 }
77
78 fn sample_at(at: Instant) -> GpuSample {
79 GpuSample {
80 gpu_id: 0,
81 at,
82 gpu_util_percent: Some(0.0),
83 mem_util_percent: None,
84 vram_used_bytes: None,
85 vram_total_bytes: None,
86 power_watts: None,
87 power_limit_watts: None,
88 temperature_celsius: None,
89 fan_percent: None,
90 graphics_clock_mhz: None,
91 memory_clock_mhz: None,
92 compute_processes: None,
93 processes: Vec::new(),
94 }
95 }
96}