Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions libmimalloc-sys/src/extended.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,12 @@ extern "C" {
///
/// Note: This function is thread safe.
pub fn mi_register_error(out: mi_error_fun, arg: *mut c_void);

/// Get the statistics for the current subprocess aggregated over all its heaps as JSON.
///
/// Returns pointer to the buffer or NULL on failure. Use mi_free() to free the buffer if the buf parameter was NULL.
#[cfg(not(feature = "v2"))]
pub fn mi_stats_get_json(buf_size: usize, buf: *mut c_char) -> *mut c_char;
}

/// An output callback. Must be thread-safe.
Expand Down Expand Up @@ -1088,6 +1094,7 @@ extern "C" {

#[cfg(test)]
mod tests {
use super::super::mi_malloc;
use super::*;

#[test]
Expand Down
6 changes: 6 additions & 0 deletions libmimalloc-sys/sys-test/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,11 @@ fn main() {
}
});

if version == "v3" {
cfg.header("mimalloc-stats.h").include(format!(
"{cargo_manifest_dir}/../c_src/mimalloc/{version}/include"
));
}

cfg.generate("../src/lib.rs", "all.rs");
}
53 changes: 53 additions & 0 deletions src/extended.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::MiMalloc;
use core::ffi::c_void;
#[cfg(not(feature = "v2"))]
use core::ffi::{c_char, CStr};

impl MiMalloc {
/// Get the mimalloc version.
Expand All @@ -17,6 +19,48 @@ impl MiMalloc {
pub unsafe fn usable_size(&self, ptr: *const u8) -> usize {
ffi::mi_usable_size(ptr as *const c_void)
}

/// Extract a string containing the JSON statistics for the whole process
///
/// Allocates (using mimalloc itself) to store the JSON structure.
#[cfg(not(feature = "v2"))]
pub fn stats_json() -> Result<StatsJson, &'static str> {
unsafe {
let buf = ffi::mi_stats_get_json(0, core::ptr::null::<c_char>() as *mut _);
if let Some(inner) = core::ptr::NonNull::new(buf) {
Ok(StatsJson { inner })
} else {
Err("failed to call mi_stats_get_json")
}
}
}
}

#[cfg(not(feature = "v2"))]
/// Wrapper around the output of `MiMalloc::stats_json()`
///
/// Derefs to a CStr
pub struct StatsJson {
inner: core::ptr::NonNull<c_char>,
}

#[cfg(not(feature = "v2"))]
impl core::ops::Deref for StatsJson {
type Target = CStr;

fn deref(&self) -> &Self::Target {
unsafe {
let cstr = CStr::from_ptr(self.inner.as_ptr());
&cstr
}
}
}

#[cfg(not(feature = "v2"))]
impl Drop for StatsJson {
fn drop(&mut self) {
unsafe { ffi::mi_free(self.inner.as_ptr() as _) }
}
}

#[cfg(test)]
Expand All @@ -43,4 +87,13 @@ mod test {
assert!(usable_size >= 8);
}
}

#[test]
#[cfg(not(feature = "v2"))]
fn test_stats_json() {
let stats = MiMalloc::stats_json().expect("should get stats");
let slice = stats.to_str().expect("should be valid UTF-8");
assert_eq!(slice.chars().next(), Some('{'));
assert!(stats.count_bytes() > 1);
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
//! own benchmarks.
//!
//! To enable secure mode, put in `Cargo.toml`:
//! ```rust,ignore
//! ```toml
//! [dependencies]
//! mimalloc = { version = "*", features = ["secure"] }
//! ```
Expand Down
Loading