diff --git a/benches/Cargo.toml b/benches/Cargo.toml index ca22ca2f3b835a..66f0f6ea8c1a47 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dev-dependencies] criterion = "0.3" +rand = { version = "0.8.0", features = ["small_rng"] } bevy = { path = "../" } [[bench]] @@ -16,6 +17,11 @@ name = "system_stage" path = "benches/bevy_ecs/stages.rs" harness = false +[[bench]] +name = "commands" +path = "benches/bevy_ecs/commands.rs" +harness = false + [[bench]] name = "iter" path = "benches/bevy_tasks/iter.rs" diff --git a/benches/benches/bevy_ecs/commands.rs b/benches/benches/bevy_ecs/commands.rs new file mode 100644 index 00000000000000..ecfc98dcf7654c --- /dev/null +++ b/benches/benches/bevy_ecs/commands.rs @@ -0,0 +1,121 @@ +use bevy::ecs::{ + system::{Command, CommandQueue, Commands}, + world::World, +}; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use rand::{rngs::SmallRng, RngCore, SeedableRng}; + +criterion_group!(benches, empty_commands, spawn_commands, fake_commands); +criterion_main!(benches); + +struct A; +struct B; +struct C; + +fn empty_commands(criterion: &mut Criterion) { + let mut group = criterion.benchmark_group("empty_commands"); + group.warm_up_time(std::time::Duration::from_millis(500)); + group.measurement_time(std::time::Duration::from_secs(4)); + + group.bench_function("0_entities", |bencher| { + let mut world = World::default(); + let mut command_queue = CommandQueue::default(); + + bencher.iter(|| { + command_queue.apply(&mut world); + }); + }); + + group.finish(); +} + +fn spawn_commands(criterion: &mut Criterion) { + let mut group = criterion.benchmark_group("spawn_commands"); + group.warm_up_time(std::time::Duration::from_millis(500)); + group.measurement_time(std::time::Duration::from_secs(4)); + + for entity_count in (1..5).map(|i| i * 2 * 1000) { + group.bench_function(format!("{}_entities", entity_count), |bencher| { + let mut world = World::default(); + let mut command_queue = CommandQueue::default(); + + let mut rng = SmallRng::seed_from_u64(42); + let mut rng_bool = || rng.next_u32() % 2 == 0; + + bencher.iter(|| { + let mut commands = Commands::new(&mut command_queue, &world); + for _ in 0..entity_count { + let mut entity = commands.spawn(); + + if rng_bool() { + entity.insert(A); + } + + if rng_bool() { + entity.insert(B); + } + + if rng_bool() { + entity.insert(C); + } + + if rng_bool() { + entity.despawn(); + } + } + drop(commands); + command_queue.apply(&mut world); + }); + }); + } + + group.finish(); +} + +struct FakeCommandA; +struct FakeCommandB(u64); + +impl Command for FakeCommandA { + fn write(self: Box, world: &mut World) { + black_box(self); + black_box(world); + } +} + +impl Command for FakeCommandB { + fn write(self: Box, world: &mut World) { + black_box(self); + black_box(world); + } +} + +fn fake_commands(criterion: &mut Criterion) { + let mut group = criterion.benchmark_group("fake_commands"); + group.warm_up_time(std::time::Duration::from_millis(500)); + group.measurement_time(std::time::Duration::from_secs(4)); + + for command_count in (1..5).map(|i| i * 2 * 1000) { + group.bench_function(format!("{}_commands", command_count), |bencher| { + let mut world = World::default(); + let mut command_queue = CommandQueue::default(); + + let mut rng = SmallRng::seed_from_u64(42); + let mut rng_bool = || rng.next_u32() % 2 == 0; + + bencher.iter(|| { + let mut commands = Commands::new(&mut command_queue, &world); + for _ in 0..command_count { + if rng_bool() { + commands.add(FakeCommandA); + } else { + commands.add(FakeCommandB(0)); + } + } + drop(commands); + command_queue.apply(&mut world); + }); + }); + } + + group.finish(); +}