use criterion::{Criterion, criterion_group, criterion_main};
use generic_static_cache::*;
use std::{
any::TypeId,
collections::HashMap,
hash::{BuildHasher, Hasher},
hint::black_box,
marker::PhantomData,
sync::{
RwLock,
atomic::{AtomicI32, Ordering},
},
};
#[allow(clippy::extra_unused_type_parameters)]
#[inline]
fn with_macro<T: 'static>() -> i32 {
generic_static!(
static COUNT: &AtomicI32 = &AtomicI32::new(1);
);
COUNT.load(Ordering::Relaxed)
}
#[inline]
fn with_global<T: Sync + 'static>() -> i32 {
let global = &global::<(PhantomData<T>, AtomicI32)>().1;
global.load(Ordering::Relaxed)
}
#[inline]
fn with_map<T: Sync + 'static>() -> i32 {
pub(crate) struct SyncWrapper(AtomicI32);
unsafe impl Sync for SyncWrapper {}
unsafe impl Send for SyncWrapper {}
static MAP: RwLock<TypeIdMap<SyncWrapper>> =
RwLock::new(TypeIdMap::with_hasher(NoOpTypeIdBuildHasher));
{
let guard = MAP.read().unwrap();
if let Some(global) = guard.get(&TypeId::of::<T>()) {
return global.0.load(Ordering::Relaxed);
}
}
let mut guard = MAP.write().unwrap();
guard.insert(TypeId::of::<T>(), SyncWrapper(AtomicI32::new(0)));
0
}
type TypeIdMap<T> = HashMap<TypeId, T, NoOpTypeIdBuildHasher>;
#[doc(hidden)]
#[derive(Default)]
struct NoOpTypeIdBuildHasher;
impl BuildHasher for NoOpTypeIdBuildHasher {
type Hasher = NoOpTypeIdHasher;
fn build_hasher(&self) -> Self::Hasher {
NoOpTypeIdHasher(0)
}
}
#[doc(hidden)]
#[derive(Default)]
struct NoOpTypeIdHasher(u64);
impl Hasher for NoOpTypeIdHasher {
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, _bytes: &[u8]) {
unimplemented!()
}
fn write_u64(&mut self, i: u64) {
self.0 = i
}
}
fn criterion_benchmark(c: &mut Criterion) {
let inner = 10_000;
c.bench_function("macro", |b| {
b.iter(|| {
let mut acc = 0;
for _ in 0..inner {
acc += black_box(with_macro::<u8>());
acc += black_box(with_macro::<u16>());
acc += black_box(with_macro::<u32>());
acc += black_box(with_macro::<u64>());
acc += black_box(with_macro::<i8>());
acc += black_box(with_macro::<i16>());
acc += black_box(with_macro::<i32>());
acc += black_box(with_macro::<i64>());
}
black_box(acc);
})
});
c.bench_function("global", |b| {
b.iter(|| {
let mut acc = 0;
for _ in 0..inner {
acc += black_box(with_global::<u8>());
acc += black_box(with_global::<u16>());
acc += black_box(with_global::<u32>());
acc += black_box(with_global::<u64>());
acc += black_box(with_global::<i8>());
acc += black_box(with_global::<i16>());
acc += black_box(with_global::<i32>());
acc += black_box(with_global::<i64>());
}
black_box(acc);
})
});
c.bench_function("map", |b| {
b.iter(|| {
let mut acc = 0;
for _ in 0..inner {
acc += black_box(with_map::<u8>());
acc += black_box(with_map::<u16>());
acc += black_box(with_map::<u32>());
acc += black_box(with_map::<u64>());
acc += black_box(with_map::<i8>());
acc += black_box(with_map::<i16>());
acc += black_box(with_map::<i32>());
acc += black_box(with_map::<i64>());
}
black_box(acc);
})
});
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);