refactor: switch to manual implementation of meminfo parse (#548)

Manually parse `/proc/meminfo` for the purposes of memory usage.
This commit is contained in:
Clement Tsang 2021-07-17 22:27:40 -04:00 committed by GitHub
parent 7f24e62867
commit 2736dc9b35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 8 deletions

1
Cargo.lock generated
View File

@ -258,6 +258,7 @@ dependencies = [
"procfs",
"regex",
"serde",
"smol",
"sysinfo",
"thiserror",
"toml",

View File

@ -68,8 +68,9 @@ log = { version = "0.4.14", optional = true }
libc = "0.2.86"
[target.'cfg(target_os = "linux")'.dependencies]
heim = { version = "0.1.0-rc.1", features = ["cpu", "disk", "memory", "net", "sensors"] }
heim = { version = "0.1.0-rc.1", features = ["cpu", "disk", "net", "sensors"] }
procfs = "0.9.1"
smol = "1.2.5"
[target.'cfg(target_os = "macos")'.dependencies]
heim = { version = "0.1.0-rc.1", features = ["cpu", "disk", "memory", "net"] }

View File

@ -8,7 +8,7 @@ The memory widget provides a visual representation of RAM and swap usage over ti
## Features
The legend displays the current usage in terms of percentage and actual usage.
The legend displays the current usage in terms of percentage and actual usage in binary units (KiB, MiB, GiB, etc.).
If the total RAM or swap available is 0, then it is automatically hidden from the legend and graph.
One can also adjust the displayed time range through either the keyboard or mouse, with a range of 30s to 600s.

View File

@ -26,7 +26,48 @@ pub async fn get_ram_data() -> crate::utils::error::Result<Option<MemHarvest>> {
let (mem_total_in_kib, mem_used_in_kib) = {
#[cfg(target_os = "linux")]
{
let mem_info = procfs::Meminfo::new()?;
use smol::fs::read_to_string;
let meminfo = read_to_string("/proc/meminfo").await?;
// All values are in KiB by default.
let mut mem_total = 0;
let mut cached = 0;
let mut s_reclaimable = 0;
let mut shmem = 0;
let mut buffers = 0;
let mut mem_free = 0;
let mut keys_read: u8 = 0;
const TOTAL_KEYS_NEEDED: u8 = 6;
for line in meminfo.lines() {
if let Some((label, value)) = line.split_once(':') {
let to_write = match label {
"MemTotal" => &mut mem_total,
"MemFree" => &mut mem_free,
"Buffers" => &mut buffers,
"Cached" => &mut cached,
"Shmem" => &mut shmem,
"SReclaimable" => &mut s_reclaimable,
_ => {
continue;
}
};
if let Some((number, _unit)) = value.trim_start().split_once(' ') {
// Parse the value, remember it's in KiB!
if let Ok(number) = number.parse::<u64>() {
*to_write = number;
// We only need a few keys, so we can bail early.
keys_read += 1;
if keys_read == TOTAL_KEYS_NEEDED {
break;
}
}
}
}
}
// Let's preface this by saying that memory usage calculations are... not straightforward.
// There are conflicting implementations everywhere.
@ -39,14 +80,13 @@ pub async fn get_ram_data() -> crate::utils::error::Result<Option<MemHarvest>> {
// Another implementation, commonly used in other things, is to skip the shmem part of the calculation,
// which matches gopsutil and stuff like free.
let total = mem_info.mem_total / 1024;
let cached_mem =
mem_info.cached + mem_info.s_reclaimable.unwrap_or(0) - mem_info.shmem.unwrap_or(0);
let used_diff = (mem_info.mem_free + cached_mem + mem_info.buffers) / 1024;
let total = mem_total;
let cached_mem = cached + s_reclaimable - shmem;
let used_diff = mem_free + cached_mem + buffers;
let used = if total >= used_diff {
total - used_diff
} else {
total - mem_info.mem_free
total - mem_free
};
(total, used)