xref: /aosp_15_r20/external/crosvm/crosvm_plugin/src/stats.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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