Skip to main content

linux_info/
cpu.rs

1//!
2//! The data is retrieved from `/proc/cpuinfo`
3//!
4//! ```
5//! use linux_info::cpu::Cpu;
6//! let info = Cpu::read().unwrap();
7//! let model_name = info.first_value("model name").unwrap();
8//! // or every model name
9//! let model_names = info.unique_values("model name");
10//! ```
11//!
12//! To list all availabe key's [linuxwiki.org](https://linuxwiki.org/proc/cpuinfo). Or you can use the api
13//! ```
14//! use linux_info::cpu::Cpu;
15//! let info = Cpu::read().expect("no cpu info");
16//!	let first = info.first().expect("no cpu found");
17//! let keys = first.keys();
18//! ```
19
20use crate::util::read_to_string_mut;
21
22use std::path::Path;
23use std::{fs, io};
24
25/// Read cpu information from /proc/cpuinfo.
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct Cpu {
28	raw: String,
29}
30
31impl Cpu {
32	fn path() -> &'static Path {
33		Path::new("/proc/cpuinfo")
34	}
35
36	#[cfg(test)]
37	fn from_string(raw: String) -> Self {
38		Self { raw }
39	}
40
41	/// Reads cpu infos from /proc/cpuinfo.
42	pub fn read() -> io::Result<Self> {
43		Ok(Self {
44			raw: fs::read_to_string(Self::path())?,
45		})
46	}
47
48	/// Reloads information without allocating.
49	pub fn reload(&mut self) -> io::Result<()> {
50		read_to_string_mut(Self::path(), &mut self.raw)
51	}
52
53	/// Main method to get cpu infos. Returns every entry.
54	pub fn entries<'a>(&'a self) -> impl Iterator<Item = CpuEntry<'a>> {
55		self.raw.split("\n\n").map(CpuEntry::from_str)
56	}
57
58	/// Returns the first entry.
59	pub fn first<'a>(&'a self) -> Option<CpuEntry<'a>> {
60		self.entries().next()
61	}
62
63	/// Returns the value of the first.
64	pub fn first_value<'a>(&'a self, key: &str) -> Option<&'a str> {
65		self.first().and_then(|i| i.value(key))
66	}
67
68	/// Returns the unique values to a specific key.
69	pub fn unique_values<'a>(&'a self, key: &str) -> Vec<&'a str> {
70		let mut list = vec![];
71		self.entries()
72			.filter_map(|info| info.value(key))
73			.for_each(|v| {
74				if !list.contains(&v) {
75					list.push(v);
76				}
77			});
78		list
79	}
80
81	/// Returns the amount of cores.
82	pub fn cores(&self) -> usize {
83		self.entries().count()
84	}
85}
86
87#[derive(Debug, Clone, PartialEq, Eq)]
88pub struct CpuEntry<'a> {
89	raw: &'a str,
90}
91
92impl<'a> CpuEntry<'a> {
93	fn from_str(raw: &'a str) -> Self {
94		Self { raw }
95	}
96
97	/// returns every key and valu ein the cpu info
98	pub fn values(&self) -> impl Iterator<Item = Option<(&'a str, &'a str)>> {
99		self.raw.split('\n').map(|line| {
100			// TODO: after 1.52 update tot split_once
101			let mut iter = line.splitn(2, ':');
102			let (key, value) = (iter.next()?, iter.next()?);
103			Some((key.trim(), value.trim()))
104		})
105	}
106
107	/// get a value to it's corresponding key
108	pub fn value(&self, key: &str) -> Option<&'a str> {
109		self.values()
110			.filter_map(|kv| kv)
111			.find_map(|(k, v)| k.eq_ignore_ascii_case(key).then(|| v))
112	}
113
114	/// list all available keys
115	pub fn keys(&self) -> impl Iterator<Item = &'a str> {
116		self.values().filter_map(|kv| kv).map(|(k, _)| k)
117	}
118}
119
120#[cfg(test)]
121mod tests {
122	use super::*;
123
124	fn cpu_info() -> Cpu {
125		Cpu::from_string("\
126processor	: 16
127vendor_id	: AuthenticAMD
128cpu family	: 23
129model		: 113
130model name	: AMD Ryzen 9 3900XT 12-Core Processor
131stepping	: 0
132microcode	: 0x8701021
133cpu MHz		: 2196.035
134cache size	: 512 KB
135physical id	: 0
136siblings	: 24
137core id		: 6
138cpu cores	: 12
139apicid		: 13
140initial apicid	: 13
141fpu		: yes
142fpu_exception	: yes
143cpuid level	: 16
144wp		: yes
145flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate sme ssbd mba sev ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif umip rdpid overflow_recov succor smca
146bugs		: sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass
147bogomips	: 7586.59
148TLB size	: 3072 4K pages
149clflush size	: 64
150cache_alignment	: 64
151address sizes	: 43 bits physical, 48 bits virtual
152power management: ts ttp tm hwpstate cpb eff_freq_ro [13] [14]
153
154processor	: 17
155vendor_id	: AuthenticAMD
156cpu family	: 23
157model		: 113
158model name	: AMD Ryzen 9 3900XT 12-Core Processor
159stepping	: 0
160microcode	: 0x8701021
161cpu MHz		: 2196.035
162cache size	: 512 KB
163physical id	: 0
164siblings	: 24
165core id		: 6
166cpu cores	: 12
167apicid		: 13
168initial apicid	: 13
169fpu		: yes
170fpu_exception	: yes
171cpuid level	: 16
172wp		: yes
173flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate sme ssbd mba sev ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif umip rdpid overflow_recov succor smca
174bugs		: sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass
175bogomips	: 7586.59
176TLB size	: 3072 4K pages
177clflush size	: 64
178cache_alignment	: 64
179address sizes	: 43 bits physical, 48 bits virtual
180power management: ts ttp tm hwpstate cpb eff_freq_ro [13] [14]\n\
181		".into())
182	}
183
184	#[test]
185	fn info_to_vec() {
186		let cpu_info = cpu_info();
187		let v: Vec<_> = cpu_info.entries().collect();
188		assert_eq!(v.len(), 2);
189	}
190
191	#[test]
192	fn info_values() {
193		let info = cpu_info();
194		let mut values = info.entries();
195		let first = values.next().unwrap();
196		println!("first {:?}", first.values().collect::<Vec<_>>());
197		let model_name = first.value("model name").unwrap();
198		assert_eq!(model_name, "AMD Ryzen 9 3900XT 12-Core Processor");
199	}
200
201	#[test]
202	fn count_cores() {
203		let cpu_info = cpu_info();
204		assert_eq!(cpu_info.cores(), 2);
205	}
206
207	#[test]
208	fn unique_values() {
209		let cpu_info = cpu_info();
210		let un = cpu_info.unique_values("model name");
211		assert_eq!(un.len(), 1);
212	}
213}