cycle_ptr 0.1.1

Smart pointers, with cycles
Documentation
//! Multi-threaded benchmarks for cycle pointer.

use criterion::{BatchSize, BenchmarkId, Criterion, criterion_group, criterion_main};
use cycle_ptr::prelude::*;
use cycle_ptr::sync::{GcMtMemberPtr, GcMtPtr, GcTask, GenerationRef, Metadata};
use std::sync::{Mutex, mpsc};
use std::thread;
use std::time::Duration;

/// We use a parameterized benchmark, to confirm that the cache timings remain mostly-constant regardless of the cache size.
const SIZES: [usize; 19] = [
    100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000,
    9000, 10000,
];

struct Child {
    _parent: GcMtMemberPtr<Parent>,
}

struct Parent {
    gc_metadata: Metadata,
    child: Mutex<Option<GcMtMemberPtr<Child>>>,
}

fn make_test_obj() -> GcMtPtr<Parent> {
    let gc_generation = GenerationRef::default();
    let parent = gc_generation.make(|gc_metadata| Parent {
        gc_metadata,
        child: None.into(),
    });
    let child = gc_generation.make(|gc_metadata| Child {
        _parent: gc_metadata.new_pointer(parent.clone()),
    });
    *parent.child.lock().unwrap() = Some(parent.gc_metadata.new_pointer(child));
    parent
}

fn multithread_gc(c: &mut Criterion) {
    let mut group = c.benchmark_group("multithread_gc");
    for size in SIZES.into_iter() {
        group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
            b.iter_batched(
                || (0..size).map(|_| make_test_obj()).collect(),
                |collection: Vec<GcMtPtr<Parent>>| {
                    drop(collection); // adds the collection to the GC.
                },
                BatchSize::SmallInput,
            );
        });
    }
    group.finish();
}

fn multithread_gc_threaded(c: &mut Criterion) {
    let mut group = c.benchmark_group("multithread_gc_threaded");
    for size in SIZES.into_iter() {
        let (pending_tx, pending_rx) = mpsc::channel::<GcTask>();
        let gc_thread = thread::spawn(move || {
            for task in pending_rx.iter() {
                task.run();
            }
        });

        let task_to_pending = move |task| {
            pending_tx.send(task).unwrap();
        };
        let callback_handle =
            GcTask::install_callback(&task_to_pending).expect("there should not be a callback");

        group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
            b.iter_batched(
                || (0..size).map(|_| make_test_obj()).collect(),
                |collection: Vec<GcMtPtr<Parent>>| {
                    drop(collection); // adds the collection to the GC.
                },
                BatchSize::SmallInput,
            );
        });

        drop(callback_handle);
        drop(task_to_pending);
        let _ = gc_thread.join();
    }
    group.finish();
}

criterion_group!(
    name = benches;
    config = Criterion::default().configure_from_args().measurement_time(Duration::from_secs(10)).sample_size(50).noise_threshold(0.025);
    targets = multithread_gc, multithread_gc_threaded,
);
criterion_main!(benches);