use std::os::unix::ffi::OsStrExt;
use std::fs;
use std::io;
use std::str;
use std::ops;
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
#[cfg(feature = "serde")]
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct CpuFrequency {
pub cpu_id: Option<u64>,
pub current: Frequency,
pub min: Option<Frequency>,
pub max: Option<Frequency>,
}
#[cfg(not(feature = "serde"))]
#[derive(Debug, Default)]
pub struct CpuFrequency {
pub cpu_id: Option<u64>,
pub current: Frequency,
pub min: Option<Frequency>,
pub max: Option<Frequency>,
}
impl ops::Add<CpuFrequency> for CpuFrequency {
type Output = CpuFrequency;
fn add(self, rhs: CpuFrequency) -> CpuFrequency {
let current = self.current + rhs.current;
let min = match (self.min, rhs.min) {
(Some(left), Some(right)) => Some(left + right),
(Some(left), None) => Some(left),
(None, Some(right)) => Some(right),
(None, None) => None,
};
let max = match (self.max, rhs.max) {
(Some(left), Some(right)) => Some(left + right),
(Some(left), None) => Some(left),
(None, Some(right)) => Some(right),
(None, None) => None,
};
CpuFrequency {
cpu_id: None,
current,
max,
min,
}
}
}
#[cfg(not(feature = "serde"))]
#[derive(Copy, Clone, Debug, Default, PartialOrd, PartialEq)]
pub struct Frequency(pub u64);
#[cfg(feature = "serde")]
#[derive(Copy, Clone, Debug, Default, PartialOrd, PartialEq, Serialize, Deserialize)]
pub struct Frequency(pub u64);
#[doc(hidden)]
impl Frequency {
pub fn from_kilohertzs(value: u64) -> Self {
Self(value * 1_000)
}
pub fn from_megahertzs(value: u64) -> Self {
Self(value * 1_000_000)
}
}
impl ops::Add<Frequency> for Frequency {
type Output = Frequency;
fn add(self, rhs: Frequency) -> Self::Output{
Frequency(self.0 + rhs.0)
}
}
pub fn frequency() -> io::Result<CpuFrequency> {
let init = CpuFrequency::default();
let freqs = frequencies()?;
let len = freqs.len();
let mut init = freqs.into_iter().fold(init, |init, f| {
init + f
});
init.current = Frequency::from_kilohertzs(init.current.0 / len as u64);
init.min = init.min.map(|v| Frequency::from_kilohertzs(v.0 / len as u64));
init.max = init.max.map(|v| Frequency::from_kilohertzs(v.0 / len as u64));
Ok(init)
}
pub fn frequencies() -> io::Result<Vec<CpuFrequency>> {
let mut vec = vec![];
let dirs = fs::read_dir("/sys/devices/system/cpu/")?;
for dir in dirs {
let dir = dir?;
let path = dir.path();
if let Some(file_name) = path.file_name() {
if file_name.as_bytes().starts_with(b"cpu") {
let core_id = unsafe { str::from_utf8_unchecked(&file_name.as_bytes()[3..]) };
if let Ok(id) = core_id.parse::<u64>() {
let mut cpufreq = CpuFrequency::default();
cpufreq.cpu_id = Some(id);
let path = path.join("cpufreq");
let path1 = path.join("scaling_cur_freq");
let content = fs::read_to_string(path1)?;
if let Ok(freq) = content.trim().parse::<u64>() {
cpufreq.current = Frequency::from_kilohertzs(freq);
}
let path2 = path.join("scaling_min_freq");
if let Ok(content) = fs::read_to_string(path2) {
if let Ok(freq) = content.trim().parse::<u64>() {
cpufreq.min = Some(Frequency::from_kilohertzs(freq));
}
}
let path2 = path.join("scaling_max_freq");
if let Ok(content) = fs::read_to_string(path2) {
if let Ok(freq) = content.trim().parse::<u64>() {
cpufreq.max = Some(Frequency::from_kilohertzs(freq));
}
}
vec.push(cpufreq)
}
}
}
}
Ok(vec)
}