Skip to main content

cbtop/frequency_control/
lock.rs

1//! RAII frequency lock guard for deterministic benchmarks.
2
3use std::path::PathBuf;
4
5use super::controller::FrequencyController;
6use super::governor::CpuGovernor;
7use super::sysfs::governor_path;
8
9/// RAII frequency lock guard
10#[derive(Debug)]
11pub struct FrequencyLock {
12    /// Original governor per CPU
13    original_governors: Vec<(usize, CpuGovernor)>,
14    /// Original frequencies per CPU
15    original_frequencies: Vec<(usize, u64)>,
16    /// Controller reference path
17    sysfs_path: PathBuf,
18    /// Was lock successful
19    locked: bool,
20    /// Mock mode
21    mock_mode: bool,
22}
23
24impl FrequencyLock {
25    /// Try to lock frequency to maximum
26    pub fn try_lock(controller: &FrequencyController) -> Self {
27        let reading = controller.read_all_frequencies();
28
29        let (original_governors, original_frequencies): (Vec<_>, Vec<_>) = reading
30            .cpus
31            .iter()
32            .map(|c| ((c.cpu_id, c.governor), (c.cpu_id, c.current_khz)))
33            .unzip();
34
35        let mut lock = Self {
36            original_governors,
37            original_frequencies,
38            sysfs_path: controller.sysfs_path.clone(),
39            locked: false,
40            mock_mode: controller.mock_mode,
41        };
42
43        if controller.mock_mode {
44            lock.locked = true;
45        } else {
46            lock.locked = lock.try_set_performance();
47        }
48
49        lock
50    }
51
52    /// Try to set performance governor on all CPUs
53    fn try_set_performance(&self) -> bool {
54        for (cpu_id, _) in &self.original_governors {
55            if std::fs::write(governor_path(&self.sysfs_path, *cpu_id), "performance").is_err() {
56                return false;
57            }
58        }
59        true
60    }
61
62    /// Check if lock was successful
63    pub fn is_locked(&self) -> bool {
64        self.locked
65    }
66}
67
68impl Drop for FrequencyLock {
69    fn drop(&mut self) {
70        if !self.locked || self.mock_mode {
71            return;
72        }
73
74        // Restore original governors
75        for (cpu_id, governor) in &self.original_governors {
76            let _ = std::fs::write(governor_path(&self.sysfs_path, *cpu_id), governor.name());
77        }
78    }
79}