mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 04:23:25 +00:00
Merge #9204
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 https://github.com/rust-lang/libc/pull/2228 Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
This commit is contained in:
commit
409f5fb563
2 changed files with 34 additions and 5 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -765,9 +765,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.95"
|
||||
version = "0.2.97"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
|
||||
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
|
|
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue