diff --git a/Cargo.lock b/Cargo.lock index 9156d679..caa04504 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -111,6 +111,7 @@ dependencies = [ "ctor", "env_logger 0.8.4", "flate2", + "indexmap 2.1.0", "infer", "inferno", "lazy_static", @@ -119,7 +120,6 @@ dependencies = [ "num_cpus", "perf-event2", "procfs", - "raw-cpuid", "rustix 0.38.26", "serde", "serde_json", @@ -725,7 +725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d" dependencies = [ "cfg-if", - "hashbrown 0.14.0", + "hashbrown 0.14.3", "lock_api", "once_cell", "parking_lot_core", @@ -779,6 +779,12 @@ dependencies = [ "log", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.2.8" @@ -956,7 +962,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.1", "slab", "tokio", "tokio-util", @@ -971,9 +977,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "heck" @@ -1127,6 +1133,16 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + [[package]] name = "infer" version = "0.13.0" @@ -1148,7 +1164,7 @@ dependencies = [ "crossbeam-utils", "dashmap", "env_logger 0.10.0", - "indexmap", + "indexmap 1.9.1", "is-terminal", "itoa", "log", @@ -1586,15 +1602,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "raw-cpuid" -version = "10.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6823ea29436221176fe662da99998ad3b4db2c7f31e7b6f5fe43adccd6320bb" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "rayon" version = "1.5.3" @@ -1884,7 +1891,7 @@ version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" dependencies = [ - "indexmap", + "indexmap 1.9.1", "ryu", "serde", "yaml-rust", diff --git a/Cargo.toml b/Cargo.toml index 02a413d3..87855cca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,10 +43,10 @@ strum_macros = "0.24" sysctl = "*" perf-event2 = "0.7.1" num_cpus = "1.0" -raw-cpuid = "10.6.0" libc = "0.2" flate2 = "1.0.26" tar = "0.4.38" infer = "0.13.0" bincode = "1.3.3" inferno = "0.11.15" +indexmap = "2.1.0" diff --git a/src/data.rs b/src/data.rs index 1cddb37c..c6fcceef 100644 --- a/src/data.rs +++ b/src/data.rs @@ -4,8 +4,10 @@ pub mod diskstats; pub mod flamegraphs; #[cfg(target_arch = "aarch64")] pub mod grv_perf_events; +pub mod intel_icelake_perf_events; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub mod intel_perf_events; +pub mod intel_sapphire_rapids_perf_events; pub mod interrupts; pub mod kernel_config; pub mod meminfodata; @@ -15,6 +17,7 @@ pub mod perf_stat; pub mod processes; pub mod sysctldata; pub mod systeminfo; +pub mod utils; pub mod vmstat; use crate::visualizer::{GetData, ReportParams}; diff --git a/src/data/intel_icelake_perf_events.rs b/src/data/intel_icelake_perf_events.rs new file mode 100644 index 00000000..fb3ba8d2 --- /dev/null +++ b/src/data/intel_icelake_perf_events.rs @@ -0,0 +1,40 @@ +use crate::data::perf_stat::{NamedCtr, NamedTypeCtr, PerfType}; + +static CYCLES: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Cycles", + config: 0x3c, +}; +static SLOTS: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Slots", + config: 0x01a4, +}; +static STALL_FRONTEND: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Frontend-Stalls", + config: 0x500019c, +}; +static STALL_BACKEND: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Backend-Stalls", + config: 0x02a4, +}; + +lazy_static! { + pub static ref ICX_CTRS: Vec> = [ + NamedCtr { + name: "stall-frontend-pkc", + nrs: vec![STALL_FRONTEND], + drs: vec![CYCLES], + scale: 1000 + }, + NamedCtr { + name: "stall-backend-pkc", + nrs: vec![STALL_BACKEND], + drs: vec![SLOTS], + scale: 1000 + }, + ] + .to_vec(); +} diff --git a/src/data/intel_perf_events.rs b/src/data/intel_perf_events.rs index bd671a84..5ebe4dc5 100644 --- a/src/data/intel_perf_events.rs +++ b/src/data/intel_perf_events.rs @@ -39,7 +39,7 @@ static L1_INSTRUCTIONS: NamedTypeCtr = NamedTypeCtr { static BACKEND_STALLS: NamedTypeCtr = NamedTypeCtr { perf_type: PerfType::RAW, name: "Backend-Stalls", - config: 0x10a2, + config: 0x01a2, }; static L3: NamedTypeCtr = NamedTypeCtr { perf_type: PerfType::RAW, diff --git a/src/data/intel_sapphire_rapids_perf_events.rs b/src/data/intel_sapphire_rapids_perf_events.rs new file mode 100644 index 00000000..74c90ffa --- /dev/null +++ b/src/data/intel_sapphire_rapids_perf_events.rs @@ -0,0 +1,122 @@ +use crate::data::perf_stat::{NamedCtr, NamedTypeCtr, PerfType}; + +static INSTRUCTIONS: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Instructions", + config: 0xc0, +}; +static CYCLES: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Cycles", + config: 0x3c, +}; +static SLOTS: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Slots", + config: 0x01a4, +}; +static L2: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "L2", + config: 0x1f25, +}; +static INSTRUCTION_TLB: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Instruction-TLB", + config: 0x2011, +}; +static INSTRUCTION_TLB_TW: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Instruction-TLB-TW", + config: 0x0e11, +}; +static DATA_RD_TLB: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Data-RD-TLB", + config: 0x2012, +}; +static DATA_ST_TLB: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Data-ST-TLB", + config: 0x2013, +}; +static DATA_RD_TLB_TW: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Data-RD-TLB-TW", + config: 0x0e12, +}; +static DATA_ST_TLB_TW: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Data-ST-TLB-TW", + config: 0x0e13, +}; +static STALL_FRONTEND: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Frontend-Stalls", + config: 0x600019c, +}; +static STALL_BACKEND: NamedTypeCtr = NamedTypeCtr { + perf_type: PerfType::RAW, + name: "Backend-Stalls", + config: 0x02a4, +}; + +lazy_static! { + pub static ref SPR_CTRS: Vec> = [ + NamedCtr { + name: "l2-mpki", + nrs: vec![L2], + drs: vec![INSTRUCTIONS], + scale: 1000 + }, + NamedCtr { + name: "inst-tlb-mpki", + nrs: vec![INSTRUCTION_TLB], + drs: vec![INSTRUCTIONS], + scale: 1000 + }, + NamedCtr { + name: "inst-tlb-tw-pki", + nrs: vec![INSTRUCTION_TLB_TW], + drs: vec![INSTRUCTIONS], + scale: 1000 + }, + NamedCtr { + name: "data-rd-tlb-mpki", + nrs: vec![DATA_RD_TLB], + drs: vec![INSTRUCTIONS], + scale: 1000 + }, + NamedCtr { + name: "data-st-tlb-mpki", + nrs: vec![DATA_ST_TLB], + drs: vec![INSTRUCTIONS], + scale: 1000 + }, + NamedCtr { + name: "data-rd-tlb-tw-pki", + nrs: vec![DATA_RD_TLB_TW], + drs: vec![INSTRUCTIONS], + scale: 1000 + }, + NamedCtr { + name: "data-st-tlb-tw-pki", + nrs: vec![DATA_ST_TLB_TW], + drs: vec![INSTRUCTIONS], + scale: 1000 + }, + NamedCtr { + name: "stall-frontend-pkc", + nrs: vec![STALL_FRONTEND], + drs: vec![CYCLES], + scale: 1000 + }, + NamedCtr { + name: "stall-backend-pkc", + nrs: vec![STALL_BACKEND], + drs: vec![SLOTS], + scale: 1000 + }, + ] + .to_vec(); +} diff --git a/src/data/perf_stat.rs b/src/data/perf_stat.rs index 3aaad310..e705b68e 100644 --- a/src/data/perf_stat.rs +++ b/src/data/perf_stat.rs @@ -1,11 +1,13 @@ extern crate ctor; +use crate::data::utils::get_cpu_info; use crate::data::{CollectData, CollectorParams, Data, DataType, ProcessedData, TimeEnum}; use crate::visualizer::{DataVisualizer, GetData, GraphLimitType, GraphMetadata}; use crate::{PERFORMANCE_DATA, VISUALIZATION_DATA}; use anyhow::Result; use chrono::prelude::*; use ctor::ctor; +use indexmap::IndexMap; use log::{trace, warn}; use perf_event::events::{Raw, Software}; use perf_event::{Builder, Counter, Group, ReadFormat}; @@ -16,11 +18,14 @@ use std::sync::Mutex; #[cfg(target_arch = "aarch64")] use crate::data::grv_perf_events; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use {crate::data::intel_perf_events, crate::PDError, raw_cpuid::CpuId}; +use { + crate::data::intel_icelake_perf_events::ICX_CTRS, crate::data::intel_perf_events, + crate::data::intel_sapphire_rapids_perf_events::SPR_CTRS, crate::PDError, +}; pub static PERF_STAT_FILE_NAME: &str = "perf_stat"; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub enum PerfType { RAW = 4, } @@ -59,7 +64,7 @@ impl Ctr { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct NamedCtr<'a> { pub name: &'a str, pub nrs: Vec>, @@ -67,7 +72,7 @@ pub struct NamedCtr<'a> { pub scale: u64, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct NamedTypeCtr<'a> { pub perf_type: PerfType, pub name: &'a str, @@ -111,7 +116,9 @@ impl CollectData for PerfStatRaw { fn prepare_data_collector(&mut self, _params: CollectorParams) -> Result<()> { let num_cpus = num_cpus::get(); let mut cpu_groups: Vec = Vec::new(); - let perf_list; + let mut perf_list; + let platform_specific_counter; + let cpu_info = get_cpu_info()?; #[cfg(target_arch = "aarch64")] { @@ -119,13 +126,35 @@ impl CollectData for PerfStatRaw { } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { - let cpuid = CpuId::new(); - let vendor_info = cpuid.get_vendor_info().unwrap(); - if vendor_info.as_str() == "GenuineIntel" { + /* Get Vendor Specific Perf events */ + if cpu_info.vendor == "GenuineIntel" { perf_list = intel_perf_events::PERF_LIST.to_vec(); + + /* Get Model specific events */ + platform_specific_counter = match cpu_info.model_name.as_str() { + "Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz" => ICX_CTRS.to_vec(), + "Intel(R) Xeon(R) Platinum 8488C" => SPR_CTRS.to_vec(), + _ => Vec::new(), + }; } else { return Err(PDError::CollectorPerfUnsupportedCPU.into()); } + + let mut events_map = IndexMap::new(); + for event in &perf_list { + events_map.insert(event.name, event.clone()); + } + + for event in platform_specific_counter { + if let Some(ctr) = events_map.get_mut(event.name) { + ctr.nrs = event.nrs; + ctr.drs = event.drs; + ctr.scale = event.scale; + } else { + events_map.insert(event.name, event); + } + } + perf_list = events_map.into_values().collect(); } for cpu in 0..num_cpus { for named_ctr in &perf_list { diff --git a/src/data/utils.rs b/src/data/utils.rs new file mode 100644 index 00000000..eb0db9ae --- /dev/null +++ b/src/data/utils.rs @@ -0,0 +1,42 @@ +use anyhow::Result; +use std::fs::File; +use std::io::{BufRead, BufReader}; + +#[derive(Clone, Debug)] +pub struct CpuInfo { + pub vendor: String, + pub model_name: String, +} + +impl CpuInfo { + fn new() -> Self { + CpuInfo { + vendor: String::new(), + model_name: String::new(), + } + } +} + +pub fn get_cpu_info() -> Result { + let file = File::open("/proc/cpuinfo")?; + let proc_cpuinfo = BufReader::new(file); + let mut cpu_info = CpuInfo::new(); + for line in proc_cpuinfo.lines() { + let info_line = line?; + if info_line.is_empty() { + break; + } + let key_value: Vec<&str> = info_line.split(':').collect(); + if key_value.len() < 2 { + continue; + } + let key = key_value[0].trim().to_string(); + let value = key_value[1].trim().to_string(); + match key.as_str() { + "vendor_id" => cpu_info.vendor = value, + "model name" => cpu_info.model_name = value, + _ => {} + } + } + Ok(cpu_info) +}