use std::hint::black_box;
use std::thread;
use stoolap_jemalloc::{Jemalloc, prof};
#[global_allocator]
static GLOBAL: Jemalloc = Jemalloc::new();
#[inline(never)]
fn leaky_function(n: usize) -> Vec<Vec<u8>> {
(0..n).map(|i| vec![i as u8; 4096]).collect()
}
#[test]
fn profile_records_live_allocations() {
assert!(prof::dump_pprof().is_err());
prof::set_sample_interval(64 * 1024);
prof::activate();
let kept = black_box(leaky_function(10_000));
let workers: Vec<_> = (0..4)
.map(|_| {
thread::spawn(|| {
for i in 0..20_000 {
black_box(vec![0u8; 1000 + i % 5000]);
}
})
})
.collect();
for w in workers {
w.join().unwrap();
}
let profile = prof::dump_pprof().unwrap();
assert!(profile.len() > 100);
let text = String::from_utf8_lossy(&profile);
for name in [
"inuse_space",
"alloc_space",
"inuse_objects",
"alloc_objects",
] {
assert!(text.contains(name), "{name}");
}
#[cfg(feature = "symbolize")]
assert!(
text.contains("leaky_function"),
"symbol names are in the profile"
);
let path = std::env::temp_dir().join(format!("stoolap-jemalloc-{}.pb", std::process::id()));
let written = prof::write_pprof(&path).unwrap();
assert_eq!(std::fs::metadata(&path).unwrap().len() as usize, written);
if let Some(dir) = std::env::var_os("PPROF_OUT") {
std::fs::copy(&path, std::path::Path::new(&dir).join("heap.pb")).unwrap();
}
std::fs::remove_file(&path).unwrap();
drop(kept);
prof::deactivate();
let mut v = Vec::new();
for i in 0..100_000 {
v.push(vec![i as u8; 100]);
}
drop(v);
}