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