# Objective - Benchmarks are inconsistently setup, there are several that do not compile, and several others that need to be reformatted. - Related / precursor to #16647, this is part of my attempt migrating [`bevy-bencher`](https://github.com/TheBevyFlock/bevy-bencher) to the official benchmarks. ## Solution > [!TIP] > > I recommend reviewing this PR commit-by-commit, instead of all at once! In5d26f56eb9I reorganized how benches were registered. Now this is one `[[bench]]` per Bevy crate. In each crate benchmark folder, there is a `main.rs` that calls `criterion_main!`. I also disabled automatic benchmark discovery, which isn't necessarily required, but may clear up confusion with our custom setup. I also fixed a few errors that were causing the benchmarks to fail to compile. Inafc8d33a87I ran `rustfmt` on all of the benchmarks. Ind6cdf960abI fixed all of the Clippy warnings. Inee94d48f50I fixed some of the benchmarks' usage of `black_box()`. I ended up opening https://github.com/rust-lang/rust/pull/133942 due to this, which should help prevent this in the future. Incbe1688dcdI renamed all of the ECS benchmark groups to be called `benches`, to be consistent with the other crate benchmarks. Ine701c212cdand8815bb78b0I re-ordered some imports and module definitions, and uplifted `fragmentation/mod.rs` to `fragementation.rs`. Finally, inb0065e0b0bI organized `Cargo.toml` and bumped Criterion to v0.5. ## Testing - `cd benches && cargo clippy --benches` - `cd benches && cargo fmt --all`
100 lines
2.9 KiB
Rust
100 lines
2.9 KiB
Rust
use bevy_ecs::prelude::*;
|
|
use bevy_ecs::system::SystemState;
|
|
use core::hint::black_box;
|
|
use criterion::*;
|
|
use glam::*;
|
|
|
|
criterion_group!(benches, iter_frag_empty);
|
|
|
|
#[derive(Component, Default)]
|
|
struct Table<const X: usize = 0>(usize);
|
|
#[derive(Component, Default)]
|
|
#[component(storage = "SparseSet")]
|
|
struct Sparse<const X: usize = 0>(usize);
|
|
|
|
fn flip_coin() -> bool {
|
|
rand::random::<bool>()
|
|
}
|
|
fn iter_frag_empty(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("iter_fragmented(4096)_empty");
|
|
group.warm_up_time(core::time::Duration::from_millis(500));
|
|
group.measurement_time(core::time::Duration::from_secs(4));
|
|
|
|
group.bench_function("foreach_table", |b| {
|
|
let mut world = World::new();
|
|
spawn_empty_frag_archetype::<Table>(&mut world);
|
|
let mut q: SystemState<Query<(Entity, &Table)>> =
|
|
SystemState::<Query<(Entity, &Table<0>)>>::new(&mut world);
|
|
let query = q.get(&world);
|
|
b.iter(move || {
|
|
let mut res = 0;
|
|
query.iter().for_each(|(e, t)| {
|
|
res += e.to_bits();
|
|
black_box(t);
|
|
});
|
|
});
|
|
});
|
|
group.bench_function("foreach_sparse", |b| {
|
|
let mut world = World::new();
|
|
spawn_empty_frag_archetype::<Sparse>(&mut world);
|
|
let mut q: SystemState<Query<(Entity, &Sparse)>> =
|
|
SystemState::<Query<(Entity, &Sparse<0>)>>::new(&mut world);
|
|
let query = q.get(&world);
|
|
b.iter(move || {
|
|
let mut res = 0;
|
|
query.iter().for_each(|(e, t)| {
|
|
res += e.to_bits();
|
|
black_box(t);
|
|
});
|
|
});
|
|
});
|
|
group.finish();
|
|
|
|
fn spawn_empty_frag_archetype<T: Component + Default>(world: &mut World) {
|
|
for i in 0..65536 {
|
|
let mut e = world.spawn_empty();
|
|
if flip_coin() {
|
|
e.insert(Table::<1>(0));
|
|
}
|
|
if flip_coin() {
|
|
e.insert(Table::<2>(0));
|
|
}
|
|
if flip_coin() {
|
|
e.insert(Table::<3>(0));
|
|
}
|
|
if flip_coin() {
|
|
e.insert(Table::<4>(0));
|
|
}
|
|
if flip_coin() {
|
|
e.insert(Table::<5>(0));
|
|
}
|
|
if flip_coin() {
|
|
e.insert(Table::<6>(0));
|
|
}
|
|
if flip_coin() {
|
|
e.insert(Table::<7>(0));
|
|
}
|
|
if flip_coin() {
|
|
e.insert(Table::<8>(0));
|
|
}
|
|
if flip_coin() {
|
|
e.insert(Table::<9>(0));
|
|
}
|
|
if flip_coin() {
|
|
e.insert(Table::<10>(0));
|
|
}
|
|
if flip_coin() {
|
|
e.insert(Table::<11>(0));
|
|
}
|
|
if flip_coin() {
|
|
e.insert(Table::<12>(0));
|
|
}
|
|
e.insert(T::default());
|
|
|
|
if i != 0 {
|
|
e.despawn();
|
|
}
|
|
}
|
|
}
|
|
}
|