use std::time::Duration;
#[derive(Default, Clone, Copy, Debug)]
pub struct KernelSnapshot {
pub user_cpu_ms: u64,
pub sys_cpu_ms: u64,
pub max_rss_bytes: u64,
pub minor_faults: u64,
pub major_faults: u64,
}
#[cfg(unix)]
pub fn snapshot() -> Option<KernelSnapshot> {
use std::mem::MaybeUninit;
unsafe {
let mut ru = MaybeUninit::<libc::rusage>::zeroed();
if libc::getrusage(libc::RUSAGE_SELF, ru.as_mut_ptr()) != 0 {
return None;
}
let ru = ru.assume_init();
let user_us = (ru.ru_utime.tv_sec as u64) * 1_000_000 + (ru.ru_utime.tv_usec as u64);
let sys_us = (ru.ru_stime.tv_sec as u64) * 1_000_000 + (ru.ru_stime.tv_usec as u64);
let max_rss = if cfg!(target_os = "macos") {
ru.ru_maxrss as u64
} else {
(ru.ru_maxrss as u64) * 1024
};
Some(KernelSnapshot {
user_cpu_ms: user_us / 1000,
sys_cpu_ms: sys_us / 1000,
max_rss_bytes: max_rss,
minor_faults: ru.ru_minflt as u64,
major_faults: ru.ru_majflt as u64,
})
}
}
#[cfg(not(unix))]
pub fn snapshot() -> Option<KernelSnapshot> {
None
}
pub fn enabled() -> bool {
std::env::var_os("AUBE_DIAG_KERNEL").is_some() && snapshot().is_some()
}
pub fn emit_phase_delta(phase: &'static str, before: KernelSnapshot, after: KernelSnapshot) {
let user_d = after.user_cpu_ms.saturating_sub(before.user_cpu_ms);
let sys_d = after.sys_cpu_ms.saturating_sub(before.sys_cpu_ms);
let rss_after = after.max_rss_bytes;
let minor_d = after.minor_faults.saturating_sub(before.minor_faults);
let major_d = after.major_faults.saturating_sub(before.major_faults);
crate::diag::event_lazy(
crate::diag::Category::Kernel,
phase,
Duration::from_millis(user_d + sys_d),
|| {
format!(
r#"{{"user_ms":{user_d},"sys_ms":{sys_d},"rss_peak":{rss_after},"minor_faults":{minor_d},"major_faults":{major_d}}}"#
)
},
);
}
pub async fn track_phase_async<F, T>(phase: &'static str, f: F) -> T
where
F: std::future::Future<Output = T>,
{
if !enabled() {
return f.await;
}
let before = snapshot().unwrap_or_default();
let result = f.await;
let after = snapshot().unwrap_or_default();
emit_phase_delta(phase, before, after);
result
}