diff options
-rw-r--r-- | src/energy.rs | 44 | ||||
-rw-r--r-- | src/energy/budget.rs | 15 | ||||
-rw-r--r-- | src/energy/rapl.rs | 10 | ||||
-rw-r--r-- | src/scheduler.rs | 2 |
4 files changed, 59 insertions, 12 deletions
diff --git a/src/energy.rs b/src/energy.rs index c6cb84b..64ec267 100644 --- a/src/energy.rs +++ b/src/energy.rs @@ -11,7 +11,10 @@ use crate::Pid; use anyhow::Result; use dashmap::DashMap; +use crate::energy::rapl::PackageEnergy; pub use budget::BudgetPolicy; +use perf_event::events::Event; +use perf_event::{Builder, Counter}; pub use trackers::{Estimator, KernelDriver, MockEstimator, PerfEstimator}; pub enum Request { @@ -27,12 +30,14 @@ pub struct ProcessInfo { pub struct EnergyService { estimator: Box<dyn Estimator>, - budget_policy: Box<dyn BudgetPolicy>, + budget_policy: Option<Box<dyn BudgetPolicy>>, active_processes: BTreeSet<Pid>, process_info: HashMap<Pid, ProcessInfo>, shared_budgets: Arc<DashMap<Pid, u64>>, request_receiver: mpsc::Receiver<Request>, update_interval: Duration, + package_energy: PackageEnergy, + package_energy_counter: Counter, } impl EnergyService { @@ -42,15 +47,19 @@ impl EnergyService { shared_budgets: Arc<DashMap<Pid, u64>>, request_receiver: mpsc::Receiver<Request>, update_interval: Duration, + package_energy: PackageEnergy, + package_energy_counter: Counter, ) -> Self { Self { estimator, - budget_policy, + budget_policy: Some(budget_policy), active_processes: BTreeSet::new(), process_info: HashMap::new(), shared_budgets, request_receiver, update_interval, + package_energy, + package_energy_counter, } } @@ -115,7 +124,10 @@ impl EnergyService { } fn update_budgets(&mut self) { - let budgets = self.budget_policy.calculate_budgets(self); + // We can't call self.budget_policy.calculate_budgets(self) directly because the first self borrows immutable and the self second borrows mutable + let policy = self.budget_policy.take().unwrap(); + let budgets = policy.calculate_budgets(self); + self.budget_policy = Some(policy); // Update the shared budgets map for (pid, budget) in budgets { @@ -130,6 +142,11 @@ impl EnergyService { &self.active_processes } + fn package_energy(&mut self) -> f64 { + self.package_energy + .to_joules(self.package_energy_counter.read().unwrap_or(0)) + } + pub fn process_energy(&self, pid: Pid) -> Option<u64> { self.process_info.get(&pid).map(|info| info.energy) } @@ -146,7 +163,7 @@ pub fn start_energy_service( use_mocking: bool, power_cap: u64, shared_budgets: Arc<DashMap<Pid, u64>>, -) -> mpsc::SyncSender<Request> { +) -> std::io::Result<mpsc::SyncSender<Request>> { // Potentially convert back to bounded channel let (request_sender, request_receiver) = mpsc::sync_channel(10000); @@ -160,6 +177,21 @@ pub fn start_energy_service( // Create budget policy let budget_policy = Box::new(budget::SimpleCappingPolicy::new(power_cap)); + // shouldn't be a problem because we are privileged + // if PackageEnergy::check_paranoid().unwrap_or(3) > 0 {} + + let package_energy = PackageEnergy::new().unwrap(); + + // Any cpu should be fine because the package power should be the same for every cpu + let mut package_energy_counter = Builder::new() + .kind(Event::Raw( + package_energy.get_type(), + package_energy.get_event_config(), + )) + .any_cpu() + .build()?; + package_energy_counter.enable()?; + // Create and start the energy service let service = EnergyService::new( estimator, @@ -167,9 +199,11 @@ pub fn start_energy_service( shared_budgets, request_receiver, Duration::from_millis(50), // 50ms update interval + package_energy, + package_energy_counter, ); service.run(); - request_sender + Ok(request_sender) } diff --git a/src/energy/budget.rs b/src/energy/budget.rs index aada2eb..7a2c7e2 100644 --- a/src/energy/budget.rs +++ b/src/energy/budget.rs @@ -5,7 +5,7 @@ use crate::energy::EnergyService; type Pid = i32; pub trait BudgetPolicy: Send + 'static { - fn calculate_budgets(&self, energy_service: &EnergyService) -> HashMap<Pid, u64>; + fn calculate_budgets(&self, energy_service: &mut EnergyService) -> HashMap<Pid, u64>; } pub struct SimpleCappingPolicy { @@ -19,21 +19,24 @@ impl SimpleCappingPolicy { } impl BudgetPolicy for SimpleCappingPolicy { - fn calculate_budgets(&self, energy_service: &EnergyService) -> HashMap<Pid, u64> { + fn calculate_budgets(&self, energy_service: &mut EnergyService) -> HashMap<Pid, u64> { let mut budgets = HashMap::new(); let process_energies = energy_service.all_process_energies(); // Total energy consumption across all processes - let total_energy: u64 = process_energies.values().sum(); + //let total_energy: u64 = process_energies.values().sum(); + + let actual_energy = + energy_service.package_energy() / energy_service.update_interval.as_secs_f64(); // Simple proportional distribution if over cap - if total_energy > self.power_cap { - let ratio = self.power_cap as f64 / total_energy as f64; + if actual_energy > self.power_cap as f64 { + let ratio = self.power_cap as f64 / actual_energy as f64; for (&pid, &energy) in &process_energies { // Calculate a scaled budget based on the ratio // Higher energy consumers get proportionally reduced budgets - let scaling_factor = 1.0 - ((energy as f64 / total_energy as f64) * (1.0 - ratio)); + let scaling_factor = 1.0 - ((energy as f64 / actual_energy) * (1.0 - ratio)); let budget = (u64::MAX as f64 * scaling_factor) as u64; budgets.insert(pid, budget); } diff --git a/src/energy/rapl.rs b/src/energy/rapl.rs index 293a0f7..34b128e 100644 --- a/src/energy/rapl.rs +++ b/src/energy/rapl.rs @@ -76,6 +76,16 @@ impl PackageEnergy { raw_value as f64 * self.scale } + /// Get the perf event type + pub fn get_type(&self) -> u32 { + self.event_type + } + + /// Get the event config + pub fn get_event_config(&self) -> u64 { + self.event_config + } + /// 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"); diff --git a/src/scheduler.rs b/src/scheduler.rs index 8618b78..0cc9522 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -56,7 +56,7 @@ impl<'a> Scheduler<'a> { // Start energy tracking service let energy_sender = - energy::start_energy_service(use_mocking, power_cap, shared_budgets.clone()); + energy::start_energy_service(use_mocking, power_cap, shared_budgets.clone())?; let topology = Topology::new().unwrap(); let mut e_core_ids = Vec::new(); |