blob: 0406e2fc275e73b14e6470945e76c7c3e7beaf05 [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::Stat;
use std::time::Instant;
#[derive(Clone, Copy)]
struct StatEntry {
count: u64,
total: u64,
max: u64,
}
pub struct StatUpdater {
idx: usize,
start: Instant,
}
pub struct GlobalStats {
entries: [StatEntry; Stat::Count as usize],
}
pub static mut STATS: GlobalStats = GlobalStats {
entries: [StatEntry {
count: 0,
total: 0,
max: 0,
}; Stat::Count as usize],
};
impl GlobalStats {
// Record latency from this call until the end of block/function
// Example:
// pub fn foo() {
// let _u = STATS.record(Stat::Foo);
// // ... some operation ...
// }
// The added STATS.record will record latency of "some operation" and will
// update max and average latencies for it under Stats::Foo. Subsequent
// call to STATS.print() will print out max and average latencies for all
// operations that were performed.
pub fn record(&mut self, idx: Stat) -> StatUpdater {
StatUpdater {
idx: idx as usize,
start: Instant::now(),
}
}
pub fn print(&self) {
for idx in 0..Stat::Count as usize {
let e = &self.entries[idx as usize];
let stat = unsafe { std::mem::transmute::<u8, Stat>(idx as u8) };
if e.count > 0 {
println!(
"Stat::{:?}: avg {}ns max {}ns",
stat,
e.total / e.count,
e.max
);
}
}
}
fn update(&mut self, idx: usize, elapsed_nanos: u64) {
let e = &mut self.entries[idx as usize];
e.total += elapsed_nanos;
if e.max < elapsed_nanos {
e.max = elapsed_nanos;
}
e.count += 1;
}
}
impl Drop for StatUpdater {
fn drop(&mut self) {
let elapsed = self.start.elapsed();
let elapsed_nanos = elapsed.as_secs() * 1000000000 + elapsed.subsec_nanos() as u64;
// Unsafe due to racy access - OK for stats
unsafe {
STATS.update(self.idx, elapsed_nanos);
}
}
}