summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Kobert <dennis@kobert.dev>2025-03-09 15:21:58 +0100
committerDennis Kobert <dennis@kobert.dev>2025-03-09 15:21:58 +0100
commit7af8a52e2ff92518b8c737dfe74d9ed68d5f4943 (patch)
tree3a5522a4bd5e4d2865de8a7f86d1f92a129c30c2
parentb720a1253fb8cc8a3ba3454014bad239233368c1 (diff)
Implement rapl abstraction
-rw-r--r--perf-event/src/events.rs6
-rw-r--r--src/energy.rs1
-rw-r--r--src/energy/rapl.rs96
-rw-r--r--src/energy/trackers/perf.rs1
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::{