use criterion::{BatchSize, BenchmarkId, Criterion, criterion_group, criterion_main};
use cycle_ptr::prelude::*;
use cycle_ptr::{GcMemberPtr, GcPtr, GcTask, GenerationRef, Metadata};
use std::cell::RefCell;
use std::time::Duration;
const SIZES: [usize; 10] = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000];
fn constructor(c: &mut Criterion) {
struct Object;
c.bench_function("constructor", |b| {
b.iter_with_large_drop(|| GcPtr::new(|_| Object));
});
}
fn destructor(c: &mut Criterion) {
struct Object;
c.bench_function("destructor", |b| {
b.iter_batched(
|| GcPtr::new(|_| Object),
|ptr: GcPtr<Object>| drop(ptr),
BatchSize::SmallInput,
);
});
}
fn constructor_with_cycles(c: &mut Criterion) {
struct Object {
_parent: GcMemberPtr<ObjectCollection>,
}
struct ObjectCollection {
gc_metadata: Metadata,
data: RefCell<Vec<GcMemberPtr<Object>>>,
}
let mut group = c.benchmark_group("constructor_with_cycles");
for size in SIZES.into_iter() {
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
b.iter_batched_ref(
|| {
let collection = GcPtr::new(|gc_metadata| ObjectCollection {
gc_metadata,
data: Vec::with_capacity(size).into(),
});
for _ in 0..size {
let object = GcPtr::new(|gc_metadata| Object {
_parent: gc_metadata.new_pointer(collection.clone()),
});
collection
.data
.borrow_mut()
.push(collection.gc_metadata.new_pointer(object));
}
collection
},
|collection| {
let object = GcPtr::new(|gc_metadata| Object {
_parent: gc_metadata.new_pointer(collection.clone()),
});
collection
.data
.borrow_mut()
.push(collection.gc_metadata.new_pointer(object));
},
BatchSize::SmallInput,
);
});
}
group.finish();
}
fn constructor_with_cycles_using_generation_ref(c: &mut Criterion) {
struct Object {
_parent: GcMemberPtr<ObjectCollection>,
}
struct ObjectCollection {
gc_metadata: Metadata,
data: RefCell<Vec<GcMemberPtr<Object>>>,
}
let mut group = c.benchmark_group("constructor_with_cycles_using_generation_ref");
for size in SIZES.into_iter() {
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
b.iter_batched_ref(
|| {
let generation = GenerationRef::default();
let collection = generation.make(|gc_metadata| ObjectCollection {
gc_metadata,
data: Vec::with_capacity(size).into(),
});
for _ in 0..size {
let object = generation.make(|gc_metadata| Object {
_parent: gc_metadata.new_pointer(collection.clone()),
});
collection
.data
.borrow_mut()
.push(collection.gc_metadata.new_pointer(object));
}
(generation, collection)
},
|(generation, collection)| {
let object = generation.make(|gc_metadata| Object {
_parent: gc_metadata.new_pointer(collection.clone()),
});
collection
.data
.borrow_mut()
.push(collection.gc_metadata.new_pointer(object));
},
BatchSize::SmallInput,
);
});
}
group.finish();
}
fn gc_without_cycles(c: &mut Criterion) {
struct Object;
struct ObjectCollection {
gc_metadata: Metadata,
data: RefCell<Vec<GcMemberPtr<Object>>>,
}
let mut group = c.benchmark_group("gc_without_cycles");
for size in SIZES.into_iter() {
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
b.iter_batched(
|| {
let collection = GcPtr::new(|gc_metadata| ObjectCollection {
gc_metadata,
data: Vec::with_capacity(size).into(),
});
for _ in 0..size {
collection
.data
.borrow_mut()
.push(collection.gc_metadata.new_pointer(GcPtr::new(|_| Object)));
}
collection
},
|collection: GcPtr<ObjectCollection>| drop(collection),
BatchSize::SmallInput,
);
});
}
group.finish();
}
fn gc_with_cycles(c: &mut Criterion) {
struct Object {
_parent: GcMemberPtr<ObjectCollection>,
}
struct ObjectCollection {
gc_metadata: Metadata,
data: RefCell<Vec<GcMemberPtr<Object>>>,
}
let mut group = c.benchmark_group("gc_with_cycles");
for size in SIZES.into_iter() {
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
b.iter_batched(
|| {
let gc_generation = GenerationRef::default();
let collection = gc_generation.make(|gc_metadata| ObjectCollection {
gc_metadata,
data: Vec::with_capacity(size).into(),
});
for _ in 0..size {
let object = gc_generation.make(|gc_metadata| Object {
_parent: gc_metadata.new_pointer(collection.clone()),
});
collection
.data
.borrow_mut()
.push(collection.gc_metadata.new_pointer(object));
}
collection
},
|collection: GcPtr<ObjectCollection>| drop(collection),
BatchSize::SmallInput,
);
});
}
group.finish();
}
fn gc_with_cycles_and_deferred_gc(c: &mut Criterion) {
struct Object {
_parent: GcMemberPtr<ObjectCollection>,
}
struct ObjectCollection {
gc_metadata: Metadata,
data: RefCell<Vec<GcMemberPtr<Object>>>,
}
let mut group = c.benchmark_group("gc_with_cycles_and_deferred_gc");
for size in SIZES.into_iter() {
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
b.iter_batched(
|| {
let gc_generation = GenerationRef::default();
let collection = gc_generation.make(|gc_metadata| ObjectCollection {
gc_metadata,
data: Vec::with_capacity(size).into(),
});
for _ in 0..size {
let object = gc_generation.make(|gc_metadata| Object {
_parent: gc_metadata.new_pointer(collection.clone()),
});
collection
.data
.borrow_mut()
.push(collection.gc_metadata.new_pointer(object));
}
collection
},
|collection: GcPtr<ObjectCollection>| {
let mut gc = Vec::default();
let handle = GcTask::install_callback(|task| gc.push(task));
collection.data.borrow_mut().clear(); drop(collection);
drop(handle);
gc.into_iter().for_each(|task| {
task.run();
});
},
BatchSize::SmallInput,
);
});
}
group.finish();
}
criterion_group!(
name = benches;
config = Criterion::default().configure_from_args().noise_threshold(0.025);
targets = constructor, destructor, constructor_with_cycles_using_generation_ref,
);
criterion_group!(
name = slow_benches;
config = Criterion::default().configure_from_args().measurement_time(Duration::from_secs(10)).sample_size(50).noise_threshold(0.025);
targets = constructor_with_cycles, gc_without_cycles, gc_with_cycles, gc_with_cycles_and_deferred_gc,
);
criterion_main!(benches, slow_benches);