#![allow(dead_code)]
use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;
pub static TEST_LOCK: Mutex<()> = Mutex::new(());
static ALLOC_CALLS: AtomicUsize = AtomicUsize::new(0);
static DEALLOC_CALLS: AtomicUsize = AtomicUsize::new(0);
static BYTES_ALLOCATED: AtomicUsize = AtomicUsize::new(0);
static BYTES_FREED: AtomicUsize = AtomicUsize::new(0);
pub struct CountingAllocator;
unsafe impl GlobalAlloc for CountingAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
ALLOC_CALLS.fetch_add(1, Ordering::Relaxed);
BYTES_ALLOCATED.fetch_add(layout.size(), Ordering::Relaxed);
unsafe { System.alloc(layout) }
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
DEALLOC_CALLS.fetch_add(1, Ordering::Relaxed);
BYTES_FREED.fetch_add(layout.size(), Ordering::Relaxed);
unsafe { System.dealloc(ptr, layout) }
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
ALLOC_CALLS.fetch_add(1, Ordering::Relaxed);
BYTES_ALLOCATED.fetch_add(layout.size(), Ordering::Relaxed);
unsafe { System.alloc_zeroed(layout) }
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
ALLOC_CALLS.fetch_add(1, Ordering::Relaxed);
BYTES_ALLOCATED.fetch_add(new_size, Ordering::Relaxed);
BYTES_FREED.fetch_add(layout.size(), Ordering::Relaxed);
unsafe { System.realloc(ptr, layout, new_size) }
}
}
#[derive(Debug, Clone, Copy)]
pub struct Snapshot {
alloc_calls: usize,
dealloc_calls: usize,
bytes_allocated: usize,
bytes_freed: usize,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Delta {
pub allocs: usize,
pub deallocs: usize,
pub bytes: usize,
pub freed: usize,
}
impl Delta {
pub fn resident(&self) -> usize {
self.bytes.saturating_sub(self.freed)
}
}
pub fn snapshot() -> Snapshot {
Snapshot {
alloc_calls: ALLOC_CALLS.load(Ordering::Relaxed),
dealloc_calls: DEALLOC_CALLS.load(Ordering::Relaxed),
bytes_allocated: BYTES_ALLOCATED.load(Ordering::Relaxed),
bytes_freed: BYTES_FREED.load(Ordering::Relaxed),
}
}
impl Snapshot {
pub fn delta_to(&self, later: Snapshot) -> Delta {
Delta {
allocs: later.alloc_calls.saturating_sub(self.alloc_calls),
deallocs: later.dealloc_calls.saturating_sub(self.dealloc_calls),
bytes: later.bytes_allocated.saturating_sub(self.bytes_allocated),
freed: later.bytes_freed.saturating_sub(self.bytes_freed),
}
}
}
pub fn measure<F, R>(f: F) -> (R, Delta)
where
F: FnOnce() -> R,
{
let before = snapshot();
let result = f();
let after = snapshot();
(result, before.delta_to(after))
}