summary refs log tree commit diff
path: root/crosvm_plugin/src/stats.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crosvm_plugin/src/stats.rs')
-rw-r--r--crosvm_plugin/src/stats.rs84
1 files changed, 84 insertions, 0 deletions
diff --git a/crosvm_plugin/src/stats.rs b/crosvm_plugin/src/stats.rs
new file mode 100644
index 0000000..0406e2f
--- /dev/null
+++ b/crosvm_plugin/src/stats.rs
@@ -0,0 +1,84 @@
+// 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);
+        }
+    }
+}