Skip to content

Commit 35b18b2

Browse files
Add support for mallinfo2 on glibc Linux
1 parent f4da4de commit 35b18b2

File tree

1 file changed

+32
-3
lines changed

1 file changed

+32
-3
lines changed

crates/profile/src/memory_usage.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@ impl MemoryUsage {
3232
allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap() as isize),
3333
}
3434
} else if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
35-
// Note: This is incredibly slow.
36-
let alloc = unsafe { libc::mallinfo() }.uordblks as isize;
37-
MemoryUsage { allocated: Bytes(alloc) }
35+
memusage_linux()
3836
} else if #[cfg(windows)] {
3937
// There doesn't seem to be an API for determining heap usage, so we try to
4038
// approximate that by using the Commit Charge value.
@@ -58,6 +56,37 @@ impl MemoryUsage {
5856
}
5957
}
6058

59+
#[cfg(all(target_os = "linux", target_env = "gnu"))]
60+
fn memusage_linux() -> MemoryUsage {
61+
// Linux/glibc has 2 APIs for allocator introspection that we can use: mallinfo and mallinfo2.
62+
// mallinfo uses `int` fields and cannot handle memory usage exceeding 2 GB.
63+
// mallinfo2 is very recent, so its presence needs to be detected at runtime.
64+
// Both are abysmally slow.
65+
66+
use std::ffi::CStr;
67+
use std::sync::atomic::{AtomicUsize, Ordering};
68+
69+
static MALLINFO2: AtomicUsize = AtomicUsize::new(1);
70+
71+
let mut mallinfo2 = MALLINFO2.load(Ordering::Relaxed);
72+
if mallinfo2 == 1 {
73+
let cstr = CStr::from_bytes_with_nul(b"mallinfo2\0").unwrap();
74+
mallinfo2 = unsafe { libc::dlsym(libc::RTLD_DEFAULT, cstr.as_ptr()) } as usize;
75+
// NB: races don't matter here, since they'll always store the same value
76+
MALLINFO2.store(mallinfo2, Ordering::Relaxed);
77+
}
78+
79+
if mallinfo2 == 0 {
80+
// mallinfo2 does not exist, use mallinfo.
81+
let alloc = unsafe { libc::mallinfo() }.uordblks as isize;
82+
MemoryUsage { allocated: Bytes(alloc) }
83+
} else {
84+
let mallinfo2: fn() -> libc::mallinfo2 = unsafe { std::mem::transmute(mallinfo2) };
85+
let alloc = mallinfo2().uordblks as isize;
86+
MemoryUsage { allocated: Bytes(alloc) }
87+
}
88+
}
89+
6190
#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
6291
pub struct Bytes(isize);
6392

0 commit comments

Comments
 (0)