Lots of claude-driven performance work.

This commit is contained in:
2026-03-23 00:24:55 -04:00
parent 497af9151d
commit e90f09bf3e
14 changed files with 1820 additions and 394 deletions

View File

@@ -0,0 +1,94 @@
use criterion::{Criterion, criterion_group, criterion_main};
use ruin_ui::{
Color, Element, FlexDirection, LayoutCache, TextStyle, TextSystem, UiSize,
layout_snapshot_with_cache,
};
fn text_style() -> TextStyle {
TextStyle::new(14.0, Color::rgb(0xFF, 0xFF, 0xFF))
}
fn make_column_tree(n: usize) -> Element {
let mut root = Element::new().direction(FlexDirection::Column);
for i in 0..n {
root = root.child(Element::text(format!("item {i}"), text_style()));
}
root
}
/// Static tree — nothing changes between frames. After one warmup frame, all
/// subsequent frames should be near-zero cost (all cache hits).
fn bench_static_tree(c: &mut Criterion) {
let mut text_system = TextSystem::new();
let mut layout_cache = LayoutCache::new();
let root = make_column_tree(200);
let size = UiSize::new(400.0, 4000.0);
// Warm up cache.
layout_snapshot_with_cache(1, size, &root, &mut text_system, &mut layout_cache);
c.bench_function("layout_static_200_nodes", |b| {
let mut version = 2u64;
b.iter(|| {
version += 1;
layout_snapshot_with_cache(version, size, &root, &mut text_system, &mut layout_cache)
});
});
}
/// 200 nodes, one text content changes per frame — only one cache miss expected.
fn bench_single_change(c: &mut Criterion) {
let mut text_system = TextSystem::new();
let mut layout_cache = LayoutCache::new();
let size = UiSize::new(400.0, 4000.0);
// Initial warmup.
let root = make_column_tree(200);
layout_snapshot_with_cache(1, size, &root, &mut text_system, &mut layout_cache);
c.bench_function("layout_single_change_200_nodes", |b| {
let mut counter = 0usize;
let mut version = 2u64;
b.iter(|| {
counter += 1;
version += 1;
let mut tree = make_column_tree(200);
tree.children[100] = Element::text(format!("changed {counter}"), text_style());
layout_snapshot_with_cache(version, size, &tree, &mut text_system, &mut layout_cache)
});
});
}
/// Scroll box with 500 items, 20 visible. Simulates a large list.
fn bench_scroll_list(c: &mut Criterion) {
let mut text_system = TextSystem::new();
let mut layout_cache = LayoutCache::new();
let item_height = 32.0;
let viewport_height = 640.0;
let n = 500;
let mut scroll_box = Element::scroll_box(0.0).width(400.0).height(viewport_height);
for i in 0..n {
scroll_box = scroll_box.child(
Element::new()
.height(item_height)
.child(Element::text(format!("list item {i}"), text_style())),
);
}
let root = Element::new().child(scroll_box);
let size = UiSize::new(400.0, viewport_height);
// Warm up.
layout_snapshot_with_cache(1, size, &root, &mut text_system, &mut layout_cache);
c.bench_function("layout_scroll_list_500_items", |b| {
let mut version = 2u64;
b.iter(|| {
version += 1;
layout_snapshot_with_cache(version, size, &root, &mut text_system, &mut layout_cache)
});
});
}
criterion_group!(benches, bench_static_tree, bench_single_change, bench_scroll_list);
criterion_main!(benches);