#[cfg(target_os = "linux")]
pub(crate) mod linux;
use std::fmt::Display;
use std::fmt::Formatter;
use std::str::FromStr;
#[cfg(target_os = "linux")]
pub use linux::*;
#[cfg(not(target_os = "linux"))]
pub(crate) mod dummy;
#[cfg(not(target_os = "linux"))]
pub use dummy::*;
use crate::report::format::format_with_underscores_f64;
use crate::stats::*;
use miniserde::Deserialize;
use miniserde::Serialize;
pub static PERF_CNT_EVENT_LISTENER_NAME: &str = "_binggan_perf";
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum PerfCounter {
CpuCycles,
Branches,
MissedBranches,
L1DCacheAccess,
L1DCacheMiss,
TLBDataAccess,
TLBDataMiss,
InstructionsRetired,
PageFaults,
PageFaultsMinor,
PageFaultsMajor,
}
const MAPPINGS: &[(&str, PerfCounter)] = &[
("Cycles", PerfCounter::CpuCycles),
("Br", PerfCounter::Branches),
("BrM", PerfCounter::MissedBranches),
("L1dA", PerfCounter::L1DCacheAccess),
("L1dM", PerfCounter::L1DCacheMiss),
("dTLBA", PerfCounter::TLBDataAccess),
("dTLBM", PerfCounter::TLBDataMiss),
("IRet", PerfCounter::InstructionsRetired),
("PGF", PerfCounter::PageFaults),
("PGFMin", PerfCounter::PageFaultsMinor),
("PGFMaj", PerfCounter::PageFaultsMajor),
];
impl Display for PerfCounter {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let val = MAPPINGS
.iter()
.find(|(_, counter)| *counter == *self)
.map(|(s, _)| *s)
.expect("Invalid PerfCounter");
write!(f, "{}", val)
}
}
impl FromStr for PerfCounter {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
MAPPINGS
.iter()
.find(|(key, _)| *key == s)
.map(|(_, counter)| *counter)
.ok_or_else(|| format!("Invalid PerfCounter: {}", s))
}
}
pub fn default_perf_counters() -> &'static [PerfCounter] {
&[
PerfCounter::Branches,
PerfCounter::MissedBranches,
PerfCounter::L1DCacheAccess,
PerfCounter::L1DCacheMiss,
PerfCounter::CpuCycles,
]
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerfCounterValues {
values: Vec<(PerfCounter, f64)>,
}
fn print_counter_value<F: Fn(f64) -> f64>(
name: &str,
value: f64,
other: Option<f64>,
f: F,
) -> String {
let diff_str = other
.map(|other_value| {
if other_value == 0.0 || value == 0.0 || other_value == value {
return "".to_string();
}
format_percentage(compute_percentage_diff(value, other_value), true)
})
.unwrap_or_default();
format!(
"{}: {} {}",
name,
format_with_underscores_f64(f(value)),
diff_str,
)
}
impl PerfCounterValues {
pub fn to_columns(&self, other_values: Option<&Self>) -> Vec<String> {
let mut result = Vec::new();
for (counter_enum, value) in self.values.iter() {
let other_value = other_values.and_then(|other| {
other
.values
.iter()
.find(|(other_enum, _)| other_enum == counter_enum)
.map(|(_, v)| *v)
});
result.push(print_counter_value(
&format!("{}", counter_enum),
*value,
other_value,
|val| val,
));
}
result
}
}