From fdcfd1d4398d4632333c0d3ed619539251d9986b Mon Sep 17 00:00:00 2001 From: Matt Delco Date: Tue, 1 Oct 2019 18:10:37 -0700 Subject: crosvm: compile out stats The stats are typically alive in the plugin library, but we typically don't care about or use these stats. BUG=None. TEST=Compiled and ran test. Verified release binary size got smaller by 25KB and debug by 50KB. Change-Id: I2469ff83f91a3aebf86d70807088bba3edce6641 Signed-off-by: Matt Delco Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1835034 Tested-by: kokoro Reviewed-by: Zach Reizner --- crosvm_plugin/Cargo.toml | 3 + crosvm_plugin/src/lib.rs | 196 ++++++++++++++++----------------------------- crosvm_plugin/src/stats.rs | 84 +++++++++++++++++++ 3 files changed, 156 insertions(+), 127 deletions(-) create mode 100644 crosvm_plugin/src/stats.rs (limited to 'crosvm_plugin') diff --git a/crosvm_plugin/Cargo.toml b/crosvm_plugin/Cargo.toml index 6805898..b9abc02 100644 --- a/crosvm_plugin/Cargo.toml +++ b/crosvm_plugin/Cargo.toml @@ -4,6 +4,9 @@ version = "0.17.0" authors = ["The Chromium OS Authors"] edition = "2018" +[features] +stats = [] + [lib] crate-type = ["cdylib"] diff --git a/crosvm_plugin/src/lib.rs b/crosvm_plugin/src/lib.rs index fa6ce2f..8def28d 100644 --- a/crosvm_plugin/src/lib.rs +++ b/crosvm_plugin/src/lib.rs @@ -28,7 +28,6 @@ use std::slice; use std::slice::{from_raw_parts, from_raw_parts_mut}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; -use std::time::Instant; use libc::{E2BIG, EINVAL, ENOENT, ENOTCONN, EPROTO}; @@ -46,6 +45,9 @@ use kvm_sys::{ use protos::plugin::*; +#[cfg(feature = "stats")] +mod stats; + // Needs to be large enough to receive all the VCPU sockets. const MAX_DATAGRAM_FD: usize = 32; // Needs to be large enough for a sizable dirty log. @@ -155,7 +157,7 @@ impl IdAllocator { #[repr(u8)] #[derive(Debug, Clone, Copy)] -enum Stat { +pub enum Stat { IoEventFd, MemoryGetDirtyLog, IrqEventGetFd, @@ -210,84 +212,29 @@ enum Stat { Count, } -#[derive(Clone, Copy)] -struct StatEntry { - count: u64, - total: u64, - max: u64, -} - -struct StatUpdater { - idx: usize, - start: Instant, -} - -struct GlobalStats { - entries: [StatEntry; Stat::Count as usize], +#[cfg(feature = "stats")] +fn record(a: Stat) -> stats::StatUpdater { + unsafe { stats::STATS.record(a) } } -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. - fn record(&mut self, idx: Stat) -> StatUpdater { - StatUpdater { - idx: idx as usize, - start: Instant::now(), - } - } - - fn print(&self) { - for idx in 0..Stat::Count as usize { - let e = &self.entries[idx as usize]; - let stat = unsafe { std::mem::transmute::(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; - } +#[cfg(not(feature = "stats"))] +fn record(_a: Stat) -> u32 { + 0 } -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 +#[cfg(feature = "stats")] +fn printstats() { + // Unsafe due to racy access - OK for stats + if std::env::var("CROSVM_STATS").is_ok() { unsafe { - STATS.update(self.idx, elapsed_nanos); + stats::STATS.print(); } } } +#[cfg(not(feature = "stats"))] +fn printstats() {} + pub struct crosvm { id_allocator: Arc, socket: UnixDatagram, @@ -378,12 +325,7 @@ impl crosvm { r.mut_destroy().id = id; self.main_transaction(&r, &[])?; self.get_id_allocator().free(id); - // Unsafe due to racy access - OK for stats - if std::env::var("CROSVM_STATS").is_ok() { - unsafe { - STATS.print(); - } - } + printstats(); Ok(()) } @@ -813,7 +755,7 @@ impl_ctor_dtor!( #[no_mangle] pub unsafe extern "C" fn crosvm_io_event_fd(this: *mut crosvm_io_event) -> c_int { - let _u = STATS.record(Stat::IoEventFd); + let _u = record(Stat::IoEventFd); (*this).evt.as_raw_fd() } @@ -886,7 +828,7 @@ pub unsafe extern "C" fn crosvm_memory_get_dirty_log( this: *mut crosvm_memory, log: *mut u8, ) -> c_int { - let _u = STATS.record(Stat::MemoryGetDirtyLog); + let _u = record(Stat::MemoryGetDirtyLog); let crosvm = &mut *crosvm; let this = &mut *this; let log_slice = slice::from_raw_parts_mut(log, dirty_log_bitmap_size(this.length as usize)); @@ -948,13 +890,13 @@ impl_ctor_dtor!( #[no_mangle] pub unsafe extern "C" fn crosvm_irq_event_get_fd(this: *mut crosvm_irq_event) -> c_int { - let _u = STATS.record(Stat::IrqEventGetFd); + let _u = record(Stat::IrqEventGetFd); (*this).trigger_evt.as_raw_fd() } #[no_mangle] pub unsafe extern "C" fn crosvm_irq_event_get_resample_fd(this: *mut crosvm_irq_event) -> c_int { - let _u = STATS.record(Stat::IrqEventGetResampleFd); + let _u = record(Stat::IrqEventGetResampleFd); (*this).resample_evt.as_raw_fd() } @@ -1276,7 +1218,7 @@ fn to_crosvm_rc(r: result::Result) -> c_int { #[no_mangle] pub unsafe extern "C" fn crosvm_connect(out: *mut *mut crosvm) -> c_int { - let _u = STATS.record(Stat::Connect); + let _u = record(Stat::Connect); let socket_name = match env::var("CROSVM_SOCKET") { Ok(v) => v, _ => return -ENOTCONN, @@ -1299,7 +1241,7 @@ pub unsafe extern "C" fn crosvm_connect(out: *mut *mut crosvm) -> c_int { #[no_mangle] pub unsafe extern "C" fn crosvm_new_connection(self_: *mut crosvm, out: *mut *mut crosvm) -> c_int { - let _u = STATS.record(Stat::NewConnection); + let _u = record(Stat::NewConnection); let self_ = &mut (*self_); match self_.try_clone() { Ok(cloned) => { @@ -1312,7 +1254,7 @@ pub unsafe extern "C" fn crosvm_new_connection(self_: *mut crosvm, out: *mut *mu #[no_mangle] pub unsafe extern "C" fn crosvm_destroy_connection(self_: *mut *mut crosvm) -> c_int { - let _u = STATS.record(Stat::DestroyConnection); + let _u = record(Stat::DestroyConnection); Box::from_raw(*self_); *self_ = null_mut(); 0 @@ -1320,7 +1262,7 @@ pub unsafe extern "C" fn crosvm_destroy_connection(self_: *mut *mut crosvm) -> c #[no_mangle] pub unsafe extern "C" fn crosvm_get_shutdown_eventfd(self_: *mut crosvm) -> c_int { - let _u = STATS.record(Stat::GetShutdownEventFd); + let _u = record(Stat::GetShutdownEventFd); let self_ = &mut (*self_); match self_.get_shutdown_eventfd() { Ok(f) => f.into_raw_fd(), @@ -1334,7 +1276,7 @@ pub unsafe extern "C" fn crosvm_check_extension( extension: u32, has_extension: *mut bool, ) -> c_int { - let _u = STATS.record(Stat::CheckExtentsion); + let _u = record(Stat::CheckExtentsion); let self_ = &mut (*self_); let ret = self_.check_extension(extension); @@ -1351,7 +1293,7 @@ pub unsafe extern "C" fn crosvm_get_supported_cpuid( cpuid_entries: *mut kvm_cpuid_entry2, out_count: *mut u32, ) -> c_int { - let _u = STATS.record(Stat::GetSupportedCpuid); + let _u = record(Stat::GetSupportedCpuid); let this = &mut *this; let cpuid_entries = from_raw_parts_mut(cpuid_entries, entry_count as usize); let mut cpuid_count: usize = 0; @@ -1367,7 +1309,7 @@ pub unsafe extern "C" fn crosvm_get_emulated_cpuid( cpuid_entries: *mut kvm_cpuid_entry2, out_count: *mut u32, ) -> c_int { - let _u = STATS.record(Stat::GetEmulatedCpuid); + let _u = record(Stat::GetEmulatedCpuid); let this = &mut *this; let cpuid_entries = from_raw_parts_mut(cpuid_entries, entry_count as usize); let mut cpuid_count: usize = 0; @@ -1383,7 +1325,7 @@ pub unsafe extern "C" fn crosvm_get_msr_index_list( msr_indices: *mut u32, out_count: *mut u32, ) -> c_int { - let _u = STATS.record(Stat::GetMsrIndexList); + let _u = record(Stat::GetMsrIndexList); let this = &mut *this; let msr_indices = from_raw_parts_mut(msr_indices, entry_count as usize); let mut msr_count: usize = 0; @@ -1397,7 +1339,7 @@ pub unsafe extern "C" fn crosvm_net_get_config( self_: *mut crosvm, config: *mut crosvm_net_config, ) -> c_int { - let _u = STATS.record(Stat::NetGetConfig); + let _u = record(Stat::NetGetConfig); let self_ = &mut (*self_); let ret = self_.get_net_config(); @@ -1415,7 +1357,7 @@ pub unsafe extern "C" fn crosvm_reserve_range( start: u64, length: u64, ) -> c_int { - let _u = STATS.record(Stat::ReserveRange); + let _u = record(Stat::ReserveRange); let self_ = &mut (*self_); let ret = self_.reserve_range(space, start, length); to_crosvm_rc(ret) @@ -1423,7 +1365,7 @@ pub unsafe extern "C" fn crosvm_reserve_range( #[no_mangle] pub unsafe extern "C" fn crosvm_set_irq(self_: *mut crosvm, irq_id: u32, active: bool) -> c_int { - let _u = STATS.record(Stat::SetIrq); + let _u = record(Stat::SetIrq); let self_ = &mut (*self_); let ret = self_.set_irq(irq_id, active); to_crosvm_rc(ret) @@ -1435,7 +1377,7 @@ pub unsafe extern "C" fn crosvm_set_irq_routing( route_count: u32, routes: *const crosvm_irq_route, ) -> c_int { - let _u = STATS.record(Stat::SetIrqRouting); + let _u = record(Stat::SetIrqRouting); let self_ = &mut (*self_); let ret = self_.set_irq_routing(slice::from_raw_parts(routes, route_count as usize)); to_crosvm_rc(ret) @@ -1447,7 +1389,7 @@ pub unsafe extern "C" fn crosvm_set_hypercall_hint( hints_count: u32, hints: *const crosvm_hint, ) -> c_int { - let _u = STATS.record(Stat::SetHypercallHint); + let _u = record(Stat::SetHypercallHint); let self_ = &mut (*self_); if hints_count < 1 { @@ -1482,7 +1424,7 @@ pub unsafe extern "C" fn crosvm_get_pic_state( primary: bool, state: *mut kvm_pic_state, ) -> c_int { - let _u = STATS.record(Stat::GetPicState); + let _u = record(Stat::GetPicState); let this = &mut *this; let state_set = if primary { MainRequest_StateSet::PIC0 @@ -1500,7 +1442,7 @@ pub unsafe extern "C" fn crosvm_set_pic_state( primary: bool, state: *mut kvm_pic_state, ) -> c_int { - let _u = STATS.record(Stat::SetPicState); + let _u = record(Stat::SetPicState); let this = &mut *this; let state_set = if primary { MainRequest_StateSet::PIC0 @@ -1517,7 +1459,7 @@ pub unsafe extern "C" fn crosvm_get_ioapic_state( this: *mut crosvm, state: *mut kvm_ioapic_state, ) -> c_int { - let _u = STATS.record(Stat::GetIoapicState); + let _u = record(Stat::GetIoapicState); let this = &mut *this; let state = from_raw_parts_mut(state as *mut u8, size_of::()); let ret = this.get_state(MainRequest_StateSet::IOAPIC, state); @@ -1529,7 +1471,7 @@ pub unsafe extern "C" fn crosvm_set_ioapic_state( this: *mut crosvm, state: *const kvm_ioapic_state, ) -> c_int { - let _u = STATS.record(Stat::SetIoapicState); + let _u = record(Stat::SetIoapicState); let this = &mut *this; let state = from_raw_parts(state as *mut u8, size_of::()); let ret = this.set_state(MainRequest_StateSet::IOAPIC, state); @@ -1541,7 +1483,7 @@ pub unsafe extern "C" fn crosvm_get_pit_state( this: *mut crosvm, state: *mut kvm_pit_state2, ) -> c_int { - let _u = STATS.record(Stat::GetPitState); + let _u = record(Stat::GetPitState); let this = &mut *this; let state = from_raw_parts_mut(state as *mut u8, size_of::()); let ret = this.get_state(MainRequest_StateSet::PIT, state); @@ -1553,7 +1495,7 @@ pub unsafe extern "C" fn crosvm_set_pit_state( this: *mut crosvm, state: *const kvm_pit_state2, ) -> c_int { - let _u = STATS.record(Stat::SetPitState); + let _u = record(Stat::SetPitState); let this = &mut *this; let state = from_raw_parts(state as *mut u8, size_of::()); let ret = this.set_state(MainRequest_StateSet::PIT, state); @@ -1565,7 +1507,7 @@ pub unsafe extern "C" fn crosvm_get_clock( this: *mut crosvm, clock_data: *mut kvm_clock_data, ) -> c_int { - let _u = STATS.record(Stat::GetClock); + let _u = record(Stat::GetClock); let this = &mut *this; let state = from_raw_parts_mut(clock_data as *mut u8, size_of::()); let ret = this.get_state(MainRequest_StateSet::CLOCK, state); @@ -1577,7 +1519,7 @@ pub unsafe extern "C" fn crosvm_set_clock( this: *mut crosvm, clock_data: *const kvm_clock_data, ) -> c_int { - let _u = STATS.record(Stat::SetClock); + let _u = record(Stat::SetClock); let this = &mut *this; let state = from_raw_parts(clock_data as *mut u8, size_of::()); let ret = this.set_state(MainRequest_StateSet::CLOCK, state); @@ -1586,7 +1528,7 @@ pub unsafe extern "C" fn crosvm_set_clock( #[no_mangle] pub unsafe extern "C" fn crosvm_set_identity_map_addr(self_: *mut crosvm, addr: u32) -> c_int { - let _u = STATS.record(Stat::SetIdentityMapAddr); + let _u = record(Stat::SetIdentityMapAddr); let self_ = &mut (*self_); let ret = self_.set_identity_map_addr(addr); to_crosvm_rc(ret) @@ -1598,7 +1540,7 @@ pub unsafe extern "C" fn crosvm_pause_vcpus( cpu_mask: u64, user: *mut c_void, ) -> c_int { - let _u = STATS.record(Stat::PauseVcpus); + let _u = record(Stat::PauseVcpus); let self_ = &mut (*self_); let ret = self_.pause_vcpus(cpu_mask, user); to_crosvm_rc(ret) @@ -1606,7 +1548,7 @@ pub unsafe extern "C" fn crosvm_pause_vcpus( #[no_mangle] pub unsafe extern "C" fn crosvm_start(self_: *mut crosvm) -> c_int { - let _u = STATS.record(Stat::Start); + let _u = record(Stat::Start); let self_ = &mut (*self_); let ret = self_.start(); to_crosvm_rc(ret) @@ -1618,7 +1560,7 @@ pub unsafe extern "C" fn crosvm_get_vcpu( cpu_id: u32, out: *mut *mut crosvm_vcpu, ) -> c_int { - let _u = STATS.record(Stat::GetVcpu); + let _u = record(Stat::GetVcpu); let self_ = &mut (*self_); let ret = self_.get_vcpu(cpu_id); @@ -1633,7 +1575,7 @@ pub unsafe extern "C" fn crosvm_vcpu_wait( this: *mut crosvm_vcpu, event: *mut crosvm_vcpu_event, ) -> c_int { - let _u = STATS.record(Stat::VcpuWait); + let _u = record(Stat::VcpuWait); let this = &mut *this; let event = &mut *event; let ret = this.wait(event); @@ -1642,7 +1584,7 @@ pub unsafe extern "C" fn crosvm_vcpu_wait( #[no_mangle] pub unsafe extern "C" fn crosvm_vcpu_resume(this: *mut crosvm_vcpu) -> c_int { - let _u = STATS.record(Stat::VcpuResume); + let _u = record(Stat::VcpuResume); let this = &mut *this; let ret = this.resume(); to_crosvm_rc(ret) @@ -1653,7 +1595,7 @@ pub unsafe extern "C" fn crosvm_vcpu_get_regs( this: *mut crosvm_vcpu, regs: *mut kvm_regs, ) -> c_int { - let _u = STATS.record(Stat::VcpuGetRegs); + let _u = record(Stat::VcpuGetRegs); let this = &mut *this; if this.regs.set { if let Err(e) = this.set_state_from_cache(VcpuRequest_StateSet::REGS) { @@ -1675,7 +1617,7 @@ pub unsafe extern "C" fn crosvm_vcpu_set_regs( this: *mut crosvm_vcpu, regs: *const kvm_regs, ) -> c_int { - let _u = STATS.record(Stat::VcpuSetRegs); + let _u = record(Stat::VcpuSetRegs); let this = &mut *this; this.regs.get = false; let regs = from_raw_parts(regs as *mut u8, size_of::()); @@ -1689,7 +1631,7 @@ pub unsafe extern "C" fn crosvm_vcpu_get_sregs( this: *mut crosvm_vcpu, sregs: *mut kvm_sregs, ) -> c_int { - let _u = STATS.record(Stat::VcpuGetSregs); + let _u = record(Stat::VcpuGetSregs); let this = &mut *this; if this.sregs.set { if let Err(e) = this.set_state_from_cache(VcpuRequest_StateSet::SREGS) { @@ -1711,7 +1653,7 @@ pub unsafe extern "C" fn crosvm_vcpu_set_sregs( this: *mut crosvm_vcpu, sregs: *const kvm_sregs, ) -> c_int { - let _u = STATS.record(Stat::VcpuSetSregs); + let _u = record(Stat::VcpuSetSregs); let this = &mut *this; this.sregs.get = false; let sregs = from_raw_parts(sregs as *mut u8, size_of::()); @@ -1722,7 +1664,7 @@ pub unsafe extern "C" fn crosvm_vcpu_set_sregs( #[no_mangle] pub unsafe extern "C" fn crosvm_vcpu_get_fpu(this: *mut crosvm_vcpu, fpu: *mut kvm_fpu) -> c_int { - let _u = STATS.record(Stat::GetFpu); + let _u = record(Stat::GetFpu); let this = &mut *this; let fpu = from_raw_parts_mut(fpu as *mut u8, size_of::()); let ret = this.get_state(VcpuRequest_StateSet::FPU, fpu); @@ -1731,7 +1673,7 @@ pub unsafe extern "C" fn crosvm_vcpu_get_fpu(this: *mut crosvm_vcpu, fpu: *mut k #[no_mangle] pub unsafe extern "C" fn crosvm_vcpu_set_fpu(this: *mut crosvm_vcpu, fpu: *const kvm_fpu) -> c_int { - let _u = STATS.record(Stat::SetFpu); + let _u = record(Stat::SetFpu); let this = &mut *this; let fpu = from_raw_parts(fpu as *mut u8, size_of::()); let ret = this.set_state(VcpuRequest_StateSet::FPU, fpu); @@ -1743,7 +1685,7 @@ pub unsafe extern "C" fn crosvm_vcpu_get_debugregs( this: *mut crosvm_vcpu, dregs: *mut kvm_debugregs, ) -> c_int { - let _u = STATS.record(Stat::GetDebugRegs); + let _u = record(Stat::GetDebugRegs); let this = &mut *this; if this.debugregs.set { if let Err(e) = this.set_state_from_cache(VcpuRequest_StateSet::DEBUGREGS) { @@ -1765,7 +1707,7 @@ pub unsafe extern "C" fn crosvm_vcpu_set_debugregs( this: *mut crosvm_vcpu, dregs: *const kvm_debugregs, ) -> c_int { - let _u = STATS.record(Stat::SetDebugRegs); + let _u = record(Stat::SetDebugRegs); let this = &mut *this; this.debugregs.get = false; let dregs = from_raw_parts(dregs as *mut u8, size_of::()); @@ -1779,7 +1721,7 @@ pub unsafe extern "C" fn crosvm_vcpu_get_xcrs( this: *mut crosvm_vcpu, xcrs: *mut kvm_xcrs, ) -> c_int { - let _u = STATS.record(Stat::GetXCRegs); + let _u = record(Stat::GetXCRegs); let this = &mut *this; let xcrs = from_raw_parts_mut(xcrs as *mut u8, size_of::()); let ret = this.get_state(VcpuRequest_StateSet::XCREGS, xcrs); @@ -1791,7 +1733,7 @@ pub unsafe extern "C" fn crosvm_vcpu_set_xcrs( this: *mut crosvm_vcpu, xcrs: *const kvm_xcrs, ) -> c_int { - let _u = STATS.record(Stat::SetXCRegs); + let _u = record(Stat::SetXCRegs); let this = &mut *this; let xcrs = from_raw_parts(xcrs as *mut u8, size_of::()); let ret = this.set_state(VcpuRequest_StateSet::XCREGS, xcrs); @@ -1805,7 +1747,7 @@ pub unsafe extern "C" fn crosvm_vcpu_get_msrs( msr_entries: *mut kvm_msr_entry, out_count: *mut u32, ) -> c_int { - let _u = STATS.record(Stat::VcpuGetMsrs); + let _u = record(Stat::VcpuGetMsrs); let this = &mut *this; let msr_entries = from_raw_parts_mut(msr_entries, msr_count as usize); let mut count: usize = 0; @@ -1820,7 +1762,7 @@ pub unsafe extern "C" fn crosvm_vcpu_set_msrs( msr_count: u32, msr_entries: *const kvm_msr_entry, ) -> c_int { - let _u = STATS.record(Stat::VcpuSetMsrs); + let _u = record(Stat::VcpuSetMsrs); let this = &mut *this; let msr_entries = from_raw_parts(msr_entries, msr_count as usize); let ret = this.set_msrs(msr_entries); @@ -1833,7 +1775,7 @@ pub unsafe extern "C" fn crosvm_vcpu_set_cpuid( cpuid_count: u32, cpuid_entries: *const kvm_cpuid_entry2, ) -> c_int { - let _u = STATS.record(Stat::VcpuSetCpuid); + let _u = record(Stat::VcpuSetCpuid); let this = &mut *this; let cpuid_entries = from_raw_parts(cpuid_entries, cpuid_count as usize); let ret = this.set_cpuid(cpuid_entries); @@ -1845,7 +1787,7 @@ pub unsafe extern "C" fn crosvm_vcpu_get_lapic_state( this: *mut crosvm_vcpu, state: *mut kvm_lapic_state, ) -> c_int { - let _u = STATS.record(Stat::VcpuGetLapicState); + let _u = record(Stat::VcpuGetLapicState); let this = &mut *this; let state = from_raw_parts_mut(state as *mut u8, size_of::()); let ret = this.get_state(VcpuRequest_StateSet::LAPIC, state); @@ -1857,7 +1799,7 @@ pub unsafe extern "C" fn crosvm_vcpu_set_lapic_state( this: *mut crosvm_vcpu, state: *const kvm_lapic_state, ) -> c_int { - let _u = STATS.record(Stat::VcpuSetLapicState); + let _u = record(Stat::VcpuSetLapicState); let this = &mut *this; let state = from_raw_parts(state as *mut u8, size_of::()); let ret = this.set_state(VcpuRequest_StateSet::LAPIC, state); @@ -1869,7 +1811,7 @@ pub unsafe extern "C" fn crosvm_vcpu_get_mp_state( this: *mut crosvm_vcpu, state: *mut kvm_mp_state, ) -> c_int { - let _u = STATS.record(Stat::VcpuGetMpState); + let _u = record(Stat::VcpuGetMpState); let this = &mut *this; let state = from_raw_parts_mut(state as *mut u8, size_of::()); let ret = this.get_state(VcpuRequest_StateSet::MP, state); @@ -1881,7 +1823,7 @@ pub unsafe extern "C" fn crosvm_vcpu_set_mp_state( this: *mut crosvm_vcpu, state: *const kvm_mp_state, ) -> c_int { - let _u = STATS.record(Stat::VcpuSetMpState); + let _u = record(Stat::VcpuSetMpState); let this = &mut *this; let state = from_raw_parts(state as *mut u8, size_of::()); let ret = this.set_state(VcpuRequest_StateSet::MP, state); @@ -1893,7 +1835,7 @@ pub unsafe extern "C" fn crosvm_vcpu_get_vcpu_events( this: *mut crosvm_vcpu, events: *mut kvm_vcpu_events, ) -> c_int { - let _u = STATS.record(Stat::VcpuGetVcpuEvents); + let _u = record(Stat::VcpuGetVcpuEvents); let this = &mut *this; let events = from_raw_parts_mut(events as *mut u8, size_of::()); let ret = this.get_state(VcpuRequest_StateSet::EVENTS, events); @@ -1905,7 +1847,7 @@ pub unsafe extern "C" fn crosvm_vcpu_set_vcpu_events( this: *mut crosvm_vcpu, events: *const kvm_vcpu_events, ) -> c_int { - let _u = STATS.record(Stat::VcpuSetVcpuEvents); + let _u = record(Stat::VcpuSetVcpuEvents); let this = &mut *this; let events = from_raw_parts(events as *mut u8, size_of::()); let ret = this.set_state(VcpuRequest_StateSet::EVENTS, events); 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::(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); + } + } +} -- cgit 1.4.1