#![cfg(target_pointer_width = "64")]
use std::alloc::{GlobalAlloc, Layout, System};
use std::cell::Cell;
use moq_net::{Timestamp, broadcast, cache, origin};
thread_local! {
static LIVE: Cell<usize> = const { Cell::new(0) };
}
struct Counting;
unsafe impl GlobalAlloc for Counting {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let _ = LIVE.try_with(|live| live.set(live.get() + layout.size()));
unsafe { System.alloc(layout) }
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
let _ = LIVE.try_with(|live| live.set(live.get().saturating_sub(layout.size())));
unsafe { System.dealloc(ptr, layout) }
}
}
#[global_allocator]
static ALLOCATOR: Counting = Counting;
const PAYLOAD: usize = 150;
const GROUPS: usize = 4096;
fn measure() -> (usize, u64) {
let pool = cache::Pool::unbounded();
let mut info = broadcast::Info::new();
info.origin = origin::Info::default().with_pool(pool.clone());
let mut broadcast = info.produce();
let mut track = broadcast.create_track("chat", None).unwrap();
let mut group = track.append_group().unwrap();
group.write_frame(Timestamp::ZERO, vec![0u8; PAYLOAD]).unwrap();
group.finish().unwrap();
let before_heap = LIVE.with(Cell::get);
let before_charge = pool.used();
for _ in 0..GROUPS {
let mut group = track.append_group().unwrap();
group.write_frame(Timestamp::ZERO, vec![0u8; PAYLOAD]).unwrap();
group.finish().unwrap();
}
let heap = (LIVE.with(Cell::get) - before_heap) / GROUPS;
let charged = (pool.used() - before_charge) / GROUPS as u64;
drop(track);
drop(broadcast);
(heap, charged)
}
#[test]
fn charge_tracks_real_memory() {
let (heap, charged) = measure();
assert!(
charged as usize >= heap / 2,
"charged {charged} B/group against {heap} B of real heap: the pool is undercounting"
);
assert!(
charged as usize <= heap * 2,
"charged {charged} B/group against {heap} B of real heap: the pool is overcounting"
);
}