use std::alloc::{GlobalAlloc, Layout};
use std::thread;
use stoolap_jemalloc::Jemalloc;
#[global_allocator]
static GLOBAL: Jemalloc = Jemalloc::new();
#[test]
fn thread_cache_round_trip() {
let layout = Layout::from_size_align(8, 8).unwrap();
unsafe {
let p = GLOBAL.alloc(layout);
p.write(1);
GLOBAL.dealloc(p, layout);
let q = GLOBAL.alloc(layout);
assert_eq!(q, p);
q.write(2);
GLOBAL.dealloc(q, layout);
}
}
#[test]
fn threads_on_different_classes() {
let classes = [16usize, 48, 200, 3000];
let blocks: Vec<Vec<usize>> = classes
.iter()
.map(|&size| {
let layout = Layout::from_size_align(size, 8).unwrap();
(0..300)
.map(|_| unsafe {
let p = GLOBAL.alloc(layout);
p.write(size as u8);
p as usize
})
.collect()
})
.collect();
let handles: Vec<_> = classes
.into_iter()
.zip(blocks)
.map(|(size, ptrs)| {
thread::spawn(move || {
let layout = Layout::from_size_align(size, 8).unwrap();
for p in ptrs {
let p = p as *mut u8;
unsafe {
assert_eq!(*p, size as u8);
GLOBAL.dealloc(p, layout);
}
}
})
})
.collect();
for h in handles {
h.join().unwrap();
}
}
#[test]
fn threads_on_large_and_huge() {
let handles: Vec<_> = [40_000usize, 300_000, 2 << 20]
.into_iter()
.map(|size| {
thread::spawn(move || {
let layout = Layout::from_size_align(size, 8).unwrap();
for _ in 0..4 {
unsafe {
let p = GLOBAL.alloc(layout);
p.write(7);
let q = GLOBAL.realloc(p, layout, size * 2);
assert_eq!(*q, 7);
GLOBAL.dealloc(q, Layout::from_size_align(size * 2, 8).unwrap());
}
}
})
})
.collect();
for h in handles {
h.join().unwrap();
}
}
struct LateUser;
impl Drop for LateUser {
fn drop(&mut self) {
let small: Vec<Box<u64>> = (0..20).map(Box::new).collect();
let large = vec![1u8; 40_000];
assert_eq!(*small[19] + u64::from(large[39_999]), 20);
}
}
thread_local! {
static LATE: LateUser = const { LateUser };
}
#[test]
fn frees_while_a_thread_exits() {
thread::spawn(|| {
LATE.with(|_| {});
drop(Box::new(5u32));
})
.join()
.unwrap();
}
#[test]
fn frees_on_another_thread() {
let (tx, rx) = std::sync::mpsc::sync_channel::<(Vec<Box<[u64; 4]>>, Vec<Vec<u8>>)>(2);
let producer = thread::spawn(move || {
for round in 0..4u64 {
let small = (0..300).map(|i| Box::new([round, i, 1, 2])).collect();
let large = (0..2)
.map(|i| vec![round as u8; 40_000 + 4096 * i])
.collect();
tx.send((small, large)).unwrap();
}
});
let consumer = thread::spawn(move || {
for (small, large) in rx {
for b in small {
assert_eq!(b[2] + b[3], 3);
}
for v in large {
assert_eq!(v[0], v[v.len() - 1]);
}
}
});
producer.join().unwrap();
consumer.join().unwrap();
stoolap_jemalloc::purge();
}