#![allow(
missing_docs,
reason = "No need for API documentation in benchmark code"
)]
use std::fmt::Write as _;
use std::hint::black_box;
use std::time::{Duration, Instant};
use all_the_time::Session as TimeSession;
use alloc_tracker::{Allocator, Report, Session};
use criterion::{Criterion, criterion_group, criterion_main};
#[global_allocator]
static ALLOCATOR: Allocator<std::alloc::System> = Allocator::system();
const SPANS_PER_OP: usize = 8;
fn entrypoint(c: &mut Criterion) {
let alloc = Session::new();
let time = TimeSession::new();
setup(c, &alloc, &time);
snapshot(c, &alloc, &time);
merge(c, &alloc, &time);
render(c, &alloc, &time);
write(c, &alloc, &time);
}
fn measured<F: FnMut()>(
iters: u64,
alloc_op: &alloc_tracker::Operation,
time_op: &all_the_time::Operation,
mut body: F,
) -> Duration {
let start = Instant::now();
{
let _alloc_span = alloc_op.measure_thread().iterations(iters);
let _time_span = time_op.measure_thread().iterations(iters);
for _ in 0..iters {
body();
}
}
start.elapsed()
}
fn build_report(num_ops: usize) -> Report {
let session = Session::new().no_stdout().no_file();
for op_idx in 0..num_ops {
let op = session.operation(format!("op_{op_idx}"));
for _ in 0..SPANS_PER_OP {
let _span = op.measure_thread().iterations(10);
black_box((0..10_u32).collect::<Vec<_>>());
}
}
session.to_report()
}
fn setup(c: &mut Criterion, alloc: &Session, time: &TimeSession) {
let mut group = c.benchmark_group("alloc_tracker_report_lifecycle/setup");
let alloc_op = alloc.operation("alloc_tracker_report_lifecycle/setup/session_100_ops");
let time_op = time.operation("alloc_tracker_report_lifecycle/setup/session_100_ops");
group.bench_function("session_100_ops", |b| {
b.iter_custom(|iters| {
measured(iters, &alloc_op, &time_op, || {
let session = Session::new().no_stdout().no_file();
for op_idx in 0..100 {
black_box(session.operation(format!("op_{op_idx}")));
}
black_box(&session);
})
});
});
group.finish();
}
fn snapshot(c: &mut Criterion, alloc: &Session, time: &TimeSession) {
let mut group = c.benchmark_group("alloc_tracker_report_lifecycle/snapshot");
let alloc_op = alloc.operation("alloc_tracker_report_lifecycle/snapshot/ops_100");
let time_op = time.operation("alloc_tracker_report_lifecycle/snapshot/ops_100");
let session = Session::new().no_stdout().no_file();
for op_idx in 0..100 {
let op = session.operation(format!("op_{op_idx}"));
for _ in 0..SPANS_PER_OP {
let _span = op.measure_thread().iterations(10);
black_box((0..10_u32).collect::<Vec<_>>());
}
}
group.bench_function("ops_100", |b| {
b.iter_custom(|iters| {
measured(iters, &alloc_op, &time_op, || {
black_box(session.to_report());
})
});
});
group.finish();
}
fn merge(c: &mut Criterion, alloc: &Session, time: &TimeSession) {
let mut group = c.benchmark_group("alloc_tracker_report_lifecycle/merge");
let alloc_op = alloc.operation("alloc_tracker_report_lifecycle/merge/ops_100");
let time_op = time.operation("alloc_tracker_report_lifecycle/merge/ops_100");
let left = build_report(100);
let right = build_report(100);
group.bench_function("ops_100", |b| {
b.iter_custom(|iters| {
measured(iters, &alloc_op, &time_op, || {
black_box(Report::merge(black_box(&left), black_box(&right)));
})
});
});
group.finish();
}
fn render(c: &mut Criterion, alloc: &Session, time: &TimeSession) {
let mut group = c.benchmark_group("alloc_tracker_report_lifecycle/render");
for num_ops in [10_usize, 100] {
let report = build_report(num_ops);
let name = format!("ops_{num_ops}");
let alloc_op = alloc.operation(format!("alloc_tracker_report_lifecycle/render/{name}"));
let time_op = time.operation(format!("alloc_tracker_report_lifecycle/render/{name}"));
group.bench_function(&name, |b| {
b.iter_custom(|iters| {
measured(iters, &alloc_op, &time_op, || {
let mut rendered = String::new();
write!(rendered, "{report}").expect("writing to a String cannot fail");
black_box(rendered);
})
});
});
}
group.finish();
}
fn write(c: &mut Criterion, alloc: &Session, time: &TimeSession) {
let mut group = c.benchmark_group("alloc_tracker_report_lifecycle/write");
let alloc_op = alloc.operation("alloc_tracker_report_lifecycle/write/ops_25");
let time_op = time.operation("alloc_tracker_report_lifecycle/write/ops_25");
let report = build_report(25);
let directory = tempfile::tempdir().expect("creating a temp directory cannot fail in a bench");
group.bench_function("ops_25", |b| {
b.iter_custom(|iters| {
measured(iters, &alloc_op, &time_op, || {
report.write_to_directory(directory.path());
})
});
});
group.finish();
}
criterion_group!(benches, entrypoint);
criterion_main!(benches);