Skip to content

Commit

Permalink
Merge #9204
Browse files Browse the repository at this point in the history
9204: feat: more accurate memory usage info on glibc Linux r=jonas-schievink a=jonas-schievink

This adds support for the new `mallinfo2` API added in glibc 2.33. It addresses a shortcoming in the `mallinfo` API where it was unable to handle memory usage of more than 2 GB, which we sometimes exceed.

Blocked on rust-lang/libc#2228

Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
  • Loading branch information
bors[bot] and jonas-schievink committed Jun 11, 2021
2 parents 72ea028 + 74dc9bb commit 409f5fb
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 5 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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
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

0 comments on commit 409f5fb

Please sign in to comment.