#![cfg(feature = "alloc-core")]
use core::alloc::Layout;
use std::time::Instant;
use sefer_alloc::alloc_core::AllocCore;
fn free_phase_nanos(n: usize, layout: Layout) -> u128 {
let mut ac = AllocCore::new().expect("primordial");
let mut ptrs = Vec::with_capacity(n);
for _ in 0..n {
let p = ac.alloc(layout);
assert!(!p.is_null(), "alloc returned null");
ptrs.push(p);
}
let start = Instant::now();
for &p in &ptrs {
ac.dealloc(p, layout);
}
start.elapsed().as_nanos()
}
#[test]
fn own_thread_free_is_subquadratic() {
let layout = Layout::from_size_align(16, 16).unwrap();
const N: usize = 2048;
let _ = free_phase_nanos(N, layout);
let best = |n: usize| (0..5).map(|_| free_phase_nanos(n, layout)).min().unwrap();
let t_n = best(N).max(1);
let t_2n = best(2 * N).max(1);
let ratio = t_2n as f64 / t_n as f64;
assert!(
ratio < 3.0,
"free phase scaled super-linearly: doubling N ({N}→{}) multiplied free \
time by {ratio:.2}× (t_N={t_n}ns, t_2N={t_2n}ns). O(N) expects ~2×, \
O(N²) ~4×. The O(1) bitmap double-free guard regressed back to an \
O(free-list-length) walk.",
2 * N
);
}