use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicIsize, Ordering};
struct CountingAllocator;
static LIVE: AtomicIsize = AtomicIsize::new(0);
static PEAK: AtomicIsize = AtomicIsize::new(0);
unsafe impl GlobalAlloc for CountingAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let pointer = unsafe { System.alloc(layout) };
if !pointer.is_null() {
record(layout.size() as isize);
}
pointer
}
unsafe fn dealloc(&self, pointer: *mut u8, layout: Layout) {
LIVE.fetch_sub(layout.size() as isize, Ordering::Relaxed);
unsafe { System.dealloc(pointer, layout) }
}
unsafe fn realloc(&self, pointer: *mut u8, old: Layout, size: usize) -> *mut u8 {
let result = unsafe { System.realloc(pointer, old, size) };
if !result.is_null() {
record(size as isize - old.size() as isize);
}
result
}
}
#[global_allocator]
static ALLOCATOR: CountingAllocator = CountingAllocator;
fn record(delta: isize) {
let live = LIVE.fetch_add(delta, Ordering::Relaxed) + delta;
PEAK.fetch_max(live, Ordering::Relaxed);
}
pub(crate) fn begin() -> isize {
let baseline = LIVE.load(Ordering::Relaxed);
PEAK.store(baseline, Ordering::Relaxed);
baseline
}
pub(crate) fn finish(baseline: isize) -> usize {
PEAK.load(Ordering::Relaxed).saturating_sub(baseline) as usize
}