From 87991c50f1d4d02a0bdc2683e1a55ba17ce6aa1f Mon Sep 17 00:00:00 2001 From: TheRawMeatball Date: Tue, 26 Apr 2022 21:20:13 +0000 Subject: [PATCH] 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 --- benches/Cargo.toml | 2 + benches/benches/bevy_ecs/world_get.rs | 119 +++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 1 deletion(-) diff --git a/benches/Cargo.toml b/benches/Cargo.toml index 9f509cccd8..4c8e51c280 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -8,6 +8,8 @@ license = "MIT OR Apache-2.0" [dev-dependencies] glam = "0.20" +rand = "0.8" +rand_chacha = "0.3" criterion = { version = "0.3", features = ["html_reports"] } bevy_ecs = { path = "../crates/bevy_ecs" } bevy_tasks = { path = "../crates/bevy_tasks" } diff --git a/benches/benches/bevy_ecs/world_get.rs b/benches/benches/bevy_ecs/world_get.rs index ce36dfd703..f96df193e7 100644 --- a/benches/benches/bevy_ecs/world_get.rs +++ b/benches/benches/bevy_ecs/world_get.rs @@ -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 rand::{prelude::SliceRandom, SeedableRng}; +use rand_chacha::ChaCha8Rng; criterion_group!( benches, @@ -8,6 +15,8 @@ criterion_group!( world_query_get, world_query_iter, world_query_for_each, + query_get_component, + query_get, ); criterion_main!(benches); @@ -20,6 +29,10 @@ struct Sparse(f32); const RANGE: std::ops::Range = 5..6; +fn deterministic_rand() -> ChaCha8Rng { + ChaCha8Rng::seed_from_u64(42) +} + fn setup(entity_count: u32) -> World { let mut world = World::default(); world.spawn_batch((0..entity_count).map(|_| (T::default(),))); @@ -188,3 +201,107 @@ fn world_query_for_each(criterion: &mut Criterion) { 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::>::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::(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::>::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::(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::>::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::>::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(); +}