use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use ftui_render::buffer::{AdaptiveDoubleBuffer, Buffer, DoubleBuffer};
use std::hint::black_box;
fn bench_swap_vs_clone(c: &mut Criterion) {
let mut group = c.benchmark_group("double_buffer/transition");
for (w, h) in [(80, 24), (120, 40), (200, 60)] {
let cells = w as u64 * h as u64;
group.throughput(Throughput::Elements(cells));
let buf = Buffer::new(w, h);
group.bench_with_input(
BenchmarkId::new("clone", format!("{w}x{h}")),
&buf,
|b, buf| b.iter(|| black_box(buf.clone())),
);
let mut db = DoubleBuffer::new(w, h);
group.bench_with_input(BenchmarkId::new("swap", format!("{w}x{h}")), &(), |b, _| {
b.iter(|| {
db.swap();
black_box(&db);
})
});
let mut clear_buf = Buffer::new(w, h);
group.bench_with_input(
BenchmarkId::new("clear", format!("{w}x{h}")),
&(),
|b, _| {
b.iter(|| {
clear_buf.clear();
black_box(&clear_buf);
})
},
);
let mut db_combined = DoubleBuffer::new(w, h);
group.bench_with_input(
BenchmarkId::new("swap_and_clear", format!("{w}x{h}")),
&(),
|b, _| {
b.iter(|| {
db_combined.swap();
db_combined.current_mut().clear();
black_box(&db_combined);
})
},
);
}
group.finish();
}
fn bench_double_buffer_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("double_buffer/ops");
for (w, h) in [(80, 24), (120, 40), (200, 60)] {
let cells = w as u64 * h as u64;
group.throughput(Throughput::Elements(cells));
group.bench_with_input(
BenchmarkId::new("new", format!("{w}x{h}")),
&(w, h),
|b, &(w, h)| b.iter(|| black_box(DoubleBuffer::new(w, h))),
);
}
let mut db = DoubleBuffer::new(80, 24);
group.bench_function("resize_80x24_to_120x40", |b| {
b.iter(|| {
db.resize(120, 40);
db.resize(80, 24); black_box(&db);
})
});
let db = DoubleBuffer::new(120, 40);
group.bench_function("current_ref_120x40", |b| b.iter(|| black_box(db.current())));
group.bench_function("previous_ref_120x40", |b| {
b.iter(|| black_box(db.previous()))
});
let mut db_mut = DoubleBuffer::new(120, 40);
group.bench_function("current_mut_120x40", |b| {
b.iter(|| {
let _ = black_box(db_mut.current_mut());
})
});
let db = DoubleBuffer::new(120, 40);
group.bench_function("dimensions_match", |b| {
b.iter(|| black_box(db.dimensions_match(120, 40)))
});
group.finish();
}
fn bench_frame_transition_simulation(c: &mut Criterion) {
let mut group = c.benchmark_group("double_buffer/frame_sim");
for (w, h) in [(80, 24), (120, 40)] {
let cells = w as u64 * h as u64;
group.throughput(Throughput::Elements(cells));
group.bench_with_input(
BenchmarkId::new("clone_per_frame", format!("{w}x{h}")),
&(w, h),
|b, &(w, h)| {
let mut current = Buffer::new(w, h);
b.iter(|| {
let _prev = current.clone();
current.clear();
black_box(¤t);
})
},
);
group.bench_with_input(
BenchmarkId::new("swap_per_frame", format!("{w}x{h}")),
&(w, h),
|b, &(w, h)| {
let mut db = DoubleBuffer::new(w, h);
b.iter(|| {
db.swap();
db.current_mut().clear();
black_box(&db);
})
},
);
}
group.finish();
}
fn bench_adaptive_resize_storm(c: &mut Criterion) {
let mut group = c.benchmark_group("adaptive_buffer/resize_storm");
for base_size in [(80, 24), (120, 40)] {
let (w, h) = base_size;
let cells = w as u64 * h as u64;
group.throughput(Throughput::Elements(cells));
group.bench_with_input(
BenchmarkId::new("adaptive", format!("{w}x{h}")),
&(w, h),
|b, &(w, h)| {
let mut adb = AdaptiveDoubleBuffer::new(w, h);
b.iter(|| {
for i in 1u16..=10 {
adb.resize(w + i, h + (i / 2));
}
adb.resize(w, h);
black_box(&adb);
})
},
);
group.bench_with_input(
BenchmarkId::new("regular", format!("{w}x{h}")),
&(w, h),
|b, &(w, h)| {
let mut db = DoubleBuffer::new(w, h);
b.iter(|| {
for i in 1u16..=10 {
db.resize(w + i, h + (i / 2));
}
db.resize(w, h);
black_box(&db);
})
},
);
}
group.finish();
}
fn bench_adaptive_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("adaptive_buffer/ops");
for (w, h) in [(80, 24), (120, 40), (200, 60)] {
let cells = w as u64 * h as u64;
group.throughput(Throughput::Elements(cells));
group.bench_with_input(
BenchmarkId::new("new", format!("{w}x{h}")),
&(w, h),
|b, &(w, h)| b.iter(|| black_box(AdaptiveDoubleBuffer::new(w, h))),
);
}
let mut adb = AdaptiveDoubleBuffer::new(80, 24);
group.bench_function("resize_within_capacity", |b| {
b.iter(|| {
adb.resize(90, 28); adb.resize(80, 24); black_box(&adb);
})
});
let mut adb2 = AdaptiveDoubleBuffer::new(80, 24);
group.bench_function("resize_beyond_capacity", |b| {
b.iter(|| {
adb2.resize(150, 60); adb2.resize(80, 24); black_box(&adb2);
})
});
let mut adb3 = AdaptiveDoubleBuffer::new(120, 40);
group.bench_function("swap_120x40", |b| {
b.iter(|| {
adb3.swap();
black_box(&adb3);
})
});
group.finish();
}
fn bench_adaptive_vs_regular_frame_transition(c: &mut Criterion) {
let mut group = c.benchmark_group("adaptive_buffer/frame_transition");
for (w, h) in [(80, 24), (120, 40)] {
let cells = w as u64 * h as u64;
group.throughput(Throughput::Elements(cells));
group.bench_with_input(
BenchmarkId::new("adaptive_swap_clear", format!("{w}x{h}")),
&(w, h),
|b, &(w, h)| {
let mut adb = AdaptiveDoubleBuffer::new(w, h);
b.iter(|| {
adb.swap();
adb.current_mut().clear();
black_box(&adb);
})
},
);
group.bench_with_input(
BenchmarkId::new("regular_swap_clear", format!("{w}x{h}")),
&(w, h),
|b, &(w, h)| {
let mut db = DoubleBuffer::new(w, h);
b.iter(|| {
db.swap();
db.current_mut().clear();
black_box(&db);
})
},
);
}
group.finish();
}
fn bench_adaptive_avoidance_ratio(c: &mut Criterion) {
let mut group = c.benchmark_group("adaptive_buffer/avoidance");
group.bench_function("small_increments_10x", |b| {
b.iter(|| {
let mut adb = AdaptiveDoubleBuffer::new(80, 24);
for i in 1u16..=10 {
adb.resize(80 + i, 24 + (i / 3));
}
let stats = adb.stats().clone();
black_box((adb.stats().avoidance_ratio(), stats));
})
});
group.bench_function("oscillation_pattern", |b| {
b.iter(|| {
let mut adb = AdaptiveDoubleBuffer::new(80, 24);
for _ in 0..5 {
adb.resize(90, 28);
adb.resize(80, 24);
}
black_box(adb.stats().avoidance_ratio());
})
});
group.finish();
}
criterion_group!(
benches,
bench_swap_vs_clone,
bench_double_buffer_operations,
bench_frame_transition_simulation,
bench_adaptive_resize_storm,
bench_adaptive_operations,
bench_adaptive_vs_regular_frame_transition,
bench_adaptive_avoidance_ratio,
);
criterion_main!(benches);