aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock4
-rw-r--r--crates/profile/src/memory_usage.rs35
2 files changed, 34 insertions, 5 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 12a096ff1..e1d2a74f0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -765,9 +765,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
765 765
766[[package]] 766[[package]]
767name = "libc" 767name = "libc"
768version = "0.2.95" 768version = "0.2.97"
769source = "registry+https://github.com/rust-lang/crates.io-index" 769source = "registry+https://github.com/rust-lang/crates.io-index"
770checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" 770checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
771 771
772[[package]] 772[[package]]
773name = "libloading" 773name = "libloading"
diff --git a/crates/profile/src/memory_usage.rs b/crates/profile/src/memory_usage.rs
index 6ef58c9c1..0b0a196ae 100644
--- a/crates/profile/src/memory_usage.rs
+++ b/crates/profile/src/memory_usage.rs
@@ -32,9 +32,7 @@ impl MemoryUsage {
32 allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap() as isize), 32 allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap() as isize),
33 } 33 }
34 } else if #[cfg(all(target_os = "linux", target_env = "gnu"))] { 34 } else if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
35 // Note: This is incredibly slow. 35 memusage_linux()
36 let alloc = unsafe { libc::mallinfo() }.uordblks as isize;
37 MemoryUsage { allocated: Bytes(alloc) }
38 } else if #[cfg(windows)] { 36 } else if #[cfg(windows)] {
39 // There doesn't seem to be an API for determining heap usage, so we try to 37 // There doesn't seem to be an API for determining heap usage, so we try to
40 // approximate that by using the Commit Charge value. 38 // approximate that by using the Commit Charge value.
@@ -58,6 +56,37 @@ impl MemoryUsage {
58 } 56 }
59} 57}
60 58
59#[cfg(all(target_os = "linux", target_env = "gnu"))]
60fn 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
61#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] 90#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
62pub struct Bytes(isize); 91pub struct Bytes(isize);
63 92