summaryrefslogtreecommitdiffstats
path: root/alacritty_terminal/src/meter.rs
blob: b208d286dc8c7b718f8abf98b79ff33bbef20252 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Rendering time meter.
//!
//! Used to track rendering times and provide moving averages.
//!
//! # Examples
//!
//! ```rust
//! // create a meter
//! let mut meter = alacritty_terminal::meter::Meter::new();
//!
//! // Sample something.
//! {
//!     let _sampler = meter.sampler();
//! }
//!
//! // Get the moving average. The meter tracks a fixed number of samples, and
//! // the average won't mean much until it's filled up at least once.
//! println!("Average time: {}", meter.average());
//! ```

use std::time::{Duration, Instant};

const NUM_SAMPLES: usize = 10;

/// The meter.
#[derive(Default)]
pub struct Meter {
    /// Track last 60 timestamps.
    times: [f64; NUM_SAMPLES],

    /// Average sample time in microseconds.
    avg: f64,

    /// Index of next time to update..
    index: usize,
}

/// Sampler.
///
/// Samplers record how long they are "alive" for and update the meter on drop..
pub struct Sampler<'a> {
    /// Reference to meter that created the sampler.
    meter: &'a mut Meter,

    /// When the sampler was created.
    created_at: Instant,
}

impl<'a> Sampler<'a> {
    fn new(meter: &'a mut Meter) -> Sampler<'a> {
        Sampler { meter, created_at: Instant::now() }
    }

    #[inline]
    fn alive_duration(&self) -> Duration {
        self.created_at.elapsed()
    }
}

impl<'a> Drop for Sampler<'a> {
    fn drop(&mut self) {
        self.meter.add_sample(self.alive_duration());
    }
}

impl Meter {
    /// Create a meter.
    pub fn new() -> Meter {
        Default::default()
    }

    /// Get a sampler.
    pub fn sampler(&mut self) -> Sampler<'_> {
        Sampler::new(self)
    }

    /// Get the current average sample duration in microseconds.
    pub fn average(&self) -> f64 {
        self.avg
    }

    /// Add a sample.
    ///
    /// Used by Sampler::drop.
    fn add_sample(&mut self, sample: Duration) {
        let mut usec = 0f64;

        usec += f64::from(sample.subsec_nanos()) / 1e3;
        usec += (sample.as_secs() as f64) * 1e6;

        let prev = self.times[self.index];
        self.times[self.index] = usec;
        self.avg -= prev / NUM_SAMPLES as f64;
        self.avg += usec / NUM_SAMPLES as f64;
        self.index = (self.index + 1) % NUM_SAMPLES;
    }
}