#[cfg(feature = "std")]
use core::alloc::{GlobalAlloc, Layout};
use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
pub const CAP: usize = 131_072;
static HEAP_LIVE: AtomicUsize = AtomicUsize::new(0);
#[cfg(any(feature = "std", target_arch = "wasm32"))]
static PEAK_END: AtomicUsize = AtomicUsize::new(0);
#[cfg(feature = "std")]
fn note_alloc(ptr: *mut u8, size: usize) {
HEAP_LIVE.fetch_add(size, Relaxed);
PEAK_END.fetch_max(ptr as usize + size, Relaxed);
}
pub struct TrackingAlloc;
#[cfg(feature = "std")]
unsafe impl GlobalAlloc for TrackingAlloc {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let p = std::alloc::System.alloc(layout);
if !p.is_null() {
note_alloc(p, layout.size());
}
p
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
let p = std::alloc::System.alloc_zeroed(layout);
if !p.is_null() {
note_alloc(p, layout.size());
}
p
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
std::alloc::System.dealloc(ptr, layout);
HEAP_LIVE.fetch_sub(layout.size(), Relaxed);
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
let p = std::alloc::System.realloc(ptr, layout, new_size);
if !p.is_null() {
HEAP_LIVE.fetch_sub(layout.size(), Relaxed);
note_alloc(p, new_size);
}
p
}
}
pub fn heap_live() -> usize {
HEAP_LIVE.load(Relaxed)
}
#[cfg(target_arch = "wasm32")]
fn base_bytes() -> usize {
#[allow(non_upper_case_globals)]
extern "C" {
static __heap_base: u8;
}
unsafe { &__heap_base as *const u8 as usize }
}
#[cfg(target_arch = "wasm32")]
pub fn used_bytes() -> usize {
base_bytes().max(PEAK_END.load(Relaxed)).min(CAP)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn used_bytes() -> usize {
0
}
pub fn used_fraction() -> f32 {
used_bytes() as f32 / CAP as f32
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "std")]
#[test]
fn tracking_alloc_counts_live_heap() {
use core::alloc::GlobalAlloc;
let a = TrackingAlloc;
let layout = Layout::from_size_align(4096, 8).unwrap();
let before = heap_live();
unsafe {
let p = a.alloc(layout);
assert!(!p.is_null());
assert_eq!(heap_live(), before + 4096);
a.dealloc(p, layout);
assert_eq!(heap_live(), before);
}
}
}