use std::{fmt::Debug, time::Instant};
#[cfg(feature = "perf_event")]
pub use perf::{PerfEventMetric, perf_event};
#[cfg(feature = "libc")]
pub use rusage::{RusageKind, RusageMetric};
#[cfg(feature = "kperf")]
pub use kperf_impl::{KperfMetric, kperf};
pub use system::{Event as SystemEvent, SystemPerfMetric};
pub mod mem;
mod system;
#[cfg(feature = "kperf")]
mod kperf_impl;
#[cfg(feature = "perf_event")]
mod perf;
#[cfg(feature = "libc")]
mod rusage;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MetricAggregation {
Sum,
Max,
}
#[derive(Debug)]
pub struct MetricReportInfo {
pub name: &'static str,
pub show_spread: bool,
pub show_baseline: bool,
pub aggregation: MetricAggregation,
}
impl MetricReportInfo {
pub const fn new(name: &'static str) -> Self {
Self {
name,
show_spread: true,
show_baseline: true,
aggregation: MetricAggregation::Sum,
}
}
pub const fn with_no_spread(mut self) -> Self {
self.show_spread = false;
self
}
pub const fn with_no_baseline(mut self) -> Self {
self.show_baseline = false;
self
}
pub const fn with_aggregation(mut self, aggregation: MetricAggregation) -> Self {
self.aggregation = aggregation;
self
}
}
pub trait Metrics: Send + Sync + 'static {
type Start: Clone + Send + 'static;
type Result: Clone + Send + 'static;
fn start(&self) -> Self::Start;
fn end(&self, start: Self::Start) -> Self::Result;
fn metrics_info() -> &'static [MetricReportInfo];
fn result_to_f64(&self, metric_idx: usize, result: &Self::Result) -> f64;
fn result_to_f64s(&self, result: &Self::Result) -> Vec<f64> {
let mut result_vec = Vec::new();
for idx in 0..Self::metrics_info().len() {
result_vec.push(self.result_to_f64(idx, result));
}
result_vec
}
fn format_value(&self, metric_idx: usize, value: f64) -> (String, &'static str);
}
pub trait SingleMetric: Send + Sync + 'static {
type Start: Clone + Send + 'static;
type Result: Clone + Send + 'static;
fn start(&self) -> Self::Start;
fn end(&self, start: Self::Start) -> Self::Result;
fn result_to_f64(&self, result: &Self::Result) -> f64;
fn format_value(&self, value: f64) -> (String, &'static str) {
format_unit_helper(value)
}
}
#[derive(Default)]
pub struct InstantProvider;
impl SingleMetric for InstantProvider {
type Start = Instant;
type Result = u128;
fn start(&self) -> Self::Start {
Instant::now()
}
fn end(&self, start: Self::Start) -> Self::Result {
start.elapsed().as_nanos()
}
fn format_value(&self, value: f64) -> (String, &'static str) {
if value >= 60_000_000_000.0 {
(format!("{:.3}", value / 60_000_000_000.0), "min")
} else if value >= 1_000_000_000.0 {
(format!("{:.3}", value / 1_000_000_000.0), "s")
} else if value >= 1_000_000.0 {
(format!("{:.3}", value / 1_000_000.0), "ms")
} else if value >= 1_000.0 {
(format!("{:.2}", value / 1_000.0), "us")
} else {
(format!("{:.1}", value), "ns")
}
}
fn result_to_f64(&self, result: &Self::Result) -> f64 {
*result as f64
}
}
pub fn format_unit_helper(value: f64) -> (String, &'static str) {
if value >= 1_000_000_000.0 {
(format!("{:.3}", value / 1_000_000_000.0), "G")
} else if value >= 1_000_000.0 {
(format!("{:.3}", value / 1_000_000.0), "M")
} else if value >= 1_000.0 {
(format!("{:.3}", value / 1_000.0), "K")
} else if value >= 1.0 {
(format!("{:.2}", value), "")
} else {
(format!("{:.3}", value), "")
}
}
macro_rules! impl_primitive_metrics {
($($ty:ty),*) => {
$(
impl SingleMetric for $ty {
type Start = ();
type Result = Self;
fn start(&self) -> Self::Start {}
fn end(&self, _start: Self::Start) -> Self::Result {
*self
}
fn result_to_f64(&self, result: &Self::Result) -> f64 {
*result as f64
}
}
)*
};
}
impl_primitive_metrics!(
u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, isize, f64
);