Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_sys/src/mem.rs

3.1 KiB, 1 run

created by r1870400018:10586, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//! Memory accounting from `/proc/meminfo`.
2
3use crate::parse::{
4 parse_num,
5 read_to_string,
6};
7
8use oxedyne_fe2o3_core::prelude::*;
9
10/// Snapshot of the key memory figures reported by the kernel.
11/// All values are in bytes; the `/proc/meminfo` kB values are
12/// multiplied on ingest so downstream consumers never have to
13/// worry about the unit.
14#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
15pub struct MemInfo {
16 /// Total usable RAM.
17 pub total: u64,
18 /// Free RAM (no use by kernel or user).
19 pub free: u64,
20 /// Kernel's best guess at actually free RAM including
21 /// reclaimable page cache and buffers.
22 pub available: u64,
23 /// Block-device buffers.
24 pub buffers: u64,
25 /// Page cache.
26 pub cached: u64,
27 /// Total swap space configured.
28 pub swap_total: u64,
29 /// Swap currently in use.
30 pub swap_free: u64,
31}
32
33impl MemInfo {
34 /// Read `/proc/meminfo` and parse the key fields.
35 pub fn sample() -> Outcome<Self> {
36 let content = res!(read_to_string("/proc/meminfo"));
37 Self::from_meminfo(&content)
38 }
39
40 /// Parse a `/proc/meminfo` body. Each line has the form
41 /// `Name: <value> kB`; unknown names are ignored.
42 pub fn from_meminfo(content: &str) -> Outcome<Self> {
43 let mut out = Self::default();
44 for line in content.lines() {
45 let (name, rest) = match line.split_once(':') {
46 Some(t) => t,
47 None => continue,
48 };
49 let mut iter = rest.split_whitespace();
50 let value = match iter.next() {
51 Some(v) => v,
52 None => continue,
53 };
54 let kb = res!(parse_num::<u64>(value, name.trim()));
55 let bytes = kb.saturating_mul(1024);
56 match name.trim() {
57 "MemTotal" => out.total = bytes,
58 "MemFree" => out.free = bytes,
59 "MemAvailable" => out.available = bytes,
60 "Buffers" => out.buffers = bytes,
61 "Cached" => out.cached = bytes,
62 "SwapTotal" => out.swap_total = bytes,
63 "SwapFree" => out.swap_free = bytes,
64 _ => (),
65 }
66 }
67 if out.total == 0 {
68 return Err(err!(
69 "/proc/meminfo did not contain a MemTotal field.";
70 Input, Missing, Decode));
71 }
72 Ok(out)
73 }
74
75 /// Bytes actually in use by processes and the kernel,
76 /// approximated as `total - available`. Prefer this over
77 /// `total - free` which double-counts page cache as "used".
78 pub fn used(&self) -> u64 {
79 self.total.saturating_sub(self.available)
80 }
81
82 /// Used memory as a fraction (0..=1) of total.
83 pub fn used_fraction(&self) -> f64 {
84 if self.total == 0 {
85 0.0
86 } else {
87 self.used() as f64 / self.total as f64
88 }
89 }
90
91 /// Swap currently in use, in bytes.
92 pub fn swap_used(&self) -> u64 {
93 self.swap_total.saturating_sub(self.swap_free)
94 }
95}