1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker //! This module contains stats that useful on the system. Local stats may not a be in
6*bb4ee6a4SAndroid Build Coastguard Worker //! state to be consumed by metris reporter or it might not be efficient to report
7*bb4ee6a4SAndroid Build Coastguard Worker //! metrics in the current state to the backend.
8*bb4ee6a4SAndroid Build Coastguard Worker
9*bb4ee6a4SAndroid Build Coastguard Worker use std::fmt;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::fmt::Debug;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::ops::Add;
12*bb4ee6a4SAndroid Build Coastguard Worker use std::ops::Div;
13*bb4ee6a4SAndroid Build Coastguard Worker use std::ops::Range;
14*bb4ee6a4SAndroid Build Coastguard Worker use std::ops::Sub;
15*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
16*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Instant;
17*bb4ee6a4SAndroid Build Coastguard Worker
18*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow;
19*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result;
20*bb4ee6a4SAndroid Build Coastguard Worker use base::info;
21*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
22*bb4ee6a4SAndroid Build Coastguard Worker
23*bb4ee6a4SAndroid Build Coastguard Worker pub trait Limits {
absolute_min() -> Self24*bb4ee6a4SAndroid Build Coastguard Worker fn absolute_min() -> Self;
absolute_max() -> Self25*bb4ee6a4SAndroid Build Coastguard Worker fn absolute_max() -> Self;
26*bb4ee6a4SAndroid Build Coastguard Worker }
27*bb4ee6a4SAndroid Build Coastguard Worker
28*bb4ee6a4SAndroid Build Coastguard Worker impl Limits for u64 {
absolute_min() -> Self29*bb4ee6a4SAndroid Build Coastguard Worker fn absolute_min() -> Self {
30*bb4ee6a4SAndroid Build Coastguard Worker u64::MIN
31*bb4ee6a4SAndroid Build Coastguard Worker }
32*bb4ee6a4SAndroid Build Coastguard Worker
absolute_max() -> Self33*bb4ee6a4SAndroid Build Coastguard Worker fn absolute_max() -> Self {
34*bb4ee6a4SAndroid Build Coastguard Worker u64::MAX
35*bb4ee6a4SAndroid Build Coastguard Worker }
36*bb4ee6a4SAndroid Build Coastguard Worker }
37*bb4ee6a4SAndroid Build Coastguard Worker
38*bb4ee6a4SAndroid Build Coastguard Worker // Aggregate information about a collection that does require large memory footprint.
39*bb4ee6a4SAndroid Build Coastguard Worker pub trait SummaryStats<T> {
40*bb4ee6a4SAndroid Build Coastguard Worker /// Count of data points that tracked.
count(&self) -> u6441*bb4ee6a4SAndroid Build Coastguard Worker fn count(&self) -> u64;
42*bb4ee6a4SAndroid Build Coastguard Worker
43*bb4ee6a4SAndroid Build Coastguard Worker /// Sum of all data points.
44*bb4ee6a4SAndroid Build Coastguard Worker /// Returns None if count is zero.
sum(&self) -> Option<T>45*bb4ee6a4SAndroid Build Coastguard Worker fn sum(&self) -> Option<T>;
46*bb4ee6a4SAndroid Build Coastguard Worker
47*bb4ee6a4SAndroid Build Coastguard Worker /// Minimum value of data points.
48*bb4ee6a4SAndroid Build Coastguard Worker /// Returns None if count is zero.
min(&self) -> Option<T>49*bb4ee6a4SAndroid Build Coastguard Worker fn min(&self) -> Option<T>;
50*bb4ee6a4SAndroid Build Coastguard Worker
51*bb4ee6a4SAndroid Build Coastguard Worker /// Maximum value of data points.
52*bb4ee6a4SAndroid Build Coastguard Worker /// Returns None if count is zero.
max(&self) -> Option<T>53*bb4ee6a4SAndroid Build Coastguard Worker fn max(&self) -> Option<T>;
54*bb4ee6a4SAndroid Build Coastguard Worker
55*bb4ee6a4SAndroid Build Coastguard Worker /// Average value of data points.
56*bb4ee6a4SAndroid Build Coastguard Worker /// Returns None if count is zero.
average(&self) -> Option<T>57*bb4ee6a4SAndroid Build Coastguard Worker fn average(&self) -> Option<T>;
58*bb4ee6a4SAndroid Build Coastguard Worker }
59*bb4ee6a4SAndroid Build Coastguard Worker
60*bb4ee6a4SAndroid Build Coastguard Worker pub trait NumberType:
61*bb4ee6a4SAndroid Build Coastguard Worker Limits + Div<u64, Output = Self> + Add<Output = Self> + Clone + Ord + PartialOrd + Debug + Sub<Self>
62*bb4ee6a4SAndroid Build Coastguard Worker {
as_f64(&self) -> f6463*bb4ee6a4SAndroid Build Coastguard Worker fn as_f64(&self) -> f64;
64*bb4ee6a4SAndroid Build Coastguard Worker }
65*bb4ee6a4SAndroid Build Coastguard Worker
66*bb4ee6a4SAndroid Build Coastguard Worker impl NumberType for u64 {
as_f64(&self) -> f6467*bb4ee6a4SAndroid Build Coastguard Worker fn as_f64(&self) -> f64 {
68*bb4ee6a4SAndroid Build Coastguard Worker *self as f64
69*bb4ee6a4SAndroid Build Coastguard Worker }
70*bb4ee6a4SAndroid Build Coastguard Worker }
71*bb4ee6a4SAndroid Build Coastguard Worker
72*bb4ee6a4SAndroid Build Coastguard Worker /// Light weight stat struct that helps you get aggregate stats like min, max, average, count and
73*bb4ee6a4SAndroid Build Coastguard Worker /// sum.
74*bb4ee6a4SAndroid Build Coastguard Worker /// Median and standard deviation are intentionally excluded to keep the structure light weight.
75*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Eq, PartialEq)]
76*bb4ee6a4SAndroid Build Coastguard Worker pub struct SimpleStat<T: NumberType> {
77*bb4ee6a4SAndroid Build Coastguard Worker count: u64,
78*bb4ee6a4SAndroid Build Coastguard Worker sum: T,
79*bb4ee6a4SAndroid Build Coastguard Worker min: T,
80*bb4ee6a4SAndroid Build Coastguard Worker max: T,
81*bb4ee6a4SAndroid Build Coastguard Worker }
82*bb4ee6a4SAndroid Build Coastguard Worker
83*bb4ee6a4SAndroid Build Coastguard Worker /// A helper trait that can be associated with information that is tracked with a histogram.
84*bb4ee6a4SAndroid Build Coastguard Worker /// For example, if histogram is tracking latencies and for debugging reasons, if we want to track
85*bb4ee6a4SAndroid Build Coastguard Worker /// size of IO along with latency, this trait makes that posssible.
86*bb4ee6a4SAndroid Build Coastguard Worker pub trait Details<T: NumberType>: Debug {
87*bb4ee6a4SAndroid Build Coastguard Worker /// Returns a value that is being traked by the histogram.
value(&self) -> T88*bb4ee6a4SAndroid Build Coastguard Worker fn value(&self) -> T;
89*bb4ee6a4SAndroid Build Coastguard Worker }
90*bb4ee6a4SAndroid Build Coastguard Worker
91*bb4ee6a4SAndroid Build Coastguard Worker impl<T: NumberType> Details<T> for T {
value(&self) -> T92*bb4ee6a4SAndroid Build Coastguard Worker fn value(&self) -> T {
93*bb4ee6a4SAndroid Build Coastguard Worker self.clone()
94*bb4ee6a4SAndroid Build Coastguard Worker }
95*bb4ee6a4SAndroid Build Coastguard Worker }
96*bb4ee6a4SAndroid Build Coastguard Worker
97*bb4ee6a4SAndroid Build Coastguard Worker impl Details<u64> for Range<u64> {
value(&self) -> u6498*bb4ee6a4SAndroid Build Coastguard Worker fn value(&self) -> u64 {
99*bb4ee6a4SAndroid Build Coastguard Worker self.end - self.start
100*bb4ee6a4SAndroid Build Coastguard Worker }
101*bb4ee6a4SAndroid Build Coastguard Worker }
102*bb4ee6a4SAndroid Build Coastguard Worker
103*bb4ee6a4SAndroid Build Coastguard Worker impl<T: NumberType> Debug for SimpleStat<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result104*bb4ee6a4SAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105*bb4ee6a4SAndroid Build Coastguard Worker if self.count == 0 {
106*bb4ee6a4SAndroid Build Coastguard Worker f.debug_struct("SimpleStat")
107*bb4ee6a4SAndroid Build Coastguard Worker .field("count", &self.count)
108*bb4ee6a4SAndroid Build Coastguard Worker .finish()
109*bb4ee6a4SAndroid Build Coastguard Worker } else {
110*bb4ee6a4SAndroid Build Coastguard Worker f.debug_struct("SimpleStat")
111*bb4ee6a4SAndroid Build Coastguard Worker .field("count", &self.count)
112*bb4ee6a4SAndroid Build Coastguard Worker .field("sum", &self.sum)
113*bb4ee6a4SAndroid Build Coastguard Worker .field("min", &self.min)
114*bb4ee6a4SAndroid Build Coastguard Worker .field("max", &self.max)
115*bb4ee6a4SAndroid Build Coastguard Worker .field("average", &self.average().unwrap())
116*bb4ee6a4SAndroid Build Coastguard Worker .finish()
117*bb4ee6a4SAndroid Build Coastguard Worker }
118*bb4ee6a4SAndroid Build Coastguard Worker }
119*bb4ee6a4SAndroid Build Coastguard Worker }
120*bb4ee6a4SAndroid Build Coastguard Worker
121*bb4ee6a4SAndroid Build Coastguard Worker impl<T: NumberType> SimpleStat<T> {
add(&mut self, value: T)122*bb4ee6a4SAndroid Build Coastguard Worker pub fn add(&mut self, value: T) {
123*bb4ee6a4SAndroid Build Coastguard Worker self.count += 1;
124*bb4ee6a4SAndroid Build Coastguard Worker self.sum = self.sum.clone() + value.clone();
125*bb4ee6a4SAndroid Build Coastguard Worker if self.max < value {
126*bb4ee6a4SAndroid Build Coastguard Worker self.max = value.clone();
127*bb4ee6a4SAndroid Build Coastguard Worker }
128*bb4ee6a4SAndroid Build Coastguard Worker if self.min > value {
129*bb4ee6a4SAndroid Build Coastguard Worker self.min = value;
130*bb4ee6a4SAndroid Build Coastguard Worker }
131*bb4ee6a4SAndroid Build Coastguard Worker }
132*bb4ee6a4SAndroid Build Coastguard Worker }
133*bb4ee6a4SAndroid Build Coastguard Worker
134*bb4ee6a4SAndroid Build Coastguard Worker impl<T: NumberType> Default for SimpleStat<T> {
default() -> Self135*bb4ee6a4SAndroid Build Coastguard Worker fn default() -> Self {
136*bb4ee6a4SAndroid Build Coastguard Worker Self {
137*bb4ee6a4SAndroid Build Coastguard Worker count: 0,
138*bb4ee6a4SAndroid Build Coastguard Worker sum: T::absolute_min(),
139*bb4ee6a4SAndroid Build Coastguard Worker min: T::absolute_max(),
140*bb4ee6a4SAndroid Build Coastguard Worker max: T::absolute_min(),
141*bb4ee6a4SAndroid Build Coastguard Worker }
142*bb4ee6a4SAndroid Build Coastguard Worker }
143*bb4ee6a4SAndroid Build Coastguard Worker }
144*bb4ee6a4SAndroid Build Coastguard Worker
145*bb4ee6a4SAndroid Build Coastguard Worker impl<T: NumberType> SummaryStats<T> for SimpleStat<T> {
count(&self) -> u64146*bb4ee6a4SAndroid Build Coastguard Worker fn count(&self) -> u64 {
147*bb4ee6a4SAndroid Build Coastguard Worker self.count
148*bb4ee6a4SAndroid Build Coastguard Worker }
149*bb4ee6a4SAndroid Build Coastguard Worker
sum(&self) -> Option<T>150*bb4ee6a4SAndroid Build Coastguard Worker fn sum(&self) -> Option<T> {
151*bb4ee6a4SAndroid Build Coastguard Worker if self.count == 0 {
152*bb4ee6a4SAndroid Build Coastguard Worker return None;
153*bb4ee6a4SAndroid Build Coastguard Worker }
154*bb4ee6a4SAndroid Build Coastguard Worker Some(self.sum.clone())
155*bb4ee6a4SAndroid Build Coastguard Worker }
156*bb4ee6a4SAndroid Build Coastguard Worker
min(&self) -> Option<T>157*bb4ee6a4SAndroid Build Coastguard Worker fn min(&self) -> Option<T> {
158*bb4ee6a4SAndroid Build Coastguard Worker if self.count == 0 {
159*bb4ee6a4SAndroid Build Coastguard Worker return None;
160*bb4ee6a4SAndroid Build Coastguard Worker }
161*bb4ee6a4SAndroid Build Coastguard Worker Some(self.min.clone())
162*bb4ee6a4SAndroid Build Coastguard Worker }
163*bb4ee6a4SAndroid Build Coastguard Worker
max(&self) -> Option<T>164*bb4ee6a4SAndroid Build Coastguard Worker fn max(&self) -> Option<T> {
165*bb4ee6a4SAndroid Build Coastguard Worker if self.count == 0 {
166*bb4ee6a4SAndroid Build Coastguard Worker return None;
167*bb4ee6a4SAndroid Build Coastguard Worker }
168*bb4ee6a4SAndroid Build Coastguard Worker Some(self.max.clone())
169*bb4ee6a4SAndroid Build Coastguard Worker }
170*bb4ee6a4SAndroid Build Coastguard Worker
average(&self) -> Option<T>171*bb4ee6a4SAndroid Build Coastguard Worker fn average(&self) -> Option<T> {
172*bb4ee6a4SAndroid Build Coastguard Worker if self.count == 0 {
173*bb4ee6a4SAndroid Build Coastguard Worker return None;
174*bb4ee6a4SAndroid Build Coastguard Worker }
175*bb4ee6a4SAndroid Build Coastguard Worker Some(self.sum.clone() / self.count)
176*bb4ee6a4SAndroid Build Coastguard Worker }
177*bb4ee6a4SAndroid Build Coastguard Worker }
178*bb4ee6a4SAndroid Build Coastguard Worker
179*bb4ee6a4SAndroid Build Coastguard Worker /// Computes and returns median of `values`.
180*bb4ee6a4SAndroid Build Coastguard Worker /// This is an expensive function as it sorts values to get the median.
median<T: NumberType, D: Details<T>>(values: &[D]) -> T181*bb4ee6a4SAndroid Build Coastguard Worker fn median<T: NumberType, D: Details<T>>(values: &[D]) -> T {
182*bb4ee6a4SAndroid Build Coastguard Worker let mut sorted: Vec<T> = values.iter().map(|v| v.value()).collect();
183*bb4ee6a4SAndroid Build Coastguard Worker sorted.sort();
184*bb4ee6a4SAndroid Build Coastguard Worker sorted.get(sorted.len() / 2).unwrap().clone()
185*bb4ee6a4SAndroid Build Coastguard Worker }
186*bb4ee6a4SAndroid Build Coastguard Worker
187*bb4ee6a4SAndroid Build Coastguard Worker /// Computes and returns standard deviation of `values`.
stddev<T: NumberType, D: Details<T>>(values: &[D], simple_stat: &SimpleStat<T>) -> f64188*bb4ee6a4SAndroid Build Coastguard Worker fn stddev<T: NumberType, D: Details<T>>(values: &[D], simple_stat: &SimpleStat<T>) -> f64 {
189*bb4ee6a4SAndroid Build Coastguard Worker let avg = simple_stat.sum().unwrap().as_f64() / simple_stat.count() as f64;
190*bb4ee6a4SAndroid Build Coastguard Worker (values
191*bb4ee6a4SAndroid Build Coastguard Worker .iter()
192*bb4ee6a4SAndroid Build Coastguard Worker .map(|value| {
193*bb4ee6a4SAndroid Build Coastguard Worker let diff = avg - (value.value().as_f64());
194*bb4ee6a4SAndroid Build Coastguard Worker diff * diff
195*bb4ee6a4SAndroid Build Coastguard Worker })
196*bb4ee6a4SAndroid Build Coastguard Worker .sum::<f64>()
197*bb4ee6a4SAndroid Build Coastguard Worker / simple_stat.count as f64)
198*bb4ee6a4SAndroid Build Coastguard Worker .sqrt()
199*bb4ee6a4SAndroid Build Coastguard Worker }
200*bb4ee6a4SAndroid Build Coastguard Worker
201*bb4ee6a4SAndroid Build Coastguard Worker /// Buckets of an histogram.
202*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)]
203*bb4ee6a4SAndroid Build Coastguard Worker struct Bucket<T: NumberType> {
204*bb4ee6a4SAndroid Build Coastguard Worker simple_stat: SimpleStat<T>,
205*bb4ee6a4SAndroid Build Coastguard Worker range: Range<T>,
206*bb4ee6a4SAndroid Build Coastguard Worker }
207*bb4ee6a4SAndroid Build Coastguard Worker
208*bb4ee6a4SAndroid Build Coastguard Worker impl<T: NumberType> Bucket<T> {
new(range: Range<T>) -> Self209*bb4ee6a4SAndroid Build Coastguard Worker fn new(range: Range<T>) -> Self {
210*bb4ee6a4SAndroid Build Coastguard Worker Self {
211*bb4ee6a4SAndroid Build Coastguard Worker simple_stat: SimpleStat::default(),
212*bb4ee6a4SAndroid Build Coastguard Worker range,
213*bb4ee6a4SAndroid Build Coastguard Worker }
214*bb4ee6a4SAndroid Build Coastguard Worker }
215*bb4ee6a4SAndroid Build Coastguard Worker
add(&mut self, value: T)216*bb4ee6a4SAndroid Build Coastguard Worker fn add(&mut self, value: T) {
217*bb4ee6a4SAndroid Build Coastguard Worker self.simple_stat.add(value);
218*bb4ee6a4SAndroid Build Coastguard Worker }
219*bb4ee6a4SAndroid Build Coastguard Worker }
220*bb4ee6a4SAndroid Build Coastguard Worker
221*bb4ee6a4SAndroid Build Coastguard Worker /// A histogram that optionally holds details about each added value. These values let
222*bb4ee6a4SAndroid Build Coastguard Worker /// us compute standard deviation and median.
223*bb4ee6a4SAndroid Build Coastguard Worker pub struct DetailedHistogram<T: NumberType, D: Details<T>> {
224*bb4ee6a4SAndroid Build Coastguard Worker buckets: Vec<Bucket<T>>,
225*bb4ee6a4SAndroid Build Coastguard Worker values: Option<Vec<D>>,
226*bb4ee6a4SAndroid Build Coastguard Worker }
227*bb4ee6a4SAndroid Build Coastguard Worker
228*bb4ee6a4SAndroid Build Coastguard Worker impl<T: NumberType, D: Details<T>> Debug for DetailedHistogram<T, D> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result229*bb4ee6a4SAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230*bb4ee6a4SAndroid Build Coastguard Worker let mut dbg = f.debug_struct("DetailedHistogram");
231*bb4ee6a4SAndroid Build Coastguard Worker let simple_stat = self.simple_stat();
232*bb4ee6a4SAndroid Build Coastguard Worker dbg.field("simple_stats", &simple_stat);
233*bb4ee6a4SAndroid Build Coastguard Worker if simple_stat.count > 0 {
234*bb4ee6a4SAndroid Build Coastguard Worker if let Some(values) = &self.values {
235*bb4ee6a4SAndroid Build Coastguard Worker dbg.field("median", &median(values));
236*bb4ee6a4SAndroid Build Coastguard Worker dbg.field("std_dev", &stddev(values, &simple_stat));
237*bb4ee6a4SAndroid Build Coastguard Worker dbg.field("values", values);
238*bb4ee6a4SAndroid Build Coastguard Worker }
239*bb4ee6a4SAndroid Build Coastguard Worker }
240*bb4ee6a4SAndroid Build Coastguard Worker dbg.field("buckets", &self.buckets);
241*bb4ee6a4SAndroid Build Coastguard Worker dbg.finish()
242*bb4ee6a4SAndroid Build Coastguard Worker }
243*bb4ee6a4SAndroid Build Coastguard Worker }
244*bb4ee6a4SAndroid Build Coastguard Worker
245*bb4ee6a4SAndroid Build Coastguard Worker impl<T: NumberType, D: Details<T>> DetailedHistogram<T, D> {
new_internal(ranges: &[Range<T>], details: bool) -> Result<Self>246*bb4ee6a4SAndroid Build Coastguard Worker fn new_internal(ranges: &[Range<T>], details: bool) -> Result<Self> {
247*bb4ee6a4SAndroid Build Coastguard Worker let mut last = T::absolute_min();
248*bb4ee6a4SAndroid Build Coastguard Worker let mut buckets = vec![];
249*bb4ee6a4SAndroid Build Coastguard Worker for r in ranges {
250*bb4ee6a4SAndroid Build Coastguard Worker if r.start > r.end {
251*bb4ee6a4SAndroid Build Coastguard Worker return Err(anyhow!("invalid range {:?}", r));
252*bb4ee6a4SAndroid Build Coastguard Worker }
253*bb4ee6a4SAndroid Build Coastguard Worker
254*bb4ee6a4SAndroid Build Coastguard Worker if r.start < last {
255*bb4ee6a4SAndroid Build Coastguard Worker return Err(anyhow!("Ranges overlap {:?} ", r));
256*bb4ee6a4SAndroid Build Coastguard Worker }
257*bb4ee6a4SAndroid Build Coastguard Worker last = r.end.clone();
258*bb4ee6a4SAndroid Build Coastguard Worker buckets.push(Bucket::new(r.clone()));
259*bb4ee6a4SAndroid Build Coastguard Worker }
260*bb4ee6a4SAndroid Build Coastguard Worker let values = if details { Some(vec![]) } else { None };
261*bb4ee6a4SAndroid Build Coastguard Worker
262*bb4ee6a4SAndroid Build Coastguard Worker Ok(Self { buckets, values })
263*bb4ee6a4SAndroid Build Coastguard Worker }
264*bb4ee6a4SAndroid Build Coastguard Worker
265*bb4ee6a4SAndroid Build Coastguard Worker /// Creates an histogram with given ranges of buckets.
new(ranges: &[Range<T>]) -> Result<Self>266*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(ranges: &[Range<T>]) -> Result<Self> {
267*bb4ee6a4SAndroid Build Coastguard Worker Self::new_internal(ranges, false)
268*bb4ee6a4SAndroid Build Coastguard Worker }
269*bb4ee6a4SAndroid Build Coastguard Worker
270*bb4ee6a4SAndroid Build Coastguard Worker /// Creating a histogram that maintains details about all the events can
271*bb4ee6a4SAndroid Build Coastguard Worker /// get expensive if the events are frequent. Hence this feature is for
272*bb4ee6a4SAndroid Build Coastguard Worker /// debug builds only.
273*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "experimental")]
new_with_details(ranges: &[Range<T>]) -> Result<Self>274*bb4ee6a4SAndroid Build Coastguard Worker pub fn new_with_details(ranges: &[Range<T>]) -> Result<Self> {
275*bb4ee6a4SAndroid Build Coastguard Worker Self::new_internal(ranges, true)
276*bb4ee6a4SAndroid Build Coastguard Worker }
277*bb4ee6a4SAndroid Build Coastguard Worker
278*bb4ee6a4SAndroid Build Coastguard Worker /// Adds a value to histogram.
add(&mut self, value: D) -> Result<()>279*bb4ee6a4SAndroid Build Coastguard Worker pub fn add(&mut self, value: D) -> Result<()> {
280*bb4ee6a4SAndroid Build Coastguard Worker for b in &mut self.buckets {
281*bb4ee6a4SAndroid Build Coastguard Worker if value.value() >= b.range.start && value.value() < b.range.end {
282*bb4ee6a4SAndroid Build Coastguard Worker b.add(value.value());
283*bb4ee6a4SAndroid Build Coastguard Worker if let Some(values) = &mut self.values {
284*bb4ee6a4SAndroid Build Coastguard Worker values.push(value);
285*bb4ee6a4SAndroid Build Coastguard Worker }
286*bb4ee6a4SAndroid Build Coastguard Worker return Ok(());
287*bb4ee6a4SAndroid Build Coastguard Worker }
288*bb4ee6a4SAndroid Build Coastguard Worker }
289*bb4ee6a4SAndroid Build Coastguard Worker Err(anyhow!(
290*bb4ee6a4SAndroid Build Coastguard Worker "value does not fit in any buckets: {:?}",
291*bb4ee6a4SAndroid Build Coastguard Worker value.value()
292*bb4ee6a4SAndroid Build Coastguard Worker ))
293*bb4ee6a4SAndroid Build Coastguard Worker }
294*bb4ee6a4SAndroid Build Coastguard Worker
295*bb4ee6a4SAndroid Build Coastguard Worker /// Returns simple stat for the histogram.
simple_stat(&self) -> SimpleStat<T>296*bb4ee6a4SAndroid Build Coastguard Worker pub fn simple_stat(&self) -> SimpleStat<T> {
297*bb4ee6a4SAndroid Build Coastguard Worker let count = self.count();
298*bb4ee6a4SAndroid Build Coastguard Worker if count == 0 {
299*bb4ee6a4SAndroid Build Coastguard Worker SimpleStat::default()
300*bb4ee6a4SAndroid Build Coastguard Worker } else {
301*bb4ee6a4SAndroid Build Coastguard Worker SimpleStat {
302*bb4ee6a4SAndroid Build Coastguard Worker count: self.count(),
303*bb4ee6a4SAndroid Build Coastguard Worker sum: self.sum().unwrap(),
304*bb4ee6a4SAndroid Build Coastguard Worker min: self.min().unwrap(),
305*bb4ee6a4SAndroid Build Coastguard Worker max: self.max().unwrap(),
306*bb4ee6a4SAndroid Build Coastguard Worker }
307*bb4ee6a4SAndroid Build Coastguard Worker }
308*bb4ee6a4SAndroid Build Coastguard Worker }
309*bb4ee6a4SAndroid Build Coastguard Worker }
310*bb4ee6a4SAndroid Build Coastguard Worker
311*bb4ee6a4SAndroid Build Coastguard Worker impl<T: NumberType, D: Details<T>> SummaryStats<T> for DetailedHistogram<T, D> {
count(&self) -> u64312*bb4ee6a4SAndroid Build Coastguard Worker fn count(&self) -> u64 {
313*bb4ee6a4SAndroid Build Coastguard Worker let mut count = 0;
314*bb4ee6a4SAndroid Build Coastguard Worker for b in &self.buckets {
315*bb4ee6a4SAndroid Build Coastguard Worker count += b.simple_stat.count();
316*bb4ee6a4SAndroid Build Coastguard Worker }
317*bb4ee6a4SAndroid Build Coastguard Worker count
318*bb4ee6a4SAndroid Build Coastguard Worker }
319*bb4ee6a4SAndroid Build Coastguard Worker
sum(&self) -> Option<T>320*bb4ee6a4SAndroid Build Coastguard Worker fn sum(&self) -> Option<T> {
321*bb4ee6a4SAndroid Build Coastguard Worker let mut sum = T::absolute_min();
322*bb4ee6a4SAndroid Build Coastguard Worker let mut ret = None;
323*bb4ee6a4SAndroid Build Coastguard Worker for b in &self.buckets {
324*bb4ee6a4SAndroid Build Coastguard Worker if let Some(v) = b.simple_stat.sum() {
325*bb4ee6a4SAndroid Build Coastguard Worker sum = sum.clone() + v;
326*bb4ee6a4SAndroid Build Coastguard Worker ret = Some(sum.clone())
327*bb4ee6a4SAndroid Build Coastguard Worker }
328*bb4ee6a4SAndroid Build Coastguard Worker }
329*bb4ee6a4SAndroid Build Coastguard Worker ret
330*bb4ee6a4SAndroid Build Coastguard Worker }
331*bb4ee6a4SAndroid Build Coastguard Worker
min(&self) -> Option<T>332*bb4ee6a4SAndroid Build Coastguard Worker fn min(&self) -> Option<T> {
333*bb4ee6a4SAndroid Build Coastguard Worker for b in &self.buckets {
334*bb4ee6a4SAndroid Build Coastguard Worker let min = b.simple_stat.min();
335*bb4ee6a4SAndroid Build Coastguard Worker if min.is_some() {
336*bb4ee6a4SAndroid Build Coastguard Worker return min;
337*bb4ee6a4SAndroid Build Coastguard Worker }
338*bb4ee6a4SAndroid Build Coastguard Worker }
339*bb4ee6a4SAndroid Build Coastguard Worker None
340*bb4ee6a4SAndroid Build Coastguard Worker }
341*bb4ee6a4SAndroid Build Coastguard Worker
max(&self) -> Option<T>342*bb4ee6a4SAndroid Build Coastguard Worker fn max(&self) -> Option<T> {
343*bb4ee6a4SAndroid Build Coastguard Worker for b in self.buckets.iter().rev() {
344*bb4ee6a4SAndroid Build Coastguard Worker let max = b.simple_stat.max();
345*bb4ee6a4SAndroid Build Coastguard Worker if max.is_some() {
346*bb4ee6a4SAndroid Build Coastguard Worker return max;
347*bb4ee6a4SAndroid Build Coastguard Worker }
348*bb4ee6a4SAndroid Build Coastguard Worker }
349*bb4ee6a4SAndroid Build Coastguard Worker None
350*bb4ee6a4SAndroid Build Coastguard Worker }
351*bb4ee6a4SAndroid Build Coastguard Worker
average(&self) -> Option<T>352*bb4ee6a4SAndroid Build Coastguard Worker fn average(&self) -> Option<T> {
353*bb4ee6a4SAndroid Build Coastguard Worker let mut count = 0;
354*bb4ee6a4SAndroid Build Coastguard Worker let mut sum = T::absolute_min();
355*bb4ee6a4SAndroid Build Coastguard Worker for b in &self.buckets {
356*bb4ee6a4SAndroid Build Coastguard Worker if b.simple_stat.count != 0 {
357*bb4ee6a4SAndroid Build Coastguard Worker sum = sum + b.simple_stat.sum().unwrap();
358*bb4ee6a4SAndroid Build Coastguard Worker count += b.simple_stat.count();
359*bb4ee6a4SAndroid Build Coastguard Worker }
360*bb4ee6a4SAndroid Build Coastguard Worker }
361*bb4ee6a4SAndroid Build Coastguard Worker if count != 0 {
362*bb4ee6a4SAndroid Build Coastguard Worker Some(sum / count)
363*bb4ee6a4SAndroid Build Coastguard Worker } else {
364*bb4ee6a4SAndroid Build Coastguard Worker None
365*bb4ee6a4SAndroid Build Coastguard Worker }
366*bb4ee6a4SAndroid Build Coastguard Worker }
367*bb4ee6a4SAndroid Build Coastguard Worker }
368*bb4ee6a4SAndroid Build Coastguard Worker
369*bb4ee6a4SAndroid Build Coastguard Worker /// A helper type alias for Histogram that doesn't store details.
370*bb4ee6a4SAndroid Build Coastguard Worker /// The structure can be used in production without much memory penalty.
371*bb4ee6a4SAndroid Build Coastguard Worker pub type Histogram<T> = DetailedHistogram<T, T>;
372*bb4ee6a4SAndroid Build Coastguard Worker
373*bb4ee6a4SAndroid Build Coastguard Worker /// A helper struct that makes it easy to get time spent in a scope.
374*bb4ee6a4SAndroid Build Coastguard Worker pub struct CallOnDrop<V, F: ?Sized + Fn(&V)> {
375*bb4ee6a4SAndroid Build Coastguard Worker init_value: V,
376*bb4ee6a4SAndroid Build Coastguard Worker update_value: F,
377*bb4ee6a4SAndroid Build Coastguard Worker }
378*bb4ee6a4SAndroid Build Coastguard Worker
379*bb4ee6a4SAndroid Build Coastguard Worker impl<V, F: Fn(&V)> CallOnDrop<V, F> {
new(init_value: V, update_value: F) -> Self380*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(init_value: V, update_value: F) -> Self {
381*bb4ee6a4SAndroid Build Coastguard Worker Self {
382*bb4ee6a4SAndroid Build Coastguard Worker init_value,
383*bb4ee6a4SAndroid Build Coastguard Worker update_value,
384*bb4ee6a4SAndroid Build Coastguard Worker }
385*bb4ee6a4SAndroid Build Coastguard Worker }
386*bb4ee6a4SAndroid Build Coastguard Worker }
387*bb4ee6a4SAndroid Build Coastguard Worker
388*bb4ee6a4SAndroid Build Coastguard Worker impl<V, F: ?Sized + Fn(&V)> Drop for CallOnDrop<V, F> {
drop(&mut self)389*bb4ee6a4SAndroid Build Coastguard Worker fn drop(&mut self) {
390*bb4ee6a4SAndroid Build Coastguard Worker let f = &(self.update_value);
391*bb4ee6a4SAndroid Build Coastguard Worker f(&self.init_value);
392*bb4ee6a4SAndroid Build Coastguard Worker }
393*bb4ee6a4SAndroid Build Coastguard Worker }
394*bb4ee6a4SAndroid Build Coastguard Worker
timed_scope( histogram: Arc<Mutex<DetailedHistogram<u64, u64>>>, ) -> CallOnDrop< (Arc<Mutex<DetailedHistogram<u64, u64>>>, Instant), fn(&(Arc<Mutex<DetailedHistogram<u64, u64>>>, Instant)), >395*bb4ee6a4SAndroid Build Coastguard Worker pub fn timed_scope(
396*bb4ee6a4SAndroid Build Coastguard Worker histogram: Arc<Mutex<DetailedHistogram<u64, u64>>>,
397*bb4ee6a4SAndroid Build Coastguard Worker ) -> CallOnDrop<
398*bb4ee6a4SAndroid Build Coastguard Worker (Arc<Mutex<DetailedHistogram<u64, u64>>>, Instant),
399*bb4ee6a4SAndroid Build Coastguard Worker fn(&(Arc<Mutex<DetailedHistogram<u64, u64>>>, Instant)),
400*bb4ee6a4SAndroid Build Coastguard Worker > {
401*bb4ee6a4SAndroid Build Coastguard Worker CallOnDrop::new((histogram, Instant::now()), |(histogram, x)| {
402*bb4ee6a4SAndroid Build Coastguard Worker if histogram.lock().add(x.elapsed().as_nanos() as u64).is_err() {
403*bb4ee6a4SAndroid Build Coastguard Worker info!("Error adding timed scope stat");
404*bb4ee6a4SAndroid Build Coastguard Worker }
405*bb4ee6a4SAndroid Build Coastguard Worker })
406*bb4ee6a4SAndroid Build Coastguard Worker }
407*bb4ee6a4SAndroid Build Coastguard Worker
408*bb4ee6a4SAndroid Build Coastguard Worker /// A helper struct to collect metrics for byte transferred and latency.
409*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)]
410*bb4ee6a4SAndroid Build Coastguard Worker pub struct BytesLatencyStats {
411*bb4ee6a4SAndroid Build Coastguard Worker /// Collects latency related metrics. The unit, u64, is large enough to hold nano-second
412*bb4ee6a4SAndroid Build Coastguard Worker /// granularity.
413*bb4ee6a4SAndroid Build Coastguard Worker pub latency: DetailedHistogram<u64, u64>,
414*bb4ee6a4SAndroid Build Coastguard Worker /// Collects bytes transferred metrics. The unit, u64, is large enough to hold byte level
415*bb4ee6a4SAndroid Build Coastguard Worker /// offset and length.
416*bb4ee6a4SAndroid Build Coastguard Worker pub bytes_transferred: DetailedHistogram<u64, Range<u64>>,
417*bb4ee6a4SAndroid Build Coastguard Worker }
418*bb4ee6a4SAndroid Build Coastguard Worker
419*bb4ee6a4SAndroid Build Coastguard Worker impl BytesLatencyStats {
new_with_buckets(latency_buckets: &[Range<u64>], bytes_buckets: &[Range<u64>]) -> Self420*bb4ee6a4SAndroid Build Coastguard Worker pub fn new_with_buckets(latency_buckets: &[Range<u64>], bytes_buckets: &[Range<u64>]) -> Self {
421*bb4ee6a4SAndroid Build Coastguard Worker Self {
422*bb4ee6a4SAndroid Build Coastguard Worker latency: DetailedHistogram::new(latency_buckets).unwrap(),
423*bb4ee6a4SAndroid Build Coastguard Worker bytes_transferred: DetailedHistogram::new(bytes_buckets).unwrap(),
424*bb4ee6a4SAndroid Build Coastguard Worker }
425*bb4ee6a4SAndroid Build Coastguard Worker }
426*bb4ee6a4SAndroid Build Coastguard Worker }
427*bb4ee6a4SAndroid Build Coastguard Worker
428*bb4ee6a4SAndroid Build Coastguard Worker pub trait GetStatsForOp<OperationType> {
get_stats_for_op(&mut self, op: OperationType) -> &mut BytesLatencyStats429*bb4ee6a4SAndroid Build Coastguard Worker fn get_stats_for_op(&mut self, op: OperationType) -> &mut BytesLatencyStats;
430*bb4ee6a4SAndroid Build Coastguard Worker }
431*bb4ee6a4SAndroid Build Coastguard Worker
432*bb4ee6a4SAndroid Build Coastguard Worker /// A generic struct that temporarily holds reference of a `Stats` to update details for an
433*bb4ee6a4SAndroid Build Coastguard Worker /// operation of type `OperationType` when the instance of `OpInfo` is dropped.
434*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(test, feature = "collect"))]
435*bb4ee6a4SAndroid Build Coastguard Worker pub struct OpInfo<Stats, OperationType> {
436*bb4ee6a4SAndroid Build Coastguard Worker stats: Arc<Mutex<Stats>>,
437*bb4ee6a4SAndroid Build Coastguard Worker io_range: Range<u64>,
438*bb4ee6a4SAndroid Build Coastguard Worker operation: OperationType,
439*bb4ee6a4SAndroid Build Coastguard Worker start_time: Instant,
440*bb4ee6a4SAndroid Build Coastguard Worker }
441*bb4ee6a4SAndroid Build Coastguard Worker
442*bb4ee6a4SAndroid Build Coastguard Worker /// Helper routine to collect byte latency stat.
443*bb4ee6a4SAndroid Build Coastguard Worker ///
444*bb4ee6a4SAndroid Build Coastguard Worker /// The mutex protecting `Stats` is not held across operation but is only held to
445*bb4ee6a4SAndroid Build Coastguard Worker /// update the stats atomically. The order of events is
446*bb4ee6a4SAndroid Build Coastguard Worker /// # get `start_time`
447*bb4ee6a4SAndroid Build Coastguard Worker /// # caller performs the operation like read(), write(), etc.
448*bb4ee6a4SAndroid Build Coastguard Worker /// # hold the stats lock
449*bb4ee6a4SAndroid Build Coastguard Worker /// # update the stats
450*bb4ee6a4SAndroid Build Coastguard Worker /// # drop the lock
451*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(test, feature = "collect"))]
collect_scoped_byte_latency_stat< Stats: GetStatsForOp<OperationType> + Debug, OperationType: Copy + Clone + Debug, >( stats: Arc<Mutex<Stats>>, io_range: Range<u64>, operation: OperationType, ) -> CallOnDrop<OpInfo<Stats, OperationType>, fn(&OpInfo<Stats, OperationType>)>452*bb4ee6a4SAndroid Build Coastguard Worker pub fn collect_scoped_byte_latency_stat<
453*bb4ee6a4SAndroid Build Coastguard Worker Stats: GetStatsForOp<OperationType> + Debug,
454*bb4ee6a4SAndroid Build Coastguard Worker OperationType: Copy + Clone + Debug,
455*bb4ee6a4SAndroid Build Coastguard Worker >(
456*bb4ee6a4SAndroid Build Coastguard Worker stats: Arc<Mutex<Stats>>,
457*bb4ee6a4SAndroid Build Coastguard Worker io_range: Range<u64>,
458*bb4ee6a4SAndroid Build Coastguard Worker operation: OperationType,
459*bb4ee6a4SAndroid Build Coastguard Worker ) -> CallOnDrop<OpInfo<Stats, OperationType>, fn(&OpInfo<Stats, OperationType>)> {
460*bb4ee6a4SAndroid Build Coastguard Worker let info = OpInfo {
461*bb4ee6a4SAndroid Build Coastguard Worker stats,
462*bb4ee6a4SAndroid Build Coastguard Worker io_range,
463*bb4ee6a4SAndroid Build Coastguard Worker operation,
464*bb4ee6a4SAndroid Build Coastguard Worker start_time: Instant::now(),
465*bb4ee6a4SAndroid Build Coastguard Worker };
466*bb4ee6a4SAndroid Build Coastguard Worker CallOnDrop::new(info, |info| {
467*bb4ee6a4SAndroid Build Coastguard Worker let mut stats = info.stats.lock();
468*bb4ee6a4SAndroid Build Coastguard Worker let op_stats = stats.get_stats_for_op(info.operation);
469*bb4ee6a4SAndroid Build Coastguard Worker
470*bb4ee6a4SAndroid Build Coastguard Worker if op_stats
471*bb4ee6a4SAndroid Build Coastguard Worker .latency
472*bb4ee6a4SAndroid Build Coastguard Worker .add(info.start_time.elapsed().as_nanos() as u64)
473*bb4ee6a4SAndroid Build Coastguard Worker .is_err()
474*bb4ee6a4SAndroid Build Coastguard Worker {
475*bb4ee6a4SAndroid Build Coastguard Worker info!("Error adding disk IO latency stat");
476*bb4ee6a4SAndroid Build Coastguard Worker }
477*bb4ee6a4SAndroid Build Coastguard Worker
478*bb4ee6a4SAndroid Build Coastguard Worker if op_stats
479*bb4ee6a4SAndroid Build Coastguard Worker .bytes_transferred
480*bb4ee6a4SAndroid Build Coastguard Worker .add(info.io_range.clone())
481*bb4ee6a4SAndroid Build Coastguard Worker .is_err()
482*bb4ee6a4SAndroid Build Coastguard Worker {
483*bb4ee6a4SAndroid Build Coastguard Worker info!("Error adding disk IO bytes transferred stat");
484*bb4ee6a4SAndroid Build Coastguard Worker }
485*bb4ee6a4SAndroid Build Coastguard Worker })
486*bb4ee6a4SAndroid Build Coastguard Worker }
487*bb4ee6a4SAndroid Build Coastguard Worker
488*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(all(not(test), not(feature = "collect")))]
489*bb4ee6a4SAndroid Build Coastguard Worker pub struct OpInfo {}
490*bb4ee6a4SAndroid Build Coastguard Worker
491*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(all(not(test), not(feature = "collect")))]
collect_scoped_byte_latency_stat< Stats: GetStatsForOp<OperationType> + Debug, OperationType: Copy + Clone + Debug, >( _stats: Arc<Mutex<Stats>>, _io_range: Range<u64>, _operation: OperationType, ) -> OpInfo492*bb4ee6a4SAndroid Build Coastguard Worker pub fn collect_scoped_byte_latency_stat<
493*bb4ee6a4SAndroid Build Coastguard Worker Stats: GetStatsForOp<OperationType> + Debug,
494*bb4ee6a4SAndroid Build Coastguard Worker OperationType: Copy + Clone + Debug,
495*bb4ee6a4SAndroid Build Coastguard Worker >(
496*bb4ee6a4SAndroid Build Coastguard Worker _stats: Arc<Mutex<Stats>>,
497*bb4ee6a4SAndroid Build Coastguard Worker _io_range: Range<u64>,
498*bb4ee6a4SAndroid Build Coastguard Worker _operation: OperationType,
499*bb4ee6a4SAndroid Build Coastguard Worker ) -> OpInfo {
500*bb4ee6a4SAndroid Build Coastguard Worker OpInfo {}
501*bb4ee6a4SAndroid Build Coastguard Worker }
502*bb4ee6a4SAndroid Build Coastguard Worker
503*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
504*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
505*bb4ee6a4SAndroid Build Coastguard Worker
506*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
507*bb4ee6a4SAndroid Build Coastguard Worker
508*bb4ee6a4SAndroid Build Coastguard Worker use super::*;
509*bb4ee6a4SAndroid Build Coastguard Worker
510*bb4ee6a4SAndroid Build Coastguard Worker #[test]
simple_stat_init()511*bb4ee6a4SAndroid Build Coastguard Worker fn simple_stat_init() {
512*bb4ee6a4SAndroid Build Coastguard Worker let x = SimpleStat::<u64>::default();
513*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.count, 0);
514*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.max(), None);
515*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.min(), None);
516*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.average(), None);
517*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.sum(), None);
518*bb4ee6a4SAndroid Build Coastguard Worker }
519*bb4ee6a4SAndroid Build Coastguard Worker
520*bb4ee6a4SAndroid Build Coastguard Worker #[test]
simple_stat_updates()521*bb4ee6a4SAndroid Build Coastguard Worker fn simple_stat_updates() {
522*bb4ee6a4SAndroid Build Coastguard Worker let mut x = SimpleStat::<u64>::default();
523*bb4ee6a4SAndroid Build Coastguard Worker x.add(10);
524*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.count, 1);
525*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.max(), Some(10));
526*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.min(), Some(10));
527*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.average(), Some(10));
528*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.sum(), Some(10));
529*bb4ee6a4SAndroid Build Coastguard Worker x.add(2);
530*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.count, 2);
531*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.max(), Some(10));
532*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.min(), Some(2));
533*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.average(), Some(6));
534*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.sum(), Some(12));
535*bb4ee6a4SAndroid Build Coastguard Worker x.add(1);
536*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.count, 3);
537*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.max(), Some(10));
538*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.min(), Some(1));
539*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.average(), Some(4));
540*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.sum(), Some(13));
541*bb4ee6a4SAndroid Build Coastguard Worker x.add(0);
542*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.count, 4);
543*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.max(), Some(10));
544*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.min(), Some(0));
545*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.average(), Some(3));
546*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(x.sum(), Some(13));
547*bb4ee6a4SAndroid Build Coastguard Worker }
548*bb4ee6a4SAndroid Build Coastguard Worker
bucket_check(bucket: &Bucket<u64>, values: &[u64])549*bb4ee6a4SAndroid Build Coastguard Worker fn bucket_check(bucket: &Bucket<u64>, values: &[u64]) {
550*bb4ee6a4SAndroid Build Coastguard Worker let mut stats = SimpleStat::default();
551*bb4ee6a4SAndroid Build Coastguard Worker for v in values {
552*bb4ee6a4SAndroid Build Coastguard Worker stats.add(*v);
553*bb4ee6a4SAndroid Build Coastguard Worker }
554*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(bucket.simple_stat.count(), stats.count());
555*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(bucket.simple_stat.sum(), stats.sum());
556*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(bucket.simple_stat.min(), stats.min());
557*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(bucket.simple_stat.max(), stats.max());
558*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(bucket.simple_stat.average(), stats.average());
559*bb4ee6a4SAndroid Build Coastguard Worker }
560*bb4ee6a4SAndroid Build Coastguard Worker
561*bb4ee6a4SAndroid Build Coastguard Worker #[test]
histogram_without_details()562*bb4ee6a4SAndroid Build Coastguard Worker fn histogram_without_details() {
563*bb4ee6a4SAndroid Build Coastguard Worker let mut histogram = Histogram::new(&[0..10, 10..100, 100..200]).unwrap();
564*bb4ee6a4SAndroid Build Coastguard Worker
565*bb4ee6a4SAndroid Build Coastguard Worker let mut simple_stats = SimpleStat::default();
566*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.simple_stat(), simple_stats);
567*bb4ee6a4SAndroid Build Coastguard Worker let values = [0, 20, 199, 50, 9, 5, 120];
568*bb4ee6a4SAndroid Build Coastguard Worker
569*bb4ee6a4SAndroid Build Coastguard Worker for v in values {
570*bb4ee6a4SAndroid Build Coastguard Worker histogram.add(v).unwrap();
571*bb4ee6a4SAndroid Build Coastguard Worker simple_stats.add(v);
572*bb4ee6a4SAndroid Build Coastguard Worker }
573*bb4ee6a4SAndroid Build Coastguard Worker
574*bb4ee6a4SAndroid Build Coastguard Worker bucket_check(&histogram.buckets[0], &[0, 9, 5]);
575*bb4ee6a4SAndroid Build Coastguard Worker bucket_check(&histogram.buckets[1], &[20, 50]);
576*bb4ee6a4SAndroid Build Coastguard Worker bucket_check(&histogram.buckets[2], &[199, 120]);
577*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.buckets.len(), 3);
578*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.simple_stat(), simple_stats);
579*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.values, None);
580*bb4ee6a4SAndroid Build Coastguard Worker }
581*bb4ee6a4SAndroid Build Coastguard Worker
582*bb4ee6a4SAndroid Build Coastguard Worker #[test]
histogram_without_details_empty_first_last_buckets()583*bb4ee6a4SAndroid Build Coastguard Worker fn histogram_without_details_empty_first_last_buckets() {
584*bb4ee6a4SAndroid Build Coastguard Worker let mut histogram = Histogram::new(&[0..4, 4..10, 10..100, 100..200, 200..300]).unwrap();
585*bb4ee6a4SAndroid Build Coastguard Worker
586*bb4ee6a4SAndroid Build Coastguard Worker let mut simple_stats = SimpleStat::default();
587*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.simple_stat(), simple_stats);
588*bb4ee6a4SAndroid Build Coastguard Worker let values = [4, 20, 199, 50, 9, 5, 120];
589*bb4ee6a4SAndroid Build Coastguard Worker
590*bb4ee6a4SAndroid Build Coastguard Worker for v in values {
591*bb4ee6a4SAndroid Build Coastguard Worker histogram.add(v).unwrap();
592*bb4ee6a4SAndroid Build Coastguard Worker simple_stats.add(v);
593*bb4ee6a4SAndroid Build Coastguard Worker }
594*bb4ee6a4SAndroid Build Coastguard Worker
595*bb4ee6a4SAndroid Build Coastguard Worker bucket_check(&histogram.buckets[1], &[4, 9, 5]);
596*bb4ee6a4SAndroid Build Coastguard Worker bucket_check(&histogram.buckets[2], &[20, 50]);
597*bb4ee6a4SAndroid Build Coastguard Worker bucket_check(&histogram.buckets[3], &[199, 120]);
598*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.buckets.len(), 5);
599*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.simple_stat(), simple_stats);
600*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.values, None);
601*bb4ee6a4SAndroid Build Coastguard Worker }
602*bb4ee6a4SAndroid Build Coastguard Worker
603*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "experimental")]
604*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Debug, PartialEq)]
605*bb4ee6a4SAndroid Build Coastguard Worker struct MyDetails(u64, u64);
606*bb4ee6a4SAndroid Build Coastguard Worker
607*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "experimental")]
608*bb4ee6a4SAndroid Build Coastguard Worker impl Details<u64> for MyDetails {
value(&self) -> u64609*bb4ee6a4SAndroid Build Coastguard Worker fn value(&self) -> u64 {
610*bb4ee6a4SAndroid Build Coastguard Worker self.1 - self.0
611*bb4ee6a4SAndroid Build Coastguard Worker }
612*bb4ee6a4SAndroid Build Coastguard Worker }
613*bb4ee6a4SAndroid Build Coastguard Worker
614*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "experimental")]
test_detailed_values() -> Vec<MyDetails>615*bb4ee6a4SAndroid Build Coastguard Worker fn test_detailed_values() -> Vec<MyDetails> {
616*bb4ee6a4SAndroid Build Coastguard Worker vec![
617*bb4ee6a4SAndroid Build Coastguard Worker MyDetails(0, 4),
618*bb4ee6a4SAndroid Build Coastguard Worker MyDetails(1, 21),
619*bb4ee6a4SAndroid Build Coastguard Worker MyDetails(2, 201),
620*bb4ee6a4SAndroid Build Coastguard Worker MyDetails(3, 53),
621*bb4ee6a4SAndroid Build Coastguard Worker MyDetails(10, 19),
622*bb4ee6a4SAndroid Build Coastguard Worker MyDetails(5, 10),
623*bb4ee6a4SAndroid Build Coastguard Worker MyDetails(120, 240),
624*bb4ee6a4SAndroid Build Coastguard Worker ]
625*bb4ee6a4SAndroid Build Coastguard Worker }
626*bb4ee6a4SAndroid Build Coastguard Worker
627*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "experimental")]
628*bb4ee6a4SAndroid Build Coastguard Worker #[test]
histogram_with_details()629*bb4ee6a4SAndroid Build Coastguard Worker fn histogram_with_details() {
630*bb4ee6a4SAndroid Build Coastguard Worker let mut histogram =
631*bb4ee6a4SAndroid Build Coastguard Worker DetailedHistogram::new_with_details(&[0..10, 10..100, 100..200]).unwrap();
632*bb4ee6a4SAndroid Build Coastguard Worker
633*bb4ee6a4SAndroid Build Coastguard Worker let mut simple_stats = SimpleStat::default();
634*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.simple_stat(), simple_stats);
635*bb4ee6a4SAndroid Build Coastguard Worker
636*bb4ee6a4SAndroid Build Coastguard Worker let values = test_detailed_values();
637*bb4ee6a4SAndroid Build Coastguard Worker
638*bb4ee6a4SAndroid Build Coastguard Worker for v in &values {
639*bb4ee6a4SAndroid Build Coastguard Worker simple_stats.add(v.value());
640*bb4ee6a4SAndroid Build Coastguard Worker histogram.add(v.clone()).unwrap();
641*bb4ee6a4SAndroid Build Coastguard Worker }
642*bb4ee6a4SAndroid Build Coastguard Worker
643*bb4ee6a4SAndroid Build Coastguard Worker bucket_check(histogram.buckets[0], &[4, 9, 5]);
644*bb4ee6a4SAndroid Build Coastguard Worker bucket_check(histogram.buckets[1], &[20, 50]);
645*bb4ee6a4SAndroid Build Coastguard Worker bucket_check(histogram.buckets[2], &[199, 120]);
646*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.buckets.len(), 3);
647*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.simple_stat(), simple_stats);
648*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.values, Some(values));
649*bb4ee6a4SAndroid Build Coastguard Worker }
650*bb4ee6a4SAndroid Build Coastguard Worker
651*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "experimental")]
652*bb4ee6a4SAndroid Build Coastguard Worker #[test]
histogram_with_details_empty_first_last_buckets()653*bb4ee6a4SAndroid Build Coastguard Worker fn histogram_with_details_empty_first_last_buckets() {
654*bb4ee6a4SAndroid Build Coastguard Worker let mut histogram =
655*bb4ee6a4SAndroid Build Coastguard Worker DetailedHistogram::new_with_details(&[0..4, 4..10, 10..100, 100..200, 200..300])
656*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
657*bb4ee6a4SAndroid Build Coastguard Worker
658*bb4ee6a4SAndroid Build Coastguard Worker let mut simple_stats = SimpleStat::default();
659*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.simple_stat(), simple_stats);
660*bb4ee6a4SAndroid Build Coastguard Worker let values = test_detailed_values();
661*bb4ee6a4SAndroid Build Coastguard Worker
662*bb4ee6a4SAndroid Build Coastguard Worker for v in &values {
663*bb4ee6a4SAndroid Build Coastguard Worker simple_stats.add(v.value());
664*bb4ee6a4SAndroid Build Coastguard Worker histogram.add(v.clone()).unwrap();
665*bb4ee6a4SAndroid Build Coastguard Worker }
666*bb4ee6a4SAndroid Build Coastguard Worker
667*bb4ee6a4SAndroid Build Coastguard Worker bucket_check(histogram.buckets[0], &[]);
668*bb4ee6a4SAndroid Build Coastguard Worker bucket_check(histogram.buckets[4], &[]);
669*bb4ee6a4SAndroid Build Coastguard Worker bucket_check(histogram.buckets[1], &[4, 9, 5]);
670*bb4ee6a4SAndroid Build Coastguard Worker bucket_check(histogram.buckets[2], &[20, 50]);
671*bb4ee6a4SAndroid Build Coastguard Worker bucket_check(histogram.buckets[3], &[199, 120]);
672*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.buckets.len(), 5);
673*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.simple_stat(), simple_stats);
674*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.values, Some(values));
675*bb4ee6a4SAndroid Build Coastguard Worker }
676*bb4ee6a4SAndroid Build Coastguard Worker
677*bb4ee6a4SAndroid Build Coastguard Worker #[test]
histogram_debug_fmt()678*bb4ee6a4SAndroid Build Coastguard Worker fn histogram_debug_fmt() {
679*bb4ee6a4SAndroid Build Coastguard Worker let range = 0..200;
680*bb4ee6a4SAndroid Build Coastguard Worker let mut histogram = Histogram::new(&[range]).unwrap();
681*bb4ee6a4SAndroid Build Coastguard Worker
682*bb4ee6a4SAndroid Build Coastguard Worker let mut simple_stats = SimpleStat::default();
683*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.simple_stat(), simple_stats);
684*bb4ee6a4SAndroid Build Coastguard Worker let values = [0, 20, 199];
685*bb4ee6a4SAndroid Build Coastguard Worker
686*bb4ee6a4SAndroid Build Coastguard Worker for v in values {
687*bb4ee6a4SAndroid Build Coastguard Worker histogram.add(v).unwrap();
688*bb4ee6a4SAndroid Build Coastguard Worker simple_stats.add(v);
689*bb4ee6a4SAndroid Build Coastguard Worker }
690*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
691*bb4ee6a4SAndroid Build Coastguard Worker format!("{:#?}", histogram),
692*bb4ee6a4SAndroid Build Coastguard Worker r#"DetailedHistogram {
693*bb4ee6a4SAndroid Build Coastguard Worker simple_stats: SimpleStat {
694*bb4ee6a4SAndroid Build Coastguard Worker count: 3,
695*bb4ee6a4SAndroid Build Coastguard Worker sum: 219,
696*bb4ee6a4SAndroid Build Coastguard Worker min: 0,
697*bb4ee6a4SAndroid Build Coastguard Worker max: 199,
698*bb4ee6a4SAndroid Build Coastguard Worker average: 73,
699*bb4ee6a4SAndroid Build Coastguard Worker },
700*bb4ee6a4SAndroid Build Coastguard Worker buckets: [
701*bb4ee6a4SAndroid Build Coastguard Worker Bucket {
702*bb4ee6a4SAndroid Build Coastguard Worker simple_stat: SimpleStat {
703*bb4ee6a4SAndroid Build Coastguard Worker count: 3,
704*bb4ee6a4SAndroid Build Coastguard Worker sum: 219,
705*bb4ee6a4SAndroid Build Coastguard Worker min: 0,
706*bb4ee6a4SAndroid Build Coastguard Worker max: 199,
707*bb4ee6a4SAndroid Build Coastguard Worker average: 73,
708*bb4ee6a4SAndroid Build Coastguard Worker },
709*bb4ee6a4SAndroid Build Coastguard Worker range: 0..200,
710*bb4ee6a4SAndroid Build Coastguard Worker },
711*bb4ee6a4SAndroid Build Coastguard Worker ],
712*bb4ee6a4SAndroid Build Coastguard Worker }"#
713*bb4ee6a4SAndroid Build Coastguard Worker );
714*bb4ee6a4SAndroid Build Coastguard Worker }
715*bb4ee6a4SAndroid Build Coastguard Worker
716*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "experimental")]
717*bb4ee6a4SAndroid Build Coastguard Worker #[test]
detailed_histogram_debug_fmt()718*bb4ee6a4SAndroid Build Coastguard Worker fn detailed_histogram_debug_fmt() {
719*bb4ee6a4SAndroid Build Coastguard Worker let mut histogram = DetailedHistogram::new_with_details(&[0..200]).unwrap();
720*bb4ee6a4SAndroid Build Coastguard Worker
721*bb4ee6a4SAndroid Build Coastguard Worker let mut simple_stats = SimpleStat::default();
722*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.simple_stat(), simple_stats);
723*bb4ee6a4SAndroid Build Coastguard Worker let values = test_detailed_values();
724*bb4ee6a4SAndroid Build Coastguard Worker
725*bb4ee6a4SAndroid Build Coastguard Worker for v in &values {
726*bb4ee6a4SAndroid Build Coastguard Worker histogram.add(v.clone()).unwrap();
727*bb4ee6a4SAndroid Build Coastguard Worker simple_stats.add(v.value());
728*bb4ee6a4SAndroid Build Coastguard Worker }
729*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
730*bb4ee6a4SAndroid Build Coastguard Worker format!("{:#?}", histogram),
731*bb4ee6a4SAndroid Build Coastguard Worker r#"DetailedHistogram {
732*bb4ee6a4SAndroid Build Coastguard Worker simple_stats: SimpleStat {
733*bb4ee6a4SAndroid Build Coastguard Worker count: 7,
734*bb4ee6a4SAndroid Build Coastguard Worker sum: 407,
735*bb4ee6a4SAndroid Build Coastguard Worker min: 4,
736*bb4ee6a4SAndroid Build Coastguard Worker max: 199,
737*bb4ee6a4SAndroid Build Coastguard Worker average: 58,
738*bb4ee6a4SAndroid Build Coastguard Worker },
739*bb4ee6a4SAndroid Build Coastguard Worker median: 20,
740*bb4ee6a4SAndroid Build Coastguard Worker std_dev: 69.03297053153779,
741*bb4ee6a4SAndroid Build Coastguard Worker values: [
742*bb4ee6a4SAndroid Build Coastguard Worker MyDetails(
743*bb4ee6a4SAndroid Build Coastguard Worker 0,
744*bb4ee6a4SAndroid Build Coastguard Worker 4,
745*bb4ee6a4SAndroid Build Coastguard Worker ),
746*bb4ee6a4SAndroid Build Coastguard Worker MyDetails(
747*bb4ee6a4SAndroid Build Coastguard Worker 1,
748*bb4ee6a4SAndroid Build Coastguard Worker 21,
749*bb4ee6a4SAndroid Build Coastguard Worker ),
750*bb4ee6a4SAndroid Build Coastguard Worker MyDetails(
751*bb4ee6a4SAndroid Build Coastguard Worker 2,
752*bb4ee6a4SAndroid Build Coastguard Worker 201,
753*bb4ee6a4SAndroid Build Coastguard Worker ),
754*bb4ee6a4SAndroid Build Coastguard Worker MyDetails(
755*bb4ee6a4SAndroid Build Coastguard Worker 3,
756*bb4ee6a4SAndroid Build Coastguard Worker 53,
757*bb4ee6a4SAndroid Build Coastguard Worker ),
758*bb4ee6a4SAndroid Build Coastguard Worker MyDetails(
759*bb4ee6a4SAndroid Build Coastguard Worker 10,
760*bb4ee6a4SAndroid Build Coastguard Worker 19,
761*bb4ee6a4SAndroid Build Coastguard Worker ),
762*bb4ee6a4SAndroid Build Coastguard Worker MyDetails(
763*bb4ee6a4SAndroid Build Coastguard Worker 5,
764*bb4ee6a4SAndroid Build Coastguard Worker 10,
765*bb4ee6a4SAndroid Build Coastguard Worker ),
766*bb4ee6a4SAndroid Build Coastguard Worker MyDetails(
767*bb4ee6a4SAndroid Build Coastguard Worker 120,
768*bb4ee6a4SAndroid Build Coastguard Worker 240,
769*bb4ee6a4SAndroid Build Coastguard Worker ),
770*bb4ee6a4SAndroid Build Coastguard Worker ],
771*bb4ee6a4SAndroid Build Coastguard Worker buckets: [
772*bb4ee6a4SAndroid Build Coastguard Worker Bucket {
773*bb4ee6a4SAndroid Build Coastguard Worker simple_stat: SimpleStat {
774*bb4ee6a4SAndroid Build Coastguard Worker count: 7,
775*bb4ee6a4SAndroid Build Coastguard Worker sum: 407,
776*bb4ee6a4SAndroid Build Coastguard Worker min: 4,
777*bb4ee6a4SAndroid Build Coastguard Worker max: 199,
778*bb4ee6a4SAndroid Build Coastguard Worker average: 58,
779*bb4ee6a4SAndroid Build Coastguard Worker },
780*bb4ee6a4SAndroid Build Coastguard Worker range: 0..200,
781*bb4ee6a4SAndroid Build Coastguard Worker },
782*bb4ee6a4SAndroid Build Coastguard Worker ],
783*bb4ee6a4SAndroid Build Coastguard Worker }"#
784*bb4ee6a4SAndroid Build Coastguard Worker );
785*bb4ee6a4SAndroid Build Coastguard Worker }
786*bb4ee6a4SAndroid Build Coastguard Worker
787*bb4ee6a4SAndroid Build Coastguard Worker #[test]
add_on_drop()788*bb4ee6a4SAndroid Build Coastguard Worker fn add_on_drop() {
789*bb4ee6a4SAndroid Build Coastguard Worker let range = 0..u64::MAX;
790*bb4ee6a4SAndroid Build Coastguard Worker let histogram = Arc::new(Mutex::new(DetailedHistogram::new(&[range]).unwrap()));
791*bb4ee6a4SAndroid Build Coastguard Worker
792*bb4ee6a4SAndroid Build Coastguard Worker {
793*bb4ee6a4SAndroid Build Coastguard Worker let _ = timed_scope(histogram.clone());
794*bb4ee6a4SAndroid Build Coastguard Worker }
795*bb4ee6a4SAndroid Build Coastguard Worker
796*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(histogram.lock().count(), 1);
797*bb4ee6a4SAndroid Build Coastguard Worker assert!(histogram.lock().sum().unwrap() > 1);
798*bb4ee6a4SAndroid Build Coastguard Worker }
799*bb4ee6a4SAndroid Build Coastguard Worker
800*bb4ee6a4SAndroid Build Coastguard Worker #[test]
disk_io_stat()801*bb4ee6a4SAndroid Build Coastguard Worker fn disk_io_stat() {
802*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)]
803*bb4ee6a4SAndroid Build Coastguard Worker struct DiskIOStats {
804*bb4ee6a4SAndroid Build Coastguard Worker read: BytesLatencyStats,
805*bb4ee6a4SAndroid Build Coastguard Worker write: BytesLatencyStats,
806*bb4ee6a4SAndroid Build Coastguard Worker }
807*bb4ee6a4SAndroid Build Coastguard Worker
808*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug)]
809*bb4ee6a4SAndroid Build Coastguard Worker enum DiskOperationType {
810*bb4ee6a4SAndroid Build Coastguard Worker Read,
811*bb4ee6a4SAndroid Build Coastguard Worker Write,
812*bb4ee6a4SAndroid Build Coastguard Worker }
813*bb4ee6a4SAndroid Build Coastguard Worker
814*bb4ee6a4SAndroid Build Coastguard Worker impl GetStatsForOp<DiskOperationType> for DiskIOStats {
815*bb4ee6a4SAndroid Build Coastguard Worker fn get_stats_for_op(&mut self, op: DiskOperationType) -> &mut BytesLatencyStats {
816*bb4ee6a4SAndroid Build Coastguard Worker match op {
817*bb4ee6a4SAndroid Build Coastguard Worker DiskOperationType::Read => &mut self.read,
818*bb4ee6a4SAndroid Build Coastguard Worker DiskOperationType::Write => &mut self.write,
819*bb4ee6a4SAndroid Build Coastguard Worker }
820*bb4ee6a4SAndroid Build Coastguard Worker }
821*bb4ee6a4SAndroid Build Coastguard Worker }
822*bb4ee6a4SAndroid Build Coastguard Worker
823*bb4ee6a4SAndroid Build Coastguard Worker let stats = Arc::new(Mutex::new(DiskIOStats {
824*bb4ee6a4SAndroid Build Coastguard Worker read: BytesLatencyStats::new_with_buckets(
825*bb4ee6a4SAndroid Build Coastguard Worker &[0..100, 100..u64::MAX],
826*bb4ee6a4SAndroid Build Coastguard Worker &[0..100, 100..u64::MAX],
827*bb4ee6a4SAndroid Build Coastguard Worker ),
828*bb4ee6a4SAndroid Build Coastguard Worker write: BytesLatencyStats::new_with_buckets(
829*bb4ee6a4SAndroid Build Coastguard Worker &[0..100, 100..u64::MAX],
830*bb4ee6a4SAndroid Build Coastguard Worker &[0..100, 100..u64::MAX],
831*bb4ee6a4SAndroid Build Coastguard Worker ),
832*bb4ee6a4SAndroid Build Coastguard Worker }));
833*bb4ee6a4SAndroid Build Coastguard Worker
834*bb4ee6a4SAndroid Build Coastguard Worker {
835*bb4ee6a4SAndroid Build Coastguard Worker let _ =
836*bb4ee6a4SAndroid Build Coastguard Worker collect_scoped_byte_latency_stat(stats.clone(), 100..1000, DiskOperationType::Read);
837*bb4ee6a4SAndroid Build Coastguard Worker std::thread::sleep(Duration::from_millis(10));
838*bb4ee6a4SAndroid Build Coastguard Worker }
839*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(stats.lock().read.latency.count(), 1);
840*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(stats.lock().read.bytes_transferred.sum(), Some(900));
841*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(stats.lock().write.latency.count(), 0);
842*bb4ee6a4SAndroid Build Coastguard Worker
843*bb4ee6a4SAndroid Build Coastguard Worker {
844*bb4ee6a4SAndroid Build Coastguard Worker let _ = collect_scoped_byte_latency_stat(
845*bb4ee6a4SAndroid Build Coastguard Worker stats.clone(),
846*bb4ee6a4SAndroid Build Coastguard Worker 200..1000,
847*bb4ee6a4SAndroid Build Coastguard Worker DiskOperationType::Write,
848*bb4ee6a4SAndroid Build Coastguard Worker );
849*bb4ee6a4SAndroid Build Coastguard Worker std::thread::sleep(Duration::from_millis(10));
850*bb4ee6a4SAndroid Build Coastguard Worker }
851*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(stats.lock().write.latency.count(), 1);
852*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(stats.lock().write.bytes_transferred.sum(), Some(800));
853*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(stats.lock().read.latency.count(), 1);
854*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(stats.lock().read.bytes_transferred.sum(), Some(900));
855*bb4ee6a4SAndroid Build Coastguard Worker }
856*bb4ee6a4SAndroid Build Coastguard Worker }
857