lscpu: Read CPU count from sysfs, add freq_boost status to output

This commit is contained in:
alxndrv
2025-02-13 18:55:26 +02:00
parent 3980e7714f
commit e689bee771
2 changed files with 81 additions and 10 deletions
src/uu/lscpu/src

@ -7,7 +7,6 @@ use clap::{crate_version, Arg, ArgAction, Command};
use regex::RegexBuilder;
use serde::Serialize;
use std::{cmp, fs};
use sysinfo::System;
use uucore::{error::UResult, format_usage, help_about, help_usage};
mod options {
@ -72,8 +71,6 @@ struct OutputOptions {
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?;
let system = System::new_all();
let output_opts = OutputOptions {
_hex: matches.get_flag(options::HEX),
json: matches.get_flag(options::JSON),
@ -91,18 +88,16 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
arch_info.add_child(CpuInfo::new("Address sizes", &addr_sizes, None))
}
if let Ok(byte_order) = fs::read_to_string("/sys/kernel/cpu_byteorder") {
match byte_order.trim() {
"big" => arch_info.add_child(CpuInfo::new("Byte Order", "Big Endian", None)),
"little" => arch_info.add_child(CpuInfo::new("Byte Order", "Little Endian", None)),
_ => eprintln!("Unrecognised Byte Order: {}", byte_order),
}
if let Some(byte_order) = sysfs::read_cpu_byte_order() {
arch_info.add_child(CpuInfo::new("Byte Order", byte_order, None));
}
let cpu_topology = sysfs::read_cpu_topology();
cpu_infos.push(arch_info);
cpu_infos.push(CpuInfo::new(
"CPU(s)",
&format!("{}", system.cpus().len()),
&format!("{}", cpu_topology.cpus.len()),
None,
));
@ -123,6 +118,15 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
model_name_info.add_child(CpuInfo::new("Model", &model, None));
}
if let Some(freq_boost_enabled) = sysfs::read_freq_boost_state() {
let s = if freq_boost_enabled {
"enabled"
} else {
"disabled"
};
model_name_info.add_child(CpuInfo::new("Frequency boost", s, None));
}
vendor_info.add_child(model_name_info);
}
cpu_infos.push(vendor_info);
@ -211,6 +215,8 @@ fn find_cpuinfo_value(contents: &str, key: &str) -> Option<String> {
value
}
// TODO: This is non-exhaustive and assumes that compile-time arch is the same as runtime
// This is not always guaranteed to be the case, ie. you can run a x86 binary on a x86_64 machine
fn get_architecture() -> String {
if cfg!(target_arch = "x86") {
"x86".to_string()

@ -5,6 +5,60 @@ pub struct CpuVulnerability {
pub mitigation: String,
}
pub struct CpuTopology {
pub cpus: Vec<Cpu>,
}
pub struct Cpu {
_index: usize,
_caches: Vec<CpuCache>,
}
pub struct CpuCache {
_index: usize,
_typ: String,
_level: String,
_size: String,
}
// TODO: This should go through each CPU in sysfs and calculate things such as cache sizes and physical topology
// For now it just returns a list of CPUs which are enabled
pub fn read_cpu_topology() -> CpuTopology {
let mut out: Vec<Cpu> = vec![];
// NOTE: All examples I could find was where this file contains a CPU index range in the form of `<start>-<end>`
// Theoretically, there might be a situation where some cores are disabled, so that `enabled` cannot be represented
// as a continuous range. For now we just assume it's always `X-Y` and use those as our bounds to read CPU information
let enabled_cpus = match fs::read_to_string("/sys/devices/system/cpu/enabled") {
Ok(content) => {
let parts: Vec<_> = content
.trim()
.split("-")
.flat_map(|part| part.parse::<usize>())
.collect();
assert_eq!(parts.len(), 2);
(parts[0], parts[1])
}
Err(e) => panic!("Could not read sysfs: {}", e),
};
for cpu_index in enabled_cpus.0..(enabled_cpus.1 + 1) {
out.push(Cpu {
_index: cpu_index,
_caches: vec![],
})
}
CpuTopology { cpus: out }
}
pub fn read_freq_boost_state() -> Option<bool> {
match fs::read_to_string("/sys/devices/system/cpu/cpufreq/boost") {
Ok(content) => Some(content.trim() == "1"),
Err(_) => None,
}
}
pub fn read_cpu_vulnerabilities() -> Vec<CpuVulnerability> {
let mut out: Vec<CpuVulnerability> = vec![];
@ -31,3 +85,14 @@ pub fn read_cpu_vulnerabilities() -> Vec<CpuVulnerability> {
out
}
pub fn read_cpu_byte_order() -> Option<&'static str> {
if let Ok(byte_order) = fs::read_to_string("/sys/kernel/cpu_byteorder") {
match byte_order.trim() {
"big" => return Some("Big Endian"),
"little" => return Some("Little Endian"),
_ => eprintln!("Unrecognised Byte Order: {}", byte_order),
}
}
None
}