From 2be87e1071e8f4f258ce97ce23d89abc48ee635c Mon Sep 17 00:00:00 2001 From: Jaya Kasa Date: Wed, 27 May 2026 14:21:20 -0400 Subject: [PATCH 1/2] Expose memory usage statistics to Rust via SnMalloc::memory_stats() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- snmalloc-rs/snmalloc-sys/src/lib.rs | 6 ++++ snmalloc-rs/src/lib.rs | 49 +++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/snmalloc-rs/snmalloc-sys/src/lib.rs b/snmalloc-rs/snmalloc-sys/src/lib.rs index 394a61fa0..3c2cc7b36 100644 --- a/snmalloc-rs/snmalloc-sys/src/lib.rs +++ b/snmalloc-rs/snmalloc-sys/src/lib.rs @@ -41,6 +41,12 @@ extern "C" { /// Return the available bytes in a memory block. pub fn sn_rust_usable_size(p: *const c_void) -> usize; + + /// Write current and peak OS-level memory reservation bytes into the given pointers. + pub fn sn_rust_statistics( + current_memory_usage: *mut usize, + peak_memory_usage: *mut usize, + ); } #[cfg(feature = "libc-api")] diff --git a/snmalloc-rs/src/lib.rs b/snmalloc-rs/src/lib.rs index c4ab77411..38ef87d01 100644 --- a/snmalloc-rs/src/lib.rs +++ b/snmalloc-rs/src/lib.rs @@ -32,6 +32,18 @@ use core::{ ptr::NonNull, }; +/// Memory usage statistics from the snmalloc backend. +/// +/// These are range-level figures (slab/chunk granularity) reflecting bytes +/// reserved from the OS, not the count of live individual allocations. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct AllocStats { + /// Bytes currently reserved from the OS. + pub current_memory_usage: usize, + /// High-water mark of `current_memory_usage`. + pub peak_memory_usage: usize, +} + #[derive(Debug, Copy, Clone)] #[repr(C)] pub struct SnMalloc; @@ -54,6 +66,15 @@ impl SnMalloc { } } + /// Returns current and peak OS-level memory reservation statistics. + /// See [`AllocStats`] for what the values measure. + pub fn memory_stats() -> AllocStats { + let mut current = 0usize; + let mut peak = 0usize; + unsafe { ffi::sn_rust_statistics(&mut current, &mut peak) }; + AllocStats { current_memory_usage: current, peak_memory_usage: peak } + } + /// Allocates memory with the given layout, returning a non-null pointer on success #[inline(always)] pub fn alloc_aligned(&self, layout: Layout) -> Option> { @@ -212,4 +233,32 @@ mod tests { assert!(usz >= 8); } } + + #[test] + fn test_memory_stats() { + let alloc = SnMalloc::new(); + let before = SnMalloc::memory_stats(); + + let layout = Layout::from_size_align(1 << 20, 64).unwrap(); + let ptr = unsafe { alloc.alloc(layout) }; + assert!(!ptr.is_null()); + + let during = SnMalloc::memory_stats(); + assert!( + during.current_memory_usage >= before.current_memory_usage, + "current usage should not decrease after allocation" + ); + assert!( + during.peak_memory_usage >= before.peak_memory_usage, + "peak usage should not decrease after allocation" + ); + + unsafe { alloc.dealloc(ptr, layout) }; + + let after = SnMalloc::memory_stats(); + assert!( + after.peak_memory_usage >= during.peak_memory_usage, + "peak usage should never decrease" + ); + } } From 512877a5969e20ba69eca5ed71a07c1113944d38 Mon Sep 17 00:00:00 2001 From: Jaya Kasa Date: Wed, 27 May 2026 14:35:19 -0400 Subject: [PATCH 2/2] Strengthen memory_stats test: assert non-zero current usage and post-dealloc reduction --- snmalloc-rs/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/snmalloc-rs/src/lib.rs b/snmalloc-rs/src/lib.rs index 38ef87d01..467c4ef54 100644 --- a/snmalloc-rs/src/lib.rs +++ b/snmalloc-rs/src/lib.rs @@ -244,6 +244,10 @@ mod tests { assert!(!ptr.is_null()); let during = SnMalloc::memory_stats(); + assert!( + during.current_memory_usage > 0, + "current usage should be non-zero after allocation" + ); assert!( during.current_memory_usage >= before.current_memory_usage, "current usage should not decrease after allocation" @@ -256,6 +260,10 @@ mod tests { unsafe { alloc.dealloc(ptr, layout) }; let after = SnMalloc::memory_stats(); + assert!( + after.current_memory_usage <= during.current_memory_usage, + "current usage should decrease after dealloc" + ); assert!( after.peak_memory_usage >= during.peak_memory_usage, "peak usage should never decrease"