use std::sync::Arc;
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use graphrefly_core::{
BindingBoundary, Core, DepBatch, FnId, FnResult, HandleId, Message, NodeId, Sink,
};
use parking_lot::Mutex;
struct BenchBinding {
next_handle: Mutex<u64>,
}
impl BenchBinding {
fn new() -> Arc<Self> {
Arc::new(Self {
next_handle: Mutex::new(1),
})
}
fn fresh_handle(&self) -> HandleId {
let mut g = self.next_handle.lock();
let h = HandleId::new(*g);
*g += 1;
h
}
}
impl BindingBoundary for BenchBinding {
fn invoke_fn(&self, _: NodeId, _: FnId, _dep_data: &[DepBatch]) -> FnResult {
FnResult::Data {
handle: self.fresh_handle(),
tracked: None,
}
}
fn custom_equals(&self, _: FnId, a: HandleId, b: HandleId) -> bool {
a == b
}
fn release_handle(&self, _: HandleId) {}
}
fn noop_sink() -> Sink {
std::rc::Rc::new(|_msgs: &[Message]| {})
}
fn bench_n_independent_emits_per_wave(c: &mut Criterion) {
let mut group = c.benchmark_group("notification_buffer_per_wave");
for &n in &[1_usize, 8, 32, 128, 256] {
let binding = BenchBinding::new();
let core = Core::new(binding.clone());
let states: Vec<NodeId> = (0..n)
.map(|_| core.register_state(HandleId::new(1), false).unwrap())
.collect();
let _subs: Vec<_> = states
.iter()
.map(|&s| core.subscribe(s, noop_sink()))
.collect();
group.throughput(Throughput::Elements(n as u64));
group.bench_with_input(BenchmarkId::from_parameter(n), &n, |b, _| {
b.iter(|| {
core.batch(|| {
for &s in &states {
let h = binding.fresh_handle();
core.emit(black_box(s), black_box(h));
}
});
});
});
}
group.finish();
}
criterion_group!(benches, bench_n_independent_emits_per_wave);
criterion_main!(benches);