Skip to main content

ying_profiler/
histogram.rs

1use std::fmt;
2
3// In terms of milliseconds
4const BUCKETS_MILLIS: &[u64] = &[1000, 5_000, 10_000, 30_000, 100_000, u64::MAX];
5const NUM_BUCKETS: usize = BUCKETS_MILLIS.len();
6
7/// Really simple histogram for tracking allocation durations
8/// Based on fixed buckets of <1s, <5s, <10s, <30s, <100s, longer
9#[derive(Copy, Clone, Debug)]
10pub struct MillisHistogram {
11    counts: [u64; NUM_BUCKETS],
12    sum: u64,
13    count: u64, // Total number of events or allocations
14}
15
16impl Default for MillisHistogram {
17    fn default() -> Self {
18        Self::new()
19    }
20}
21
22impl MillisHistogram {
23    pub fn new() -> Self {
24        Self {
25            counts: [0; NUM_BUCKETS],
26            sum: 0,
27            count: 0,
28        }
29    }
30
31    pub(crate) fn add_sample(&mut self, millis: u64) {
32        self.count += 1;
33        self.sum += millis;
34        match BUCKETS_MILLIS.binary_search(&millis) {
35            Ok(index) if index < NUM_BUCKETS => self.counts[index] += 1,
36            Err(index) if index < NUM_BUCKETS => self.counts[index] += 1,
37            _ => {}
38        }
39    }
40
41    pub fn average_millis(&self) -> f64 {
42        self.sum as f64 / self.count as f64
43    }
44
45    pub fn counts(&self) -> [u64; NUM_BUCKETS] {
46        self.counts
47    }
48
49    // TODO: add percentile calculation
50}
51
52impl fmt::Display for MillisHistogram {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        write!(
55            f,
56            "Histogram avg: {:.2}secs {{",
57            self.average_millis() / 1000.0
58        )?;
59        for (bucket, count) in BUCKETS_MILLIS.iter().zip(self.counts) {
60            write!(f, "{:.2}s: {}, ", *bucket as f64 / 1000.0, count)?;
61        }
62        write!(f, "}}")?;
63        Ok(())
64    }
65}