Skip to content

Commit f9b8ed2

Browse files
authored
Expose memory usage statistics to Rust via SnMalloc::memory_stats() (#851)
* Expose memory usage statistics to Rust via SnMalloc::memory_stats() Wire up the existing `sn_rust_statistics` C export (already present in rust.cc) to Rust. Adds an FFI binding in snmalloc-sys and a safe `SnMalloc::memory_stats()` associated function in snmalloc-rs that returns an `AllocStats` struct with current and peak OS-level memory reservation figures tracked by StatsRange. No C++ changes required — the backend counters are always active. * Strengthen memory_stats test: assert non-zero current usage and post-dealloc reduction
1 parent 48fd18a commit f9b8ed2

2 files changed

Lines changed: 63 additions & 0 deletions

File tree

snmalloc-rs/snmalloc-sys/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ extern "C" {
4141

4242
/// Return the available bytes in a memory block.
4343
pub fn sn_rust_usable_size(p: *const c_void) -> usize;
44+
45+
/// Write current and peak OS-level memory reservation bytes into the given pointers.
46+
pub fn sn_rust_statistics(
47+
current_memory_usage: *mut usize,
48+
peak_memory_usage: *mut usize,
49+
);
4450
}
4551

4652
#[cfg(feature = "libc-api")]

snmalloc-rs/src/lib.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,18 @@ use core::{
3232
ptr::NonNull,
3333
};
3434

35+
/// Memory usage statistics from the snmalloc backend.
36+
///
37+
/// These are range-level figures (slab/chunk granularity) reflecting bytes
38+
/// reserved from the OS, not the count of live individual allocations.
39+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
40+
pub struct AllocStats {
41+
/// Bytes currently reserved from the OS.
42+
pub current_memory_usage: usize,
43+
/// High-water mark of `current_memory_usage`.
44+
pub peak_memory_usage: usize,
45+
}
46+
3547
#[derive(Debug, Copy, Clone)]
3648
#[repr(C)]
3749
pub struct SnMalloc;
@@ -54,6 +66,15 @@ impl SnMalloc {
5466
}
5567
}
5668

69+
/// Returns current and peak OS-level memory reservation statistics.
70+
/// See [`AllocStats`] for what the values measure.
71+
pub fn memory_stats() -> AllocStats {
72+
let mut current = 0usize;
73+
let mut peak = 0usize;
74+
unsafe { ffi::sn_rust_statistics(&mut current, &mut peak) };
75+
AllocStats { current_memory_usage: current, peak_memory_usage: peak }
76+
}
77+
5778
/// Allocates memory with the given layout, returning a non-null pointer on success
5879
#[inline(always)]
5980
pub fn alloc_aligned(&self, layout: Layout) -> Option<NonNull<u8>> {
@@ -212,4 +233,40 @@ mod tests {
212233
assert!(usz >= 8);
213234
}
214235
}
236+
237+
#[test]
238+
fn test_memory_stats() {
239+
let alloc = SnMalloc::new();
240+
let before = SnMalloc::memory_stats();
241+
242+
let layout = Layout::from_size_align(1 << 20, 64).unwrap();
243+
let ptr = unsafe { alloc.alloc(layout) };
244+
assert!(!ptr.is_null());
245+
246+
let during = SnMalloc::memory_stats();
247+
assert!(
248+
during.current_memory_usage > 0,
249+
"current usage should be non-zero after allocation"
250+
);
251+
assert!(
252+
during.current_memory_usage >= before.current_memory_usage,
253+
"current usage should not decrease after allocation"
254+
);
255+
assert!(
256+
during.peak_memory_usage >= before.peak_memory_usage,
257+
"peak usage should not decrease after allocation"
258+
);
259+
260+
unsafe { alloc.dealloc(ptr, layout) };
261+
262+
let after = SnMalloc::memory_stats();
263+
assert!(
264+
after.current_memory_usage <= during.current_memory_usage,
265+
"current usage should decrease after dealloc"
266+
);
267+
assert!(
268+
after.peak_memory_usage >= during.peak_memory_usage,
269+
"peak usage should never decrease"
270+
);
271+
}
215272
}

0 commit comments

Comments
 (0)