Skip to content

Commit 12c43fd

Browse files
committed
refactor(uucore): integrate procfs for Linux memory parsing
1 parent 6e422b7 commit 12c43fd

3 files changed

Lines changed: 69 additions & 19 deletions

File tree

Cargo.lock

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/uucore/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ xattr = { workspace = true, optional = true }
101101
[dev-dependencies]
102102
tempfile = { workspace = true }
103103

104+
[target.'cfg(target_os = "linux")'.dependencies]
105+
procfs = "0.18"
106+
104107
[target.'cfg(target_os = "windows")'.dependencies]
105108
winapi-util = { workspace = true, optional = true }
106109
windows-sys = { workspace = true, optional = true, default-features = false, features = [

src/uucore/src/lib/features/parser/parse_size.rs

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@
88
99
use std::error::Error;
1010
use std::fmt;
11-
#[cfg(target_os = "linux")]
12-
use std::io::BufRead;
1311
use std::num::{IntErrorKind, ParseIntError};
1412

1513
use crate::display::Quotable;
14+
#[cfg(target_os = "linux")]
15+
use procfs::{Current, Meminfo};
1616

1717
/// Error arising from trying to compute system memory.
1818
enum SystemError {
1919
IOError,
2020
ParseError,
21+
#[cfg(not(target_os = "linux"))]
2122
NotFound,
2223
}
2324

@@ -43,25 +44,37 @@ impl From<ParseIntError> for SystemError {
4344
/// entry in the file.
4445
#[cfg(target_os = "linux")]
4546
fn total_physical_memory() -> Result<u128, SystemError> {
46-
// On Linux, the `/proc/meminfo` file has a table with information
47-
// about memory usage. For example,
48-
//
49-
// MemTotal: 7811500 kB
50-
// MemFree: 1487876 kB
51-
// MemAvailable: 3857232 kB
52-
// ...
53-
//
54-
// We just need to extract the number of `MemTotal`
55-
let table = std::fs::read("/proc/meminfo")?;
56-
for line in table.lines() {
57-
let line = line?;
58-
if line.starts_with("MemTotal:") && line.ends_with("kB") {
59-
let num_kilobytes: u128 = line[9..line.len() - 2].trim().parse()?;
60-
let num_bytes = 1024 * num_kilobytes;
61-
return Ok(num_bytes);
47+
let info = Meminfo::current().map_err(|_| SystemError::IOError)?;
48+
Ok((info.mem_total as u128).saturating_mul(1024))
49+
}
50+
51+
/// Return the number of bytes of memory that appear to be currently available.
52+
#[cfg(target_os = "linux")]
53+
pub fn available_memory_bytes() -> Option<u128> {
54+
let info = Meminfo::current().ok()?;
55+
56+
if let Some(available_kib) = info.mem_available {
57+
let available_bytes = (available_kib as u128).saturating_mul(1024);
58+
if available_bytes > 0 {
59+
return Some(available_bytes);
6260
}
6361
}
64-
Err(SystemError::NotFound)
62+
63+
let fallback_kib = (info.mem_free as u128)
64+
.saturating_add(info.buffers as u128)
65+
.saturating_add(info.cached as u128);
66+
67+
if fallback_kib > 0 {
68+
Some(fallback_kib.saturating_mul(1024))
69+
} else {
70+
total_physical_memory().ok()
71+
}
72+
}
73+
74+
/// Return `None` when the platform does not expose Linux-like `/proc/meminfo`.
75+
#[cfg(not(target_os = "linux"))]
76+
pub fn available_memory_bytes() -> Option<u128> {
77+
None
6578
}
6679

6780
/// Get the total number of bytes of physical memory.
@@ -361,6 +374,15 @@ pub fn parse_size_u64(size: &str) -> Result<u64, ParseSizeError> {
361374
Parser::default().parse_u64(size)
362375
}
363376

377+
/// Same as `parse_size_u64()`, except 0 fails to parse
378+
pub fn parse_size_non_zero_u64(size: &str) -> Result<u64, ParseSizeError> {
379+
let v = Parser::default().parse_u64(size)?;
380+
if v == 0 {
381+
return Err(ParseSizeError::ParseFailure("0".to_string()));
382+
}
383+
Ok(v)
384+
}
385+
364386
/// Same as `parse_size_u64()` - deprecated
365387
#[deprecated = "Please use parse_size_u64(size: &str) -> Result<u64, ParseSizeError> OR parse_size_u128(size: &str) -> Result<u128, ParseSizeError> instead."]
366388
pub fn parse_size(size: &str) -> Result<u64, ParseSizeError> {

0 commit comments

Comments
 (0)