Add button benchmark (#6854)

This helped me benchmark the atomic layout (#5830) changes.

I also realized that the label benchmark wasn't testing the painting,
since the buttons at some point will be placed outside the screen_rect,
meaning it won't be painted.

This fixes it by benching the label in a child ui.

The `label &str` benchmark went from 483 ns to 535 ns with these
changes.

EDIT:

I fixed another benchmark problem, since the benchmark would show the
same widget millions of times for a single frame, the WidgetRects
hashmap would get huge, causing each iteration to slow down a bit more
and causing the benchmark to have unreliable results.

With this the `label &str` benchmark went from 535ns to 298ns. Also the
`label format!` benchmark now takes almost the same time (302 ns).
Before, it was a lot slower since it reused the same Context which
already had millions of widget ids.
This commit is contained in:
Lucas Meurer 2025-04-28 11:58:05 +02:00 committed by GitHub
parent f2ce6424f3
commit 7d185acb41
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 80 additions and 10 deletions

View File

@ -14,3 +14,19 @@ The demo library is a separate crate for three reasons:
* To remove the amount of code in `egui` proper.
* To make it easy for 3rd party egui integrations to use it for tests.
- See for instance https://github.com/not-fl3/egui-miniquad/blob/master/examples/demo.rs
This crate also contains benchmarks for egui.
Run them with
```bash
# Run all benchmarks
cargo bench -p egui_demo_lib
# Run a single benchmark
cargo bench -p egui_demo_lib "benchmark name"
# Profile benchmarks with cargo-flamegraph (--root flag is necessary for MacOS)
CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph --bench benchmark --root -p egui_demo_lib -- --bench "benchmark name"
# Profile with cargo-instruments
CARGO_PROFILE_BENCH_DEBUG=true cargo instruments --profile bench --bench benchmark -p egui_demo_lib -t time -- --bench "benchmark name"
```

View File

@ -1,11 +1,20 @@
use std::fmt::Write as _;
use criterion::{criterion_group, criterion_main, Criterion};
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use egui::epaint::TextShape;
use egui::load::SizedTexture;
use egui::{Button, Id, TextureId, Ui, UiBuilder, Vec2};
use egui_demo_lib::LOREM_IPSUM_LONG;
use rand::Rng as _;
/// Each iteration should be called in their own `Ui` with an intentional id clash,
/// to prevent the Context from building a massive map of `WidgetRects` (which would slow the test,
/// causing unreliable results).
fn create_benchmark_ui(ctx: &egui::Context) -> Ui {
Ui::new(ctx.clone(), Id::new("clashing_id"), UiBuilder::new())
}
pub fn criterion_benchmark(c: &mut Criterion) {
use egui::RawInput;
@ -55,17 +64,62 @@ pub fn criterion_benchmark(c: &mut Criterion) {
{
let ctx = egui::Context::default();
let _ = ctx.run(RawInput::default(), |ctx| {
egui::CentralPanel::default().show(ctx, |ui| {
c.bench_function("label &str", |b| {
b.iter(|| {
c.bench_function("label &str", |b| {
b.iter_batched_ref(
|| create_benchmark_ui(ctx),
|ui| {
ui.label("the quick brown fox jumps over the lazy dog");
});
});
c.bench_function("label format!", |b| {
b.iter(|| {
},
BatchSize::LargeInput,
);
});
c.bench_function("label format!", |b| {
b.iter_batched_ref(
|| create_benchmark_ui(ctx),
|ui| {
ui.label("the quick brown fox jumps over the lazy dog".to_owned());
});
});
},
BatchSize::LargeInput,
);
});
});
}
{
let ctx = egui::Context::default();
let _ = ctx.run(RawInput::default(), |ctx| {
let mut group = c.benchmark_group("button");
// To ensure we have a valid image, let's use the font texture. The size
// shouldn't be important for this benchmark.
let image = SizedTexture::new(TextureId::default(), Vec2::splat(16.0));
group.bench_function("1_button_text", |b| {
b.iter_batched_ref(
|| create_benchmark_ui(ctx),
|ui| {
ui.add(Button::new("Hello World"));
},
BatchSize::LargeInput,
);
});
group.bench_function("2_button_text_image", |b| {
b.iter_batched_ref(
|| create_benchmark_ui(ctx),
|ui| {
ui.add(Button::image_and_text(image, "Hello World"));
},
BatchSize::LargeInput,
);
});
group.bench_function("3_button_text_image_right_text", |b| {
b.iter_batched_ref(
|| create_benchmark_ui(ctx),
|ui| {
ui.add(Button::image_and_text(image, "Hello World").right_text(""));
},
BatchSize::LargeInput,
);
});
});
}