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
33	fn path() -> &'static Path {
34		Path::new("/proc/cpuinfo")
35	}
36
37	#[cfg(test)]
38	fn from_string(raw: String) -> Self {
39		Self {raw}
40	}
41
42	/// Reads cpu infos from /proc/cpuinfo.
43	pub fn read() -> io::Result<Self> {
44		Ok(Self {
45			raw: fs::read_to_string(Self::path())?
46		})
47	}
48
49	/// Reloads information without allocating.
50	pub fn reload(&mut self) -> io::Result<()> {
51		read_to_string_mut(Self::path(), &mut self.raw)
52	}
53
54	/// Main method to get cpu infos. Returns every entry.
55	pub fn entries<'a>(&'a self) -> impl Iterator<Item=CpuEntry<'a>> {
56		self.raw.split("\n\n")
57			.map(CpuEntry::from_str)
58	}
59
60	/// Returns the first entry.
61	pub fn first<'a>(&'a self) -> Option<CpuEntry<'a>> {
62		self.entries().next()
63	}
64
65	/// Returns the value of the first.
66	pub fn first_value<'a>(&'a self, key: &str) -> Option<&'a str> {
67		self.first()
68			.and_then(|i| i.value(key))
69	}
70
71	/// Returns the unique values to a specific key.
72	pub fn unique_values<'a>(&'a self, key: &str) -> Vec<&'a str> {
73		let mut list = vec![];
74		self.entries()
75			.filter_map(|info| info.value(key))
76			.for_each(|v| {
77				if !list.contains(&v) {
78					list.push(v);
79				}
80			});
81		list
82	}
83
84	/// Returns the amount of cores.
85	pub fn cores(&self) -> usize {
86		self.entries().count()
87	}
88
89}
90
91#[derive(Debug, Clone, PartialEq, Eq)]
92pub struct CpuEntry<'a> {
93	raw: &'a str
94}
95
96impl<'a> CpuEntry<'a> {
97
98	fn from_str(raw: &'a str) -> Self {
99		Self {raw}
100	}
101
102	/// returns every key and valu ein the cpu info
103	pub fn values(&self) -> impl Iterator<Item=Option<(&'a str, &'a str)>> {
104		self.raw.split('\n')
105			.map(|line| {
106				// TODO: after 1.52 update tot split_once
107				let mut iter = line.splitn(2, ':');
108				let (key, value) = (iter.next()?, iter.next()?);
109				Some((key.trim(), value.trim()))
110			})
111	}
112
113	/// get a value to it's corresponding key
114	pub fn value(&self, key: &str) -> Option<&'a str> {
115		self.values()
116			.filter_map(|kv| kv)
117			.find_map(|(k, v)| k.eq_ignore_ascii_case(key).then(|| v))
118	}
119
120	/// list all available keys
121	pub fn keys(&self) -> impl Iterator<Item=&'a str> {
122		self.values()
123			.filter_map(|kv| kv)
124			.map(|(k, _)| k)
125	}
126
127}
128
129#[cfg(test)]
130mod tests {
131	use super::*;
132
133	fn cpu_info() -> Cpu {
134		Cpu::from_string("\
135processor	: 16
136vendor_id	: AuthenticAMD
137cpu family	: 23
138model		: 113
139model name	: AMD Ryzen 9 3900XT 12-Core Processor
140stepping	: 0
141microcode	: 0x8701021
142cpu MHz		: 2196.035
143cache size	: 512 KB
144physical id	: 0
145siblings	: 24
146core id		: 6
147cpu cores	: 12
148apicid		: 13
149initial apicid	: 13
150fpu		: yes
151fpu_exception	: yes
152cpuid level	: 16
153wp		: yes
154flags		: 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
155bugs		: sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass
156bogomips	: 7586.59
157TLB size	: 3072 4K pages
158clflush size	: 64
159cache_alignment	: 64
160address sizes	: 43 bits physical, 48 bits virtual
161power management: ts ttp tm hwpstate cpb eff_freq_ro [13] [14]
162
163processor	: 17
164vendor_id	: AuthenticAMD
165cpu family	: 23
166model		: 113
167model name	: AMD Ryzen 9 3900XT 12-Core Processor
168stepping	: 0
169microcode	: 0x8701021
170cpu MHz		: 2196.035
171cache size	: 512 KB
172physical id	: 0
173siblings	: 24
174core id		: 6
175cpu cores	: 12
176apicid		: 13
177initial apicid	: 13
178fpu		: yes
179fpu_exception	: yes
180cpuid level	: 16
181wp		: yes
182flags		: 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
183bugs		: sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass
184bogomips	: 7586.59
185TLB size	: 3072 4K pages
186clflush size	: 64
187cache_alignment	: 64
188address sizes	: 43 bits physical, 48 bits virtual
189power management: ts ttp tm hwpstate cpb eff_freq_ro [13] [14]\n\
190		".into())
191	}
192
193	#[test]
194	fn info_to_vec() {
195		let cpu_info = cpu_info();
196		let v: Vec<_> = cpu_info.entries().collect();
197		assert_eq!(v.len(), 2);
198	}
199
200	#[test]
201	fn info_values() {
202		let info = cpu_info();
203		let mut values = info.entries();
204		let first = values.next().unwrap();
205		println!("first {:?}", first.values().collect::<Vec<_>>());
206		let model_name = first.value("model name").unwrap();
207		assert_eq!(model_name, "AMD Ryzen 9 3900XT 12-Core Processor");
208	}
209
210	#[test]
211	fn count_cores() {
212		let cpu_info = cpu_info();
213		assert_eq!(cpu_info.cores(), 2);
214	}
215
216	#[test]
217	fn unique_values() {
218		let cpu_info = cpu_info();
219		let un = cpu_info.unique_values("model name");
220		assert_eq!(un.len(), 1);
221	}
222
223}