diff options
author | Dennis Kobert <dennis@kobert.dev> | 2025-03-09 15:21:58 +0100 |
---|---|---|
committer | Dennis Kobert <dennis@kobert.dev> | 2025-03-09 15:21:58 +0100 |
commit | 7af8a52e2ff92518b8c737dfe74d9ed68d5f4943 (patch) | |
tree | 3a5522a4bd5e4d2865de8a7f86d1f92a129c30c2 | |
parent | b720a1253fb8cc8a3ba3454014bad239233368c1 (diff) |
Implement rapl abstraction
-rw-r--r-- | perf-event/src/events.rs | 6 | ||||
-rw-r--r-- | src/energy.rs | 1 | ||||
-rw-r--r-- | src/energy/rapl.rs | 96 | ||||
-rw-r--r-- | src/energy/trackers/perf.rs | 1 |
4 files changed, 100 insertions, 4 deletions
diff --git a/perf-event/src/events.rs b/perf-event/src/events.rs index a46f6b8..25eaa51 100644 --- a/perf-event/src/events.rs +++ b/perf-event/src/events.rs @@ -49,7 +49,7 @@ pub enum Event { Cache(Cache), #[allow(missing_docs)] - Raw(u32), + Raw(u32, u64), } impl Event { @@ -58,7 +58,7 @@ impl Event { Event::Hardware(_) => bindings::PERF_TYPE_HARDWARE, Event::Software(_) => bindings::PERF_TYPE_SOFTWARE, Event::Cache(_) => bindings::PERF_TYPE_HW_CACHE, - Event::Raw(ty) => *ty, + Event::Raw(ty, _) => *ty, } } @@ -66,7 +66,7 @@ impl Event { match self { Event::Hardware(hw) => hw as _, Event::Software(sw) => sw as _, - Event::Raw(_) => 0, + Event::Raw(_, config) => config, Event::Cache(cache) => cache.as_config(), } } diff --git a/src/energy.rs b/src/energy.rs index c8da2cf..c6cb84b 100644 --- a/src/energy.rs +++ b/src/energy.rs @@ -1,4 +1,5 @@ mod budget; +mod rapl; mod trackers; use std::collections::{BTreeSet, HashMap}; diff --git a/src/energy/rapl.rs b/src/energy/rapl.rs new file mode 100644 index 0000000..293a0f7 --- /dev/null +++ b/src/energy/rapl.rs @@ -0,0 +1,96 @@ +use std::fs; +use std::io; +use std::path::Path; + +/// Main structure for CPU package energy monitoring +pub struct PackageEnergy { + /// The perf event type + event_type: u32, + /// The event config + event_config: u64, + /// The scaling factor for joules + scale: f64, +} + +impl PackageEnergy { + /// Initialize a new PackageEnergy monitor + pub fn new() -> io::Result<Self> { + // 1. Check if RAPL is supported via perf events + let type_path = Path::new("/sys/bus/event_source/devices/power/type"); + if !type_path.exists() { + return Err(io::Error::new( + io::ErrorKind::NotFound, + "RAPL perf event support not found (requires Linux 3.14 or newer)", + )); + } + + // 2. Read the perf event type for power + let event_type = fs::read_to_string(type_path)? + .trim() + .parse::<u32>() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + + // 3. Check if package energy domain is available + let event_path = "/sys/bus/event_source/devices/power/events/energy-pkg"; + if !Path::new(event_path).exists() { + return Err(io::Error::new( + io::ErrorKind::NotFound, + "Package energy monitoring not available", + )); + } + + // 4. Read event config + let event_content = fs::read_to_string(event_path)?; + let event_config_str = event_content + .split('=') + .nth(1) + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "Invalid event format"))?; + let event_config = u64::from_str_radix(event_config_str.trim(), 16) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + + // 5. Read scale + let scale_path = format!("{}.scale", event_path); + let scale = if Path::new(&scale_path).exists() { + fs::read_to_string(&scale_path)? + .trim() + .parse::<f64>() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))? + } else { + 1.0 // Default scale if not available + }; + + Ok(PackageEnergy { + event_type, + event_config, + scale, + }) + } + + /// Get the scaling factor for joules + pub fn get_scale(&self) -> f64 { + self.scale + } + + /// Convert raw counter value to joules + pub fn to_joules(&self, raw_value: u64) -> f64 { + raw_value as f64 * self.scale + } + + /// Check if perf_event_paranoid setting might cause permission issues + pub fn check_paranoid() -> io::Result<i32> { + let path = Path::new("/proc/sys/kernel/perf_event_paranoid"); + if !path.exists() { + return Err(io::Error::new( + io::ErrorKind::NotFound, + "perf_event_paranoid file not found", + )); + } + + let value = fs::read_to_string(path)? + .trim() + .parse::<i32>() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + + Ok(value) + } +} diff --git a/src/energy/trackers/perf.rs b/src/energy/trackers/perf.rs index 19ec0be..7c26bdb 100644 --- a/src/energy/trackers/perf.rs +++ b/src/energy/trackers/perf.rs @@ -1,4 +1,3 @@ -// energy/trackers/perf.rs use std::collections::HashMap; use perf_event::{ |