2024-06-22 19:28:26 +00:00
|
|
|
//! jemalloc allocator
|
|
|
|
|
2024-04-27 04:50:20 -07:00
|
|
|
use std::ffi::{c_char, c_void};
|
|
|
|
|
|
|
|
use tikv_jemalloc_sys as ffi;
|
|
|
|
use tikv_jemallocator as jemalloc;
|
|
|
|
|
|
|
|
#[global_allocator]
|
|
|
|
static JEMALLOC: jemalloc::Jemalloc = jemalloc::Jemalloc;
|
|
|
|
|
2024-05-09 15:59:08 -07:00
|
|
|
#[must_use]
|
2024-08-18 17:36:33 -04:00
|
|
|
#[cfg(feature = "jemalloc_stats")]
|
2024-07-09 21:55:56 +00:00
|
|
|
pub fn memory_usage() -> Option<String> {
|
2024-04-27 04:50:20 -07:00
|
|
|
use mallctl::stats;
|
2024-08-18 17:36:33 -04:00
|
|
|
use tikv_jemalloc_ctl as mallctl;
|
2024-07-07 06:17:58 +00:00
|
|
|
|
|
|
|
let mibs = |input: Result<usize, mallctl::Error>| {
|
|
|
|
let input = input.unwrap_or_default();
|
|
|
|
let kibs = input / 1024;
|
|
|
|
let kibs = u32::try_from(kibs).unwrap_or_default();
|
|
|
|
let kibs = f64::from(kibs);
|
|
|
|
kibs / 1024.0
|
|
|
|
};
|
|
|
|
|
|
|
|
let allocated = mibs(stats::allocated::read());
|
|
|
|
let active = mibs(stats::active::read());
|
|
|
|
let mapped = mibs(stats::mapped::read());
|
|
|
|
let metadata = mibs(stats::metadata::read());
|
|
|
|
let resident = mibs(stats::resident::read());
|
|
|
|
let retained = mibs(stats::retained::read());
|
2024-07-09 21:55:56 +00:00
|
|
|
Some(format!(
|
2024-07-07 06:17:58 +00:00
|
|
|
"allocated: {allocated:.2} MiB\nactive: {active:.2} MiB\nmapped: {mapped:.2} MiB\nmetadata: {metadata:.2} \
|
|
|
|
MiB\nresident: {resident:.2} MiB\nretained: {retained:.2} MiB\n"
|
2024-07-09 21:55:56 +00:00
|
|
|
))
|
2024-04-27 04:50:20 -07:00
|
|
|
}
|
|
|
|
|
2024-08-18 17:36:33 -04:00
|
|
|
#[must_use]
|
|
|
|
#[cfg(not(feature = "jemalloc_stats"))]
|
|
|
|
pub fn memory_usage() -> Option<String> { None }
|
|
|
|
|
2024-05-09 15:59:08 -07:00
|
|
|
#[must_use]
|
2024-07-09 21:55:56 +00:00
|
|
|
pub fn memory_stats() -> Option<String> {
|
2024-04-27 04:50:20 -07:00
|
|
|
const MAX_LENGTH: usize = 65536 - 4096;
|
|
|
|
|
|
|
|
let opts_s = "d";
|
2024-04-27 22:03:30 -07:00
|
|
|
let mut str = String::new();
|
2024-04-27 04:50:20 -07:00
|
|
|
|
2024-04-28 11:48:06 -04:00
|
|
|
let opaque = std::ptr::from_mut(&mut str).cast::<c_void>();
|
2024-06-02 00:30:04 +00:00
|
|
|
let opts_p: *const c_char = std::ffi::CString::new(opts_s)
|
|
|
|
.expect("cstring")
|
|
|
|
.into_raw()
|
|
|
|
.cast_const();
|
2024-04-27 22:03:30 -07:00
|
|
|
|
2024-04-28 01:31:24 -04:00
|
|
|
// SAFETY: calls malloc_stats_print() with our string instance which must remain
|
|
|
|
// in this frame. https://docs.rs/tikv-jemalloc-sys/latest/tikv_jemalloc_sys/fn.malloc_stats_print.html
|
2024-04-27 04:50:20 -07:00
|
|
|
unsafe { ffi::malloc_stats_print(Some(malloc_stats_cb), opaque, opts_p) };
|
|
|
|
|
|
|
|
str.truncate(MAX_LENGTH);
|
2024-07-09 21:55:56 +00:00
|
|
|
Some(format!("<pre><code>{str}</code></pre>"))
|
2024-04-27 04:50:20 -07:00
|
|
|
}
|
|
|
|
|
2024-12-12 10:22:30 -05:00
|
|
|
unsafe extern "C" fn malloc_stats_cb(opaque: *mut c_void, msg: *const c_char) {
|
2024-04-27 22:03:30 -07:00
|
|
|
// SAFETY: we have to trust the opaque points to our String
|
2024-04-28 11:48:06 -04:00
|
|
|
let res: &mut String = unsafe { opaque.cast::<String>().as_mut().unwrap() };
|
2024-04-27 22:03:30 -07:00
|
|
|
|
|
|
|
// SAFETY: we have to trust the string is null terminated.
|
2024-04-27 04:50:20 -07:00
|
|
|
let msg = unsafe { std::ffi::CStr::from_ptr(msg) };
|
2024-04-27 22:03:30 -07:00
|
|
|
|
2024-04-27 04:50:20 -07:00
|
|
|
let msg = String::from_utf8_lossy(msg.to_bytes());
|
|
|
|
res.push_str(msg.as_ref());
|
|
|
|
}
|