Skip to main content

gpu_histop/
history.rs

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}