diff options
-rw-r--r-- | Cargo.lock | 4 | ||||
-rw-r--r-- | crates/profile/src/memory_usage.rs | 35 |
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]] |
767 | name = "libc" | 767 | name = "libc" |
768 | version = "0.2.95" | 768 | version = "0.2.97" |
769 | source = "registry+https://github.com/rust-lang/crates.io-index" | 769 | source = "registry+https://github.com/rust-lang/crates.io-index" |
770 | checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" | 770 | checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" |
771 | 771 | ||
772 | [[package]] | 772 | [[package]] |
773 | name = "libloading" | 773 | name = "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"))] | ||
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 | |||
61 | #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] | 90 | #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] |
62 | pub struct Bytes(isize); | 91 | pub struct Bytes(isize); |
63 | 92 | ||