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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
extern crate heatmap;
extern crate histogram;

use common::*;
use heatmap::Heatmap;
use histogram::Histogram;
use receiver::Receiver;
use std::fmt::Display;
use std::hash::Hash;
use std::marker::PhantomData;
use std::time::Duration;

/// a configuration struct for customizing `Receiver`
#[derive(Clone)]
pub struct Config<T> {
    resource_type: PhantomData<T>,
    /// the nominal sampling rate in Hertz
    pub sample_rate: f64,
    /// duration of a reporting interval (window) in seconds
    /// typical values are 1 or 60 for secondly or minutely reporting
    pub duration: usize,
    /// the number of reporting intervals (windows) to aggregate in
    /// heatmap and traces.
    /// NOTE: The receiver will halt if service_mode is false and the
    /// total number of windows have elapsed
    pub windows: usize,
    /// the largest Tau used in producing Allan Deviation meta-metrics
    pub max_tau: usize,
    /// the capacity of the stats queue. Default: 256
    pub capacity: usize,
    /// the default batch size of a `Sender`. Default: 512
    pub batch_size: usize,
    /// set continuous-run mode. heatmaps and traces will generate
    /// every N windows when this is set to true. If it is set to false,
    /// the `Receiver` will halt after N windows
    pub service_mode: bool,
    /// set an optional delay between calls to poll
    pub poll_delay: Option<Duration>,
    /// save a latency heatmap trace to the given file
    pub trace_file: Option<String>,
    /// save a waterfal png of the latency heatmap to the given file
    pub waterfall_file: Option<String>,
    /// the shared `Heatmap` configuration
    pub heatmap_config: heatmap::Config,
    /// the shared `Histogram` configuration
    pub histogram_config: histogram::Config,
}

impl<T: Hash + Eq + Send + Display + Clone> Default for Config<T> {
    fn default() -> Config<T> {
        let heatmap_config = Heatmap::configure().slice_duration(SECOND).precision(2);
        let histogram_config = Histogram::configure().max_value(MINUTE).precision(4);
        Config {
            resource_type: PhantomData::<T>,
            sample_rate: 1.0,
            duration: (MINUTE / SECOND) as usize,
            windows: (MINUTE / SECOND) as usize,
            capacity: 256,
            batch_size: 512,
            max_tau: 300,
            service_mode: false,
            poll_delay: None,
            trace_file: None,
            waterfall_file: None,
            heatmap_config: heatmap_config,
            histogram_config: histogram_config,
        }
    }
}

impl<T: Hash + Eq + Send + Display + Clone> Config<T> {
    /// create a new tic Config with defaults
    ///
    /// # Example
    /// ```
    /// # use tic::Receiver;
    /// let mut c = Receiver::<usize>::configure();
    /// ```
    pub fn new() -> Config<T> {
        Default::default()
    }

    /// set sampling rate in Hertz: default 1 Hz
    ///
    /// # Example
    /// ```
    /// # use tic::Receiver;
    /// let mut c = Receiver::<usize>::configure();
    /// c.sample_rate(1.0); // set to 1 Hz sample rate
    /// ```
    pub fn sample_rate(mut self, frequency: f64) -> Self {
        self.sample_rate = frequency;
        self
    }

    /// set integration window in seconds: default 60
    ///
    /// # Example
    /// ```
    /// # use tic::Receiver;
    /// let mut c = Receiver::<usize>::configure();
    /// c.duration(60); // set to 60 second integration window
    /// ```
    pub fn duration(mut self, duration: usize) -> Self {
        self.duration = duration;
        self.heatmap_config.num_slices(self.duration * self.windows);
        self
    }

    /// set number of windows to collect: default 60
    ///
    /// # Example
    /// ```
    /// # use tic::Receiver;
    /// let mut c = Receiver::<usize>::configure();
    /// c.windows(60); // collect for 60 x duration and terminate
    /// ```
    pub fn windows(mut self, windows: usize) -> Self {
        self.windows = windows;
        self.heatmap_config.num_slices(self.duration * self.windows);
        self
    }

    /// set max Tau used in calculating Allan Deviation: default 300
    ///
    /// # Example
    /// ```
    /// # use tic::Receiver;
    /// let mut c = Receiver::<usize>::configure();
    /// c.max_tau(300); // produce ADEV from 1-300 inclusive
    /// ```
    pub fn max_tau(mut self, tau: usize) -> Self {
        self.max_tau = tau;
        self
    }

    /// set capacity of the queue: default 256
    ///
    /// # Example
    /// ```
    /// # use tic::Receiver;
    /// let mut c = Receiver::<usize>::configure();
    /// c.capacity(256); // buffer for 256 batches of samples
    /// ```
    pub fn capacity(mut self, capacity: usize) -> Self {
        self.capacity = capacity;
        self
    }

    /// set batch size of the sender: default 512
    ///
    /// # Example
    /// ```
    /// # use tic::Receiver;
    /// let mut c = Receiver::<usize>::configure();
    /// c.batch_size(512); // batch 512 samples in one queue write
    /// ```
    pub fn batch_size(mut self, batch_size: usize) -> Self {
        self.batch_size = batch_size;
        self
    }

    /// set the heatmap trace file
    ///
    /// # Example
    /// ```
    /// # use tic::Receiver;
    /// let mut c = Receiver::<usize>::configure();
    /// c.trace_file("/tmp/heatmap.trace".to_owned()); // heatmap trace will write here
    /// ```
    pub fn trace_file(mut self, path: String) -> Self {
        self.trace_file = Some(path);
        self
    }

    /// set the heatmap trace file
    ///
    /// # Example
    /// ```
    /// # use tic::Receiver;
    /// let mut c = Receiver::<usize>::configure();
    /// c.waterfall_file("/tmp/waterfall.png".to_owned()); // waterfall png will render here
    /// ```
    pub fn waterfall_file(mut self, path: String) -> Self {
        self.waterfall_file = Some(path);
        self
    }

    /// set the poll delay
    ///
    /// # Example
    /// ```
    /// # use tic::Receiver;
    /// # use std::time::Duration;
    /// let mut c = Receiver::<usize>::configure();
    /// c.poll_delay(Some(Duration::new(0, 100_000)));
    pub fn poll_delay(mut self, delay: Option<Duration>) -> Self {
        self.poll_delay = delay;
        self
    }

    /// set receiver to continuous run mode aka service mode
    ///
    /// # Example
    /// ```
    /// # use tic::Receiver;
    /// let mut c = Receiver::<usize>::configure();
    /// c.service(true);
    pub fn service(mut self, enabled: bool) -> Self {
        self.service_mode = enabled;
        self
    }

    /// Build a new Receiver based on the current configuration
    pub fn build(self) -> Receiver<T> {
        Receiver::configured(self)
    }
}