Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: more accurate memory usage info on glibc Linux #9204

Merged
merged 2 commits into from Jun 11, 2021
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 32 additions & 3 deletions crates/profile/src/memory_usage.rs
Expand Up @@ -32,9 +32,7 @@ impl MemoryUsage {
allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap() as isize),
}
} else if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
// Note: This is incredibly slow.
let alloc = unsafe { libc::mallinfo() }.uordblks as isize;
MemoryUsage { allocated: Bytes(alloc) }
memusage_linux()
} else if #[cfg(windows)] {
// There doesn't seem to be an API for determining heap usage, so we try to
// approximate that by using the Commit Charge value.
Expand All @@ -58,6 +56,37 @@ impl MemoryUsage {
}
}

#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn memusage_linux() -> MemoryUsage {
// Linux/glibc has 2 APIs for allocator introspection that we can use: mallinfo and mallinfo2.
// mallinfo uses `int` fields and cannot handle memory usage exceeding 2 GB.
// mallinfo2 is very recent, so its presence needs to be detected at runtime.
// Both are abysmally slow.

use std::ffi::CStr;
use std::sync::atomic::{AtomicUsize, Ordering};

static MALLINFO2: AtomicUsize = AtomicUsize::new(1);

let mut mallinfo2 = MALLINFO2.load(Ordering::Relaxed);
if mallinfo2 == 1 {
let cstr = CStr::from_bytes_with_nul(b"mallinfo2\0").unwrap();
mallinfo2 = unsafe { libc::dlsym(libc::RTLD_DEFAULT, cstr.as_ptr()) } as usize;
// NB: races don't matter here, since they'll always store the same value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting! OnceCell sort-of has a type for this, but using it would seem to be more awkward: https://docs.rs/once_cell/1.7.2/once_cell/race/struct.OnceNonZeroUsize.html

MALLINFO2.store(mallinfo2, Ordering::Relaxed);
}

if mallinfo2 == 0 {
// mallinfo2 does not exist, use mallinfo.
let alloc = unsafe { libc::mallinfo() }.uordblks as isize;
MemoryUsage { allocated: Bytes(alloc) }
} else {
let mallinfo2: fn() -> libc::mallinfo2 = unsafe { std::mem::transmute(mallinfo2) };
let alloc = mallinfo2().uordblks as isize;
MemoryUsage { allocated: Bytes(alloc) }
}
}

#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
pub struct Bytes(isize);

Expand Down