refactor(uucore): integrate procfs for Linux memory parsing

This commit is contained in:
mattsu
2025-10-18 21:00:43 +09:00
parent 6e422b728e
commit 12c43fd4b5
3 changed files with 69 additions and 19 deletions
Generated
+25
View File
@@ -2331,6 +2331,30 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "procfs"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25485360a54d6861439d60facef26de713b1e126bf015ec8f98239467a2b82f7"
dependencies = [
"bitflags 2.9.1",
"chrono",
"flate2",
"procfs-core",
"rustix",
]
[[package]]
name = "procfs-core"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6401bf7b6af22f78b563665d15a22e9aef27775b79b149a66ca022468a4e405"
dependencies = [
"bitflags 2.9.1",
"chrono",
"hex",
]
[[package]]
name = "quote"
version = "1.0.41"
@@ -4329,6 +4353,7 @@ dependencies = [
"num-traits",
"number_prefix",
"os_display",
"procfs",
"selinux",
"sha1",
"sha2",
+3
View File
@@ -101,6 +101,9 @@ xattr = { workspace = true, optional = true }
[dev-dependencies]
tempfile = { workspace = true }
[target.'cfg(target_os = "linux")'.dependencies]
procfs = "0.18"
[target.'cfg(target_os = "windows")'.dependencies]
winapi-util = { workspace = true, optional = true }
windows-sys = { workspace = true, optional = true, default-features = false, features = [
@@ -8,16 +8,17 @@
use std::error::Error;
use std::fmt;
#[cfg(target_os = "linux")]
use std::io::BufRead;
use std::num::{IntErrorKind, ParseIntError};
use crate::display::Quotable;
#[cfg(target_os = "linux")]
use procfs::{Current, Meminfo};
/// Error arising from trying to compute system memory.
enum SystemError {
IOError,
ParseError,
#[cfg(not(target_os = "linux"))]
NotFound,
}
@@ -43,25 +44,37 @@ impl From<ParseIntError> for SystemError {
/// entry in the file.
#[cfg(target_os = "linux")]
fn total_physical_memory() -> Result<u128, SystemError> {
// On Linux, the `/proc/meminfo` file has a table with information
// about memory usage. For example,
//
// MemTotal: 7811500 kB
// MemFree: 1487876 kB
// MemAvailable: 3857232 kB
// ...
//
// We just need to extract the number of `MemTotal`
let table = std::fs::read("/proc/meminfo")?;
for line in table.lines() {
let line = line?;
if line.starts_with("MemTotal:") && line.ends_with("kB") {
let num_kilobytes: u128 = line[9..line.len() - 2].trim().parse()?;
let num_bytes = 1024 * num_kilobytes;
return Ok(num_bytes);
let info = Meminfo::current().map_err(|_| SystemError::IOError)?;
Ok((info.mem_total as u128).saturating_mul(1024))
}
/// Return the number of bytes of memory that appear to be currently available.
#[cfg(target_os = "linux")]
pub fn available_memory_bytes() -> Option<u128> {
let info = Meminfo::current().ok()?;
if let Some(available_kib) = info.mem_available {
let available_bytes = (available_kib as u128).saturating_mul(1024);
if available_bytes > 0 {
return Some(available_bytes);
}
}
Err(SystemError::NotFound)
let fallback_kib = (info.mem_free as u128)
.saturating_add(info.buffers as u128)
.saturating_add(info.cached as u128);
if fallback_kib > 0 {
Some(fallback_kib.saturating_mul(1024))
} else {
total_physical_memory().ok()
}
}
/// Return `None` when the platform does not expose Linux-like `/proc/meminfo`.
#[cfg(not(target_os = "linux"))]
pub fn available_memory_bytes() -> Option<u128> {
None
}
/// Get the total number of bytes of physical memory.
@@ -361,6 +374,15 @@ pub fn parse_size_u64(size: &str) -> Result<u64, ParseSizeError> {
Parser::default().parse_u64(size)
}
/// Same as `parse_size_u64()`, except 0 fails to parse
pub fn parse_size_non_zero_u64(size: &str) -> Result<u64, ParseSizeError> {
let v = Parser::default().parse_u64(size)?;
if v == 0 {
return Err(ParseSizeError::ParseFailure("0".to_string()));
}
Ok(v)
}
/// Same as `parse_size_u64()` - deprecated
#[deprecated = "Please use parse_size_u64(size: &str) -> Result<u64, ParseSizeError> OR parse_size_u128(size: &str) -> Result<u128, ParseSizeError> instead."]
pub fn parse_size(size: &str) -> Result<u64, ParseSizeError> {