1 // Copyright 2019 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::time::Instant; 6 7 use crate::Stat; 8 9 #[derive(Clone, Copy)] 10 struct StatEntry { 11 count: u64, 12 total: u64, 13 max: u64, 14 } 15 16 pub struct StatUpdater { 17 idx: usize, 18 start: Instant, 19 } 20 21 pub struct GlobalStats { 22 entries: [StatEntry; Stat::Count as usize], 23 } 24 25 pub static mut STATS: GlobalStats = GlobalStats { 26 entries: [StatEntry { 27 count: 0, 28 total: 0, 29 max: 0, 30 }; Stat::Count as usize], 31 }; 32 33 impl GlobalStats { 34 // Record latency from this call until the end of block/function 35 // Example: 36 // pub fn foo() { 37 // let _u = STATS.record(Stat::Foo); 38 // // ... some operation ... 39 // } 40 // The added STATS.record will record latency of "some operation" and will 41 // update max and average latencies for it under Stats::Foo. Subsequent 42 // call to STATS.print() will print out max and average latencies for all 43 // operations that were performed. record(&mut self, idx: Stat) -> StatUpdater44 pub fn record(&mut self, idx: Stat) -> StatUpdater { 45 StatUpdater { 46 idx: idx as usize, 47 start: Instant::now(), 48 } 49 } 50 print(&self)51 pub fn print(&self) { 52 for idx in 0..Stat::Count as usize { 53 let e = &self.entries[idx as usize]; 54 let stat = unsafe { std::mem::transmute::<u8, Stat>(idx as u8) }; 55 if e.count > 0 { 56 println!( 57 "Stat::{:?}: avg {}ns max {}ns", 58 stat, 59 e.total / e.count, 60 e.max 61 ); 62 } 63 } 64 } 65 update(&mut self, idx: usize, elapsed_nanos: u64)66 fn update(&mut self, idx: usize, elapsed_nanos: u64) { 67 let e = &mut self.entries[idx as usize]; 68 e.total += elapsed_nanos; 69 if e.max < elapsed_nanos { 70 e.max = elapsed_nanos; 71 } 72 e.count += 1; 73 } 74 } 75 76 impl Drop for StatUpdater { drop(&mut self)77 fn drop(&mut self) { 78 let elapsed = self.start.elapsed(); 79 let elapsed_nanos = elapsed.as_secs() * 1000000000 + elapsed.subsec_nanos() as u64; 80 // Unsafe due to racy access - OK for stats 81 unsafe { 82 STATS.update(self.idx, elapsed_nanos); 83 } 84 } 85 } 86