Add a random access get_component benchmark (#4607)

# Objective

Add a benchmark to measure the performance of get_component, particularly for cases involving random access.

Enables #2965
This commit is contained in:
TheRawMeatball 2022-04-26 21:20:13 +00:00
parent 4e547ded11
commit 87991c50f1
2 changed files with 120 additions and 1 deletions

View file

@ -8,6 +8,8 @@ license = "MIT OR Apache-2.0"
[dev-dependencies] [dev-dependencies]
glam = "0.20" glam = "0.20"
rand = "0.8"
rand_chacha = "0.3"
criterion = { version = "0.3", features = ["html_reports"] } criterion = { version = "0.3", features = ["html_reports"] }
bevy_ecs = { path = "../crates/bevy_ecs" } bevy_ecs = { path = "../crates/bevy_ecs" }
bevy_tasks = { path = "../crates/bevy_tasks" } bevy_tasks = { path = "../crates/bevy_tasks" }

View file

@ -1,5 +1,12 @@
use bevy_ecs::{component::Component, entity::Entity, world::World}; use bevy_ecs::{
component::Component,
entity::Entity,
system::{Query, SystemState},
world::World,
};
use criterion::{black_box, criterion_group, criterion_main, Criterion}; use criterion::{black_box, criterion_group, criterion_main, Criterion};
use rand::{prelude::SliceRandom, SeedableRng};
use rand_chacha::ChaCha8Rng;
criterion_group!( criterion_group!(
benches, benches,
@ -8,6 +15,8 @@ criterion_group!(
world_query_get, world_query_get,
world_query_iter, world_query_iter,
world_query_for_each, world_query_for_each,
query_get_component,
query_get,
); );
criterion_main!(benches); criterion_main!(benches);
@ -20,6 +29,10 @@ struct Sparse(f32);
const RANGE: std::ops::Range<u32> = 5..6; const RANGE: std::ops::Range<u32> = 5..6;
fn deterministic_rand() -> ChaCha8Rng {
ChaCha8Rng::seed_from_u64(42)
}
fn setup<T: Component + Default>(entity_count: u32) -> World { fn setup<T: Component + Default>(entity_count: u32) -> World {
let mut world = World::default(); let mut world = World::default();
world.spawn_batch((0..entity_count).map(|_| (T::default(),))); world.spawn_batch((0..entity_count).map(|_| (T::default(),)));
@ -188,3 +201,107 @@ fn world_query_for_each(criterion: &mut Criterion) {
group.finish(); group.finish();
} }
fn query_get_component(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("query_get_component");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
group.bench_function(format!("{}_entities_table", entity_count), |bencher| {
let mut world = World::default();
let mut entities: Vec<_> = world
.spawn_batch((0..entity_count).map(|_| (Table::default(),)))
.collect();
entities.shuffle(&mut deterministic_rand());
let mut query = SystemState::<Query<&Table>>::new(&mut world);
let query = query.get(&world);
bencher.iter(|| {
let mut count = 0;
for comp in entities
.iter()
.flat_map(|&e| query.get_component::<Table>(e))
{
black_box(comp);
count += 1;
black_box(count);
}
assert_eq!(black_box(count), entity_count);
});
});
group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
let mut world = World::default();
let mut entities: Vec<_> = world
.spawn_batch((0..entity_count).map(|_| (Sparse::default(),)))
.collect();
entities.shuffle(&mut deterministic_rand());
let mut query = SystemState::<Query<&Sparse>>::new(&mut world);
let query = query.get(&world);
bencher.iter(|| {
let mut count = 0;
for comp in entities
.iter()
.flat_map(|&e| query.get_component::<Sparse>(e))
{
black_box(comp);
count += 1;
black_box(count);
}
assert_eq!(black_box(count), entity_count);
});
});
}
group.finish();
}
fn query_get(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("query_get");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
group.bench_function(format!("{}_entities_table", entity_count), |bencher| {
let mut world = World::default();
let mut entities: Vec<_> = world
.spawn_batch((0..entity_count).map(|_| (Table::default(),)))
.collect();
entities.shuffle(&mut deterministic_rand());
let mut query = SystemState::<Query<&Table>>::new(&mut world);
let query = query.get(&world);
bencher.iter(|| {
let mut count = 0;
for comp in entities.iter().flat_map(|&e| query.get(e)) {
black_box(comp);
count += 1;
black_box(count);
}
assert_eq!(black_box(count), entity_count);
});
});
group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
let mut world = World::default();
let mut entities: Vec<_> = world
.spawn_batch((0..entity_count).map(|_| (Sparse::default(),)))
.collect();
entities.shuffle(&mut deterministic_rand());
let mut query = SystemState::<Query<&Sparse>>::new(&mut world);
let query = query.get(&world);
bencher.iter(|| {
let mut count = 0;
for comp in entities.iter().flat_map(|&e| query.get(e)) {
black_box(comp);
count += 1;
black_box(count);
}
assert_eq!(black_box(count), entity_count);
});
});
}
group.finish();
}