blob: 6d164f43bb58d32e3c6c9f6daf744a2e4348a218 [file]
// Copyright 2025 the Vello Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT
use criterion::{Criterion, black_box};
use rand::rngs::SmallRng;
use rand::{Rng, SeedableRng};
use vello_common::multi_atlas::Atlas;
use vello_common::multi_atlas::AtlasId;
use crate::SEED;
const ATLAS_SIZE: u32 = 4096;
fn make_atlas() -> Atlas {
Atlas::new(AtlasId::new(0), ATLAS_SIZE, ATLAS_SIZE)
}
pub fn allocator(c: &mut Criterion) {
allocate_varied(c);
allocate_until_full(c);
alloc_dealloc_churn(c);
}
/// Allocate 1000 rectangles with random sizes between 8x8 and 128x128.
fn allocate_varied(c: &mut Criterion) {
let mut rng = SmallRng::from_seed(SEED);
let sizes: Vec<(u32, u32)> = (0..1000)
.map(|_| (rng.random_range(8..=128), rng.random_range(8..=128)))
.collect();
let mut g = c.benchmark_group("allocator");
g.bench_function("alloc_1000_varied_8_128", |b| {
b.iter(|| {
let mut atlas = make_atlas();
for &(w, h) in &sizes {
black_box(atlas.allocate(w, h));
}
});
});
g.finish();
}
/// Pack as many 32x32 tiles as possible until the atlas is full.
fn allocate_until_full(c: &mut Criterion) {
let mut g = c.benchmark_group("allocator");
g.bench_function("alloc_until_full_32x32", |b| {
b.iter(|| {
let mut atlas = make_atlas();
let mut count = 0_u32;
while atlas.allocate(32, 32).is_some() {
count += 1;
}
black_box(count);
});
});
g.finish();
}
/// Steady-state churn: allocate 500 rects, then repeatedly deallocate one and allocate a new one
/// (500 cycles). Measures reuse / merge performance under typical glyph-cache turnover.
fn alloc_dealloc_churn(c: &mut Criterion) {
let mut rng = SmallRng::from_seed(SEED);
let sizes: Vec<(u32, u32)> = (0..1000)
.map(|_| (rng.random_range(16..=64), rng.random_range(16..=64)))
.collect();
let mut g = c.benchmark_group("allocator");
g.bench_function("churn_500_steady_state", |b| {
b.iter(|| {
let mut atlas = make_atlas();
let mut live: Vec<(vello_common::multi_atlas::AllocId, u32, u32)> = Vec::new();
for &(w, h) in sizes.iter().take(500) {
if let Some(a) = atlas.allocate(w, h) {
live.push((a.id, w, h));
}
}
let mut rng = SmallRng::from_seed(SEED);
for &(w, h) in sizes.iter().skip(500) {
if !live.is_empty() {
let idx = rng.random_range(0..live.len());
let (id, dw, dh) = live.swap_remove(idx);
atlas.deallocate(id, dw, dh);
}
if let Some(a) = atlas.allocate(w, h) {
live.push((a.id, w, h));
}
}
black_box(&live);
});
});
g.finish();
}