Skip to main content

linux_info/
memory.rs

1//!
2//! The data is retrieved from `/proc/meminfo`
3//!
4//! To list all availabe key's [linuxwiki.org](https://linuxwiki.org/proc/meminfo). Or you can use the api
5//! ```
6//! use linux_info::memory::Memory;
7//! let info = Memory::read().unwrap();
8//! let keys = info.keys();
9//! ```
10
11use crate::unit::DataSize;
12use crate::util::read_to_string_mut;
13
14use std::path::Path;
15use std::{fs, io};
16
17/// Read memory information from /proc/meminfo.
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Memory {
20	raw: String,
21}
22
23impl Memory {
24	fn path() -> &'static Path {
25		Path::new("/proc/meminfo")
26	}
27
28	#[cfg(test)]
29	fn from_string(raw: String) -> Self {
30		Self { raw }
31	}
32
33	/// Read memory infos from /proc/meminfo.
34	pub fn read() -> io::Result<Self> {
35		Ok(Self {
36			raw: fs::read_to_string(Self::path())?,
37		})
38	}
39
40	/// Reloads information without allocating.
41	pub fn reload(&mut self) -> io::Result<()> {
42		read_to_string_mut(Self::path(), &mut self.raw)
43	}
44
45	/// Get all key and values.
46	pub fn values<'a>(&'a self) -> impl Iterator<Item = (&'a str, &'a str)> {
47		self.raw.split('\n').filter_map(|line| {
48			// TODO: after 1.52 update tot split_once
49			let mut iter = line.splitn(2, ':');
50			let (key, value) = (iter.next()?, iter.next()?);
51			Some((key.trim(), value.trim()))
52		})
53	}
54
55	/// get all keys.
56	pub fn keys<'a>(&'a self) -> impl Iterator<Item = &'a str> {
57		self.values().map(|(k, _)| k)
58	}
59
60	/// Get value by key.
61	pub fn value<'a>(&'a self, key: &str) -> Option<&'a str> {
62		self.values()
63			.find_map(|(k, v)| k.eq_ignore_ascii_case(key).then(|| v))
64	}
65
66	/// Get size by key.
67	pub fn size_value<'a>(&'a self, key: &str) -> Option<DataSize> {
68		self.value(key).and_then(DataSize::from_str)
69	}
70
71	/// Returns the total memory.
72	pub fn total_memory(&self) -> Option<DataSize> {
73		self.size_value("MemTotal")
74	}
75
76	/// Returns the free memory.
77	pub fn free_memory(&self) -> Option<DataSize> {
78		self.size_value("MemFree")
79	}
80
81	/// Returns the available memory.
82	pub fn available_memory(&self) -> Option<DataSize> {
83		self.size_value("MemAvailable")
84	}
85}
86
87#[cfg(test)]
88mod tests {
89	use super::*;
90	use crate::unit::DataSizeUnit;
91
92	fn memory_info() -> Memory {
93		Memory::from_string(
94			"\
95MemTotal:       32853280 kB
96MemFree:          919776 kB
97MemAvailable:   28781828 kB
98Buffers:          298460 kB
99Cached:         27104800 kB
100SwapCached:          168 kB
101Active:          7764012 kB
102Inactive:       22289624 kB
103Active(anon):    2257064 kB
104Inactive(anon):   624500 kB
105Active(file):    5506948 kB
106Inactive(file): 21665124 kB
107Unevictable:          16 kB
108Mlocked:              16 kB
109SwapTotal:       2097148 kB
110SwapFree:        2094844 kB
111Dirty:               360 kB
112Writeback:             0 kB
113AnonPages:       2650504 kB
114Mapped:           760008 kB
115Shmem:            231188 kB
116KReclaimable:    1154740 kB
117Slab:            1529684 kB
118SReclaimable:    1154740 kB
119SUnreclaim:       374944 kB
120KernelStack:       21600 kB
121PageTables:        31948 kB
122NFS_Unstable:          0 kB
123Bounce:                0 kB
124WritebackTmp:          0 kB
125CommitLimit:    18523788 kB
126Committed_AS:    9191380 kB
127VmallocTotal:   34359738367 kB
128VmallocUsed:       62668 kB
129VmallocChunk:          0 kB
130Percpu:            37376 kB
131HardwareCorrupted:     0 kB
132AnonHugePages:         0 kB
133ShmemHugePages:        0 kB
134ShmemPmdMapped:        0 kB
135FileHugePages:         0 kB
136FilePmdMapped:         0 kB
137HugePages_Total:       0
138HugePages_Free:        0
139HugePages_Rsvd:        0
140HugePages_Surp:        0
141Hugepagesize:       2048 kB
142Hugetlb:               0 kB
143DirectMap4k:      922564 kB
144DirectMap2M:    10518528 kB
145DirectMap1G:    22020096 kB\
146		"
147			.into(),
148		)
149	}
150
151	#[test]
152	fn total_memory() {
153		let mem_info = memory_info();
154		let total_memory = mem_info.total_memory().unwrap();
155		assert_eq!(total_memory.to(&DataSizeUnit::Kb), 32853280.0);
156	}
157}