1use anyhow::{anyhow, Result};
7use std::fs::{File, OpenOptions};
8use std::io::Write;
9use std::path::Path;
10
11pub fn update_global_idle_resume_latency(value_us: i32) -> Result<File> {
15 if value_us < 0 {
16 return Err(anyhow!("Latency value must be non-negative"));
17 }
18
19 let mut file = OpenOptions::new()
20 .write(true)
21 .open("/dev/cpu_dma_latency")?;
22 let bytes = value_us.to_le_bytes(); file.write_all(&bytes)?;
24 Ok(file) }
26
27pub fn update_cpu_idle_resume_latency(cpu_num: usize, value_us: i32) -> Result<()> {
29 if value_us < 0 {
30 return Err(anyhow!("Latency value must be non-negative"));
31 }
32
33 let path = format!("/sys/devices/system/cpu/cpu{cpu_num}/power/pm_qos_resume_latency_us");
34
35 let mut file = File::create(Path::new(&path))?;
36 write!(file, "{value_us}")?;
37 Ok(())
38}
39
40pub fn cpu_idle_resume_latency_supported() -> bool {
42 std::fs::exists("/sys/devices/system/cpu/cpu0/power/pm_qos_resume_latency_us").unwrap_or(false)
43}
44
45const INTEL_UNCORE_FREQ_PATH: &str = "/sys/devices/system/cpu/intel_uncore_frequency";
46
47pub fn uncore_freq_supported() -> bool {
49 std::fs::exists(INTEL_UNCORE_FREQ_PATH).unwrap_or(false)
50}
51
52pub fn get_uncore_max_freq_khz(package: u32, die: u32) -> Result<u32> {
54 let path = format!(
55 "{}/package_{:02}_die_{:02}/initial_max_freq_khz",
56 INTEL_UNCORE_FREQ_PATH, package, die
57 );
58 let content = std::fs::read_to_string(&path)?;
59 content
60 .trim()
61 .parse()
62 .map_err(|e| anyhow!("Failed to parse uncore freq: {}", e))
63}
64
65pub fn get_uncore_min_freq_khz(package: u32, die: u32) -> Result<u32> {
67 let path = format!(
68 "{}/package_{:02}_die_{:02}/initial_min_freq_khz",
69 INTEL_UNCORE_FREQ_PATH, package, die
70 );
71 let content = std::fs::read_to_string(&path)?;
72 content
73 .trim()
74 .parse()
75 .map_err(|e| anyhow!("Failed to parse uncore freq: {}", e))
76}
77
78pub fn set_uncore_max_freq_khz(package: u32, die: u32, freq_khz: u32) -> Result<()> {
80 let path = format!(
81 "{}/package_{:02}_die_{:02}/max_freq_khz",
82 INTEL_UNCORE_FREQ_PATH, package, die
83 );
84 let mut file = File::create(Path::new(&path))?;
85 write!(file, "{freq_khz}")?;
86 Ok(())
87}
88
89pub fn for_each_uncore_domain<F>(mut f: F) -> Result<()>
91where
92 F: FnMut(u32, u32) -> Result<()>,
93{
94 let entries = std::fs::read_dir(INTEL_UNCORE_FREQ_PATH)?;
95 for entry in entries {
96 let entry = entry?;
97 let name = entry.file_name();
98 let name = name.to_string_lossy();
99 if let Some(rest) = name.strip_prefix("package_") {
100 let parts: Vec<&str> = rest.split("_die_").collect();
101 if parts.len() == 2 {
102 if let (Ok(pkg), Ok(die)) = (parts[0].parse::<u32>(), parts[1].parse::<u32>()) {
103 f(pkg, die)?;
104 }
105 }
106 }
107 }
108 Ok(())
109}
110
111const INTEL_PSTATE_PATH: &str = "/sys/devices/system/cpu/intel_pstate";
112
113pub fn turbo_supported() -> bool {
115 std::fs::exists(format!("{}/no_turbo", INTEL_PSTATE_PATH)).unwrap_or(false)
116}
117
118pub fn get_turbo_enabled() -> Result<bool> {
120 let content = std::fs::read_to_string(format!("{}/no_turbo", INTEL_PSTATE_PATH))?;
121 Ok(content.trim() == "0")
122}
123
124pub fn set_turbo_enabled(enabled: bool) -> Result<()> {
126 let value = if enabled { "0" } else { "1" };
127 std::fs::write(format!("{}/no_turbo", INTEL_PSTATE_PATH), value)?;
128 Ok(())
129}
130
131pub fn epp_supported() -> bool {
133 std::fs::exists("/sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference")
134 .unwrap_or(false)
135}
136
137pub fn get_epp(cpu: usize) -> Result<String> {
139 let path = format!(
140 "/sys/devices/system/cpu/cpu{}/cpufreq/energy_performance_preference",
141 cpu
142 );
143 Ok(std::fs::read_to_string(&path)?.trim().to_string())
144}
145
146pub fn set_epp(cpu: usize, epp: &str) -> Result<()> {
148 let path = format!(
149 "/sys/devices/system/cpu/cpu{}/cpufreq/energy_performance_preference",
150 cpu
151 );
152 std::fs::write(&path, epp)?;
153 Ok(())
154}