ECS benchmarks organization (#5189)

## Objective

Fixes: #5110

## Solution

- Moved benches into separate modules according to the part of ECS they are testing.
- Made so all ECS benches are included in one `benches.rs` so they don’t need to be added separately in `Cargo.toml`.
- Renamed a bunch of files to have more coherent names.
- Merged `schedule.rs` and `system_schedule.rs` into one file.
This commit is contained in:
ShadowCurse 2022-07-04 14:17:45 +00:00
parent 050251da5a
commit 179f719553
41 changed files with 612 additions and 639 deletions

View File

@ -18,38 +18,8 @@ bevy_tasks = { path = "../crates/bevy_tasks" }
bevy_utils = { path = "../crates/bevy_utils" } bevy_utils = { path = "../crates/bevy_utils" }
[[bench]] [[bench]]
name = "archetype_updates" name = "ecs"
path = "benches/bevy_ecs/archetype_updates.rs" path = "benches/bevy_ecs/benches.rs"
harness = false
[[bench]]
name = "ecs_bench_suite"
path = "benches/bevy_ecs/ecs_bench_suite/mod.rs"
harness = false
[[bench]]
name = "run_criteria"
path = "benches/bevy_ecs/run_criteria.rs"
harness = false
[[bench]]
name = "commands"
path = "benches/bevy_ecs/commands.rs"
harness = false
[[bench]]
name = "system_stage"
path = "benches/bevy_ecs/stages.rs"
harness = false
[[bench]]
name = "world_get"
path = "benches/bevy_ecs/world_get.rs"
harness = false
[[bench]]
name = "schedule"
path = "benches/bevy_ecs/schedule.rs"
harness = false harness = false
[[bench]] [[bench]]

View File

@ -0,0 +1,13 @@
use criterion::criterion_main;
mod components;
mod iteration;
mod scheduling;
mod world;
criterion_main!(
iteration::iterations_benches,
components::components_benches,
scheduling::scheduling_benches,
world::world_benches,
);

View File

@ -3,10 +3,7 @@ use bevy_ecs::{
schedule::{Stage, SystemStage}, schedule::{Stage, SystemStage},
world::World, world::World,
}; };
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use criterion::{BenchmarkId, Criterion};
criterion_group!(benches, no_archetypes, added_archetypes);
criterion_main!(benches);
#[derive(Component)] #[derive(Component)]
struct A<const N: u16>(f32); struct A<const N: u16>(f32);
@ -77,7 +74,7 @@ fn add_archetypes(world: &mut World, count: u16) {
} }
} }
fn no_archetypes(criterion: &mut Criterion) { pub fn no_archetypes(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("no_archetypes"); let mut group = criterion.benchmark_group("no_archetypes");
for i in 0..=5 { for i in 0..=5 {
let system_count = i * 20; let system_count = i * 20;
@ -94,7 +91,7 @@ fn no_archetypes(criterion: &mut Criterion) {
} }
} }
fn added_archetypes(criterion: &mut Criterion) { pub fn added_archetypes(criterion: &mut Criterion) {
const SYSTEM_COUNT: usize = 100; const SYSTEM_COUNT: usize = 100;
let mut group = criterion.benchmark_group("added_archetypes"); let mut group = criterion.benchmark_group("added_archetypes");
for archetype_count in [100, 200, 500, 1000, 2000, 5000, 10000] { for archetype_count in [100, 200, 500, 1000, 2000, 5000, 10000] {

View File

@ -0,0 +1,65 @@
use criterion::*;
mod add_remove_big_sparse_set;
mod add_remove_big_table;
mod add_remove_sparse_set;
mod add_remove_table;
mod archetype_updates;
mod insert_simple;
mod insert_simple_unbatched;
use archetype_updates::*;
criterion_group!(
components_benches,
add_remove,
add_remove_big,
insert_simple,
no_archetypes,
added_archetypes,
);
fn add_remove(c: &mut Criterion) {
let mut group = c.benchmark_group("add_remove");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("table", |b| {
let mut bench = add_remove_table::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("sparse_set", |b| {
let mut bench = add_remove_sparse_set::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}
fn add_remove_big(c: &mut Criterion) {
let mut group = c.benchmark_group("add_remove_big");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("table", |b| {
let mut bench = add_remove_big_table::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("sparse_set", |b| {
let mut bench = add_remove_big_sparse_set::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}
fn insert_simple(c: &mut Criterion) {
let mut group = c.benchmark_group("insert_simple");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("base", |b| {
let mut bench = insert_simple::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("unbatched", |b| {
let mut bench = insert_simple_unbatched::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}

View File

@ -1,23 +0,0 @@
use bevy_ecs::prelude::*;
#[derive(Component)]
struct A(f32);
pub struct Benchmark<'w>(World, Entity, QueryState<&'w mut A>);
impl<'w> Benchmark<'w> {
pub fn new() -> Self {
let mut world = World::new();
let entity = world.spawn().insert(A(0.0)).id();
let query = world.query::<&mut A>();
Self(world, entity, query)
}
pub fn run(&mut self) {
for _x in 0..100000 {
let mut a = unsafe { self.2.get_unchecked(&mut self.0, self.1).unwrap() };
a.0 += 1.0;
}
}
}

View File

@ -1,29 +0,0 @@
use bevy_ecs::prelude::*;
#[derive(Component)]
struct A(f32);
pub struct Benchmark(World, Entity, Box<dyn System<In = Entity, Out = ()>>);
impl Benchmark {
pub fn new() -> Self {
let mut world = World::new();
let entity = world.spawn().insert(A(0.0)).id();
fn query_system(In(entity): In<Entity>, mut query: Query<&mut A>) {
for _ in 0..100_000 {
let mut a = query.get_mut(entity).unwrap();
a.0 += 1.0;
}
}
let mut system = IntoSystem::into_system(query_system);
system.initialize(&mut world);
system.update_archetype_component_access(&world);
Self(world, entity, Box::new(system))
}
pub fn run(&mut self) {
self.2.run(self.1, &mut self.0);
}
}

View File

@ -1,214 +0,0 @@
use criterion::*;
mod add_remove_big_sparse_set;
mod add_remove_big_table;
mod add_remove_sparse_set;
mod add_remove_table;
mod frag_iter;
mod frag_iter_wide;
mod frag_iter_foreach;
mod frag_iter_foreach_wide;
mod get_component;
mod get_component_system;
mod heavy_compute;
mod schedule;
mod simple_insert;
mod simple_insert_unbatched;
mod simple_iter;
mod simple_iter_wide;
mod simple_iter_foreach;
mod simple_iter_foreach_wide;
mod simple_iter_sparse;
mod simple_iter_sparse_wide;
mod simple_iter_sparse_foreach;
mod simple_iter_sparse_foreach_wide;
mod simple_iter_system;
mod sparse_frag_iter;
mod sparse_frag_iter_wide;
mod sparse_frag_iter_foreach;
mod sparse_frag_iter_foreach_wide;
fn bench_simple_insert(c: &mut Criterion) {
let mut group = c.benchmark_group("simple_insert");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("base", |b| {
let mut bench = simple_insert::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("unbatched", |b| {
let mut bench = simple_insert_unbatched::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}
fn bench_simple_iter(c: &mut Criterion) {
let mut group = c.benchmark_group("simple_iter");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("base", |b| {
let mut bench = simple_iter::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("wide", |b| {
let mut bench = simple_iter_wide::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("system", |b| {
let mut bench = simple_iter_system::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("sparse", |b| {
let mut bench = simple_iter_sparse::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("sparse_wide", |b| {
let mut bench = simple_iter_sparse_wide::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("foreach", |b| {
let mut bench = simple_iter_foreach::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("foreach_wide", |b| {
let mut bench = simple_iter_foreach_wide::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("sparse_foreach", |b| {
let mut bench = simple_iter_sparse_foreach::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("sparse_foreach_wide", |b| {
let mut bench = simple_iter_sparse_foreach_wide::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}
fn bench_frag_iter_bc(c: &mut Criterion) {
let mut group = c.benchmark_group("fragmented_iter");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("base", |b| {
let mut bench = frag_iter::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("wide", |b| {
let mut bench = frag_iter_wide::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("foreach", |b| {
let mut bench = frag_iter_foreach::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("foreach_wide", |b| {
let mut bench = frag_iter_foreach_wide::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}
fn bench_sparse_frag_iter(c: &mut Criterion) {
let mut group = c.benchmark_group("sparse_fragmented_iter");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("base", |b| {
let mut bench = sparse_frag_iter::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("wide", |b| {
let mut bench = sparse_frag_iter_wide::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("foreach", |b| {
let mut bench = sparse_frag_iter_foreach::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("foreach_wide", |b| {
let mut bench = sparse_frag_iter_foreach_wide::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}
fn bench_schedule(c: &mut Criterion) {
let mut group = c.benchmark_group("schedule");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("base", |b| {
let mut bench = schedule::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}
fn bench_heavy_compute(c: &mut Criterion) {
let mut group = c.benchmark_group("heavy_compute");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("base", |b| {
let mut bench = heavy_compute::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}
fn bench_add_remove(c: &mut Criterion) {
let mut group = c.benchmark_group("add_remove_component");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("table", |b| {
let mut bench = add_remove_table::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("sparse_set", |b| {
let mut bench = add_remove_sparse_set::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}
fn bench_add_remove_big(c: &mut Criterion) {
let mut group = c.benchmark_group("add_remove_component_big");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("table", |b| {
let mut bench = add_remove_big_table::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("sparse_set", |b| {
let mut bench = add_remove_big_sparse_set::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}
fn bench_get_component(c: &mut Criterion) {
let mut group = c.benchmark_group("get_component");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("base", |b| {
let mut bench = get_component::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("system", |b| {
let mut bench = get_component_system::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}
criterion_group!(
benchmarks,
bench_simple_insert,
bench_simple_iter,
bench_frag_iter_bc,
bench_sparse_frag_iter,
bench_schedule,
bench_heavy_compute,
bench_add_remove,
bench_add_remove_big,
bench_get_component,
);
criterion_main!(benchmarks);

View File

@ -1,58 +0,0 @@
use bevy_ecs::prelude::*;
#[derive(Component)]
struct A(f32);
#[derive(Component)]
struct B(f32);
#[derive(Component)]
struct C(f32);
#[derive(Component)]
struct D(f32);
#[derive(Component)]
struct E(f32);
fn ab(mut query: Query<(&mut A, &mut B)>) {
query.for_each_mut(|(mut a, mut b)| {
std::mem::swap(&mut a.0, &mut b.0);
});
}
fn cd(mut query: Query<(&mut C, &mut D)>) {
query.for_each_mut(|(mut c, mut d)| {
std::mem::swap(&mut c.0, &mut d.0);
});
}
fn ce(mut query: Query<(&mut C, &mut E)>) {
query.for_each_mut(|(mut c, mut e)| {
std::mem::swap(&mut c.0, &mut e.0);
});
}
pub struct Benchmark(World, SystemStage);
impl Benchmark {
pub fn new() -> Self {
let mut world = World::default();
world.spawn_batch((0..10000).map(|_| (A(0.0), B(0.0))));
world.spawn_batch((0..10000).map(|_| (A(0.0), B(0.0), C(0.0))));
world.spawn_batch((0..10000).map(|_| (A(0.0), B(0.0), C(0.0), D(0.0))));
world.spawn_batch((0..10000).map(|_| (A(0.0), B(0.0), C(0.0), E(0.0))));
let mut stage = SystemStage::parallel();
stage.add_system(ab);
stage.add_system(cd);
stage.add_system(ce);
stage.run(&mut world);
Self(world, stage)
}
pub fn run(&mut self) {
self.1.run(&mut self.0);
}
}

View File

@ -1,23 +1,25 @@
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
use bevy_tasks::{ComputeTaskPool, TaskPool}; use bevy_tasks::{ComputeTaskPool, TaskPool};
use criterion::Criterion;
use glam::*; use glam::*;
#[derive(Component, Copy, Clone)] pub fn heavy_compute(c: &mut Criterion) {
struct Position(Vec3); #[derive(Component, Copy, Clone)]
struct Position(Vec3);
#[derive(Component, Copy, Clone)] #[derive(Component, Copy, Clone)]
struct Rotation(Vec3); struct Rotation(Vec3);
#[derive(Component, Copy, Clone)] #[derive(Component, Copy, Clone)]
struct Velocity(Vec3); struct Velocity(Vec3);
#[derive(Component, Copy, Clone)] #[derive(Component, Copy, Clone)]
struct Transform(Mat4); struct Transform(Mat4);
pub struct Benchmark(World, Box<dyn System<In = (), Out = ()>>); let mut group = c.benchmark_group("heavy_compute");
group.warm_up_time(std::time::Duration::from_millis(500));
impl Benchmark { group.measurement_time(std::time::Duration::from_secs(4));
pub fn new() -> Self { group.bench_function("base", |b| {
ComputeTaskPool::init(TaskPool::default); ComputeTaskPool::init(TaskPool::default);
let mut world = World::default(); let mut world = World::default();
@ -45,10 +47,7 @@ impl Benchmark {
system.initialize(&mut world); system.initialize(&mut world);
system.update_archetype_component_access(&world); system.update_archetype_component_access(&world);
Self(world, Box::new(system)) b.iter(move || system.run((), &mut world));
} });
group.finish();
pub fn run(&mut self) {
self.1.run((), &mut self.0);
}
} }

View File

@ -7,7 +7,7 @@ macro_rules! create_entities {
struct $variants(f32); struct $variants(f32);
for _ in 0..20 { for _ in 0..20 {
$world.spawn().insert_bundle(( $world.spawn().insert_bundle((
$variants(0.0), $variants(0.0),
Data::<0>(1.0), Data::<0>(1.0),
Data::<1>(1.0), Data::<1>(1.0),
Data::<2>(1.0), Data::<2>(1.0),
@ -28,19 +28,22 @@ macro_rules! create_entities {
#[derive(Component)] #[derive(Component)]
struct Data<const X: usize>(f32); struct Data<const X: usize>(f32);
pub struct Benchmark<'w>(World, QueryState<( pub struct Benchmark<'w>(
&'w mut Data<0>, World,
&'w mut Data<1>, QueryState<(
&'w mut Data<2>, &'w mut Data<0>,
&'w mut Data<3>, &'w mut Data<1>,
&'w mut Data<4>, &'w mut Data<2>,
&'w mut Data<5>, &'w mut Data<3>,
&'w mut Data<6>, &'w mut Data<4>,
&'w mut Data<7>, &'w mut Data<5>,
&'w mut Data<8>, &'w mut Data<6>,
&'w mut Data<9>, &'w mut Data<7>,
&'w mut Data<10>, &'w mut Data<8>,
)>); &'w mut Data<9>,
&'w mut Data<10>,
)>,
);
impl<'w> Benchmark<'w> { impl<'w> Benchmark<'w> {
pub fn new() -> Self { pub fn new() -> Self {
@ -54,17 +57,17 @@ impl<'w> Benchmark<'w> {
pub fn run(&mut self) { pub fn run(&mut self) {
self.1.for_each_mut(&mut self.0, |mut data| { self.1.for_each_mut(&mut self.0, |mut data| {
data.0.0 *= 2.0; data.0 .0 *= 2.0;
data.1.0 *= 2.0; data.1 .0 *= 2.0;
data.2.0 *= 2.0; data.2 .0 *= 2.0;
data.3.0 *= 2.0; data.3 .0 *= 2.0;
data.4.0 *= 2.0; data.4 .0 *= 2.0;
data.5.0 *= 2.0; data.5 .0 *= 2.0;
data.6.0 *= 2.0; data.6 .0 *= 2.0;
data.7.0 *= 2.0; data.7 .0 *= 2.0;
data.8.0 *= 2.0; data.8 .0 *= 2.0;
data.9.0 *= 2.0; data.9 .0 *= 2.0;
data.10.0 *= 2.0; data.10 .0 *= 2.0;
}); });
} }
} }

View File

@ -15,19 +15,22 @@ macro_rules! create_entities {
#[derive(Component)] #[derive(Component)]
struct Data<const X: usize>(f32); struct Data<const X: usize>(f32);
pub struct Benchmark<'w>(World, QueryState<( pub struct Benchmark<'w>(
&'w mut Data<0>, World,
&'w mut Data<1>, QueryState<(
&'w mut Data<2>, &'w mut Data<0>,
&'w mut Data<3>, &'w mut Data<1>,
&'w mut Data<4>, &'w mut Data<2>,
&'w mut Data<5>, &'w mut Data<3>,
&'w mut Data<6>, &'w mut Data<4>,
&'w mut Data<7>, &'w mut Data<5>,
&'w mut Data<8>, &'w mut Data<6>,
&'w mut Data<9>, &'w mut Data<7>,
&'w mut Data<10>, &'w mut Data<8>,
)>); &'w mut Data<9>,
&'w mut Data<10>,
)>,
);
impl<'w> Benchmark<'w> { impl<'w> Benchmark<'w> {
pub fn new() -> Self { pub fn new() -> Self {
@ -64,17 +67,17 @@ impl<'w> Benchmark<'w> {
pub fn run(&mut self) { pub fn run(&mut self) {
self.1.for_each_mut(&mut self.0, |mut data| { self.1.for_each_mut(&mut self.0, |mut data| {
data.0.0 *= 2.0; data.0 .0 *= 2.0;
data.1.0 *= 2.0; data.1 .0 *= 2.0;
data.2.0 *= 2.0; data.2 .0 *= 2.0;
data.3.0 *= 2.0; data.3 .0 *= 2.0;
data.4.0 *= 2.0; data.4 .0 *= 2.0;
data.5.0 *= 2.0; data.5 .0 *= 2.0;
data.6.0 *= 2.0; data.6 .0 *= 2.0;
data.7.0 *= 2.0; data.7 .0 *= 2.0;
data.8.0 *= 2.0; data.8 .0 *= 2.0;
data.9.0 *= 2.0; data.9 .0 *= 2.0;
data.10.0 *= 2.0; data.10 .0 *= 2.0;
}); });
} }
} }

View File

@ -7,7 +7,7 @@ macro_rules! create_entities {
struct $variants(f32); struct $variants(f32);
for _ in 0..20 { for _ in 0..20 {
$world.spawn().insert_bundle(( $world.spawn().insert_bundle((
$variants(0.0), $variants(0.0),
Data::<0>(1.0), Data::<0>(1.0),
Data::<1>(1.0), Data::<1>(1.0),
Data::<2>(1.0), Data::<2>(1.0),
@ -28,19 +28,22 @@ macro_rules! create_entities {
#[derive(Component)] #[derive(Component)]
struct Data<const X: usize>(f32); struct Data<const X: usize>(f32);
pub struct Benchmark<'w>(World, QueryState<( pub struct Benchmark<'w>(
&'w mut Data<0>, World,
&'w mut Data<1>, QueryState<(
&'w mut Data<2>, &'w mut Data<0>,
&'w mut Data<3>, &'w mut Data<1>,
&'w mut Data<4>, &'w mut Data<2>,
&'w mut Data<5>, &'w mut Data<3>,
&'w mut Data<6>, &'w mut Data<4>,
&'w mut Data<7>, &'w mut Data<5>,
&'w mut Data<8>, &'w mut Data<6>,
&'w mut Data<9>, &'w mut Data<7>,
&'w mut Data<10>, &'w mut Data<8>,
)>); &'w mut Data<9>,
&'w mut Data<10>,
)>,
);
impl<'w> Benchmark<'w> { impl<'w> Benchmark<'w> {
pub fn new() -> Self { pub fn new() -> Self {
@ -54,17 +57,17 @@ impl<'w> Benchmark<'w> {
pub fn run(&mut self) { pub fn run(&mut self) {
for mut data in self.1.iter_mut(&mut self.0) { for mut data in self.1.iter_mut(&mut self.0) {
data.0.0 *= 2.0; data.0 .0 *= 2.0;
data.1.0 *= 2.0; data.1 .0 *= 2.0;
data.2.0 *= 2.0; data.2 .0 *= 2.0;
data.3.0 *= 2.0; data.3 .0 *= 2.0;
data.4.0 *= 2.0; data.4 .0 *= 2.0;
data.5.0 *= 2.0; data.5 .0 *= 2.0;
data.6.0 *= 2.0; data.6 .0 *= 2.0;
data.7.0 *= 2.0; data.7 .0 *= 2.0;
data.8.0 *= 2.0; data.8 .0 *= 2.0;
data.9.0 *= 2.0; data.9 .0 *= 2.0;
data.10.0 *= 2.0; data.10 .0 *= 2.0;
} }
} }
} }

View File

@ -14,19 +14,22 @@ macro_rules! create_entities {
#[derive(Component)] #[derive(Component)]
struct Data<const X: usize>(f32); struct Data<const X: usize>(f32);
pub struct Benchmark<'w>(World, QueryState<( pub struct Benchmark<'w>(
&'w mut Data<0>, World,
&'w mut Data<1>, QueryState<(
&'w mut Data<2>, &'w mut Data<0>,
&'w mut Data<3>, &'w mut Data<1>,
&'w mut Data<4>, &'w mut Data<2>,
&'w mut Data<5>, &'w mut Data<3>,
&'w mut Data<6>, &'w mut Data<4>,
&'w mut Data<7>, &'w mut Data<5>,
&'w mut Data<8>, &'w mut Data<6>,
&'w mut Data<9>, &'w mut Data<7>,
&'w mut Data<10>, &'w mut Data<8>,
)>); &'w mut Data<9>,
&'w mut Data<10>,
)>,
);
impl<'w> Benchmark<'w> { impl<'w> Benchmark<'w> {
pub fn new() -> Self { pub fn new() -> Self {
@ -64,17 +67,17 @@ impl<'w> Benchmark<'w> {
pub fn run(&mut self) { pub fn run(&mut self) {
for mut data in self.1.iter_mut(&mut self.0) { for mut data in self.1.iter_mut(&mut self.0) {
data.0.0 *= 2.0; data.0 .0 *= 2.0;
data.1.0 *= 2.0; data.1 .0 *= 2.0;
data.2.0 *= 2.0; data.2 .0 *= 2.0;
data.3.0 *= 2.0; data.3 .0 *= 2.0;
data.4.0 *= 2.0; data.4 .0 *= 2.0;
data.5.0 *= 2.0; data.5 .0 *= 2.0;
data.6.0 *= 2.0; data.6 .0 *= 2.0;
data.7.0 *= 2.0; data.7 .0 *= 2.0;
data.8.0 *= 2.0; data.8 .0 *= 2.0;
data.9.0 *= 2.0; data.9 .0 *= 2.0;
data.10.0 *= 2.0; data.10 .0 *= 2.0;
} }
} }
} }

View File

@ -13,18 +13,21 @@ struct Rotation(Vec3);
#[derive(Component, Copy, Clone)] #[derive(Component, Copy, Clone)]
struct Velocity<const X: usize>(Vec3); struct Velocity<const X: usize>(Vec3);
pub struct Benchmark<'w>(World, QueryState<( pub struct Benchmark<'w>(
&'w Velocity<0>, World,
&'w mut Position<0>, QueryState<(
&'w Velocity<1>, &'w Velocity<0>,
&'w mut Position<1>, &'w mut Position<0>,
&'w Velocity<2>, &'w Velocity<1>,
&'w mut Position<2>, &'w mut Position<1>,
&'w Velocity<3>, &'w Velocity<2>,
&'w mut Position<3>, &'w mut Position<2>,
&'w Velocity<4>, &'w Velocity<3>,
&'w mut Position<4>, &'w mut Position<3>,
)>); &'w Velocity<4>,
&'w mut Position<4>,
)>,
);
impl<'w> Benchmark<'w> { impl<'w> Benchmark<'w> {
pub fn new() -> Self { pub fn new() -> Self {
@ -54,10 +57,10 @@ impl<'w> Benchmark<'w> {
pub fn run(&mut self) { pub fn run(&mut self) {
self.1.for_each_mut(&mut self.0, |mut item| { self.1.for_each_mut(&mut self.0, |mut item| {
item.1.0 += item.0.0; item.1 .0 += item.0 .0;
item.3.0 += item.2.0; item.3 .0 += item.2 .0;
item.5.0 += item.4.0; item.5 .0 += item.4 .0;
item.7.0 += item.6.0; item.7 .0 += item.6 .0;
}); });
} }
} }

View File

@ -15,18 +15,21 @@ struct Rotation(Vec3);
#[component(storage = "SparseSet")] #[component(storage = "SparseSet")]
struct Velocity<const X: usize>(Vec3); struct Velocity<const X: usize>(Vec3);
pub struct Benchmark<'w>(World, QueryState<( pub struct Benchmark<'w>(
&'w Velocity<0>, World,
&'w mut Position<0>, QueryState<(
&'w Velocity<1>, &'w Velocity<0>,
&'w mut Position<1>, &'w mut Position<0>,
&'w Velocity<2>, &'w Velocity<1>,
&'w mut Position<2>, &'w mut Position<1>,
&'w Velocity<3>, &'w Velocity<2>,
&'w mut Position<3>, &'w mut Position<2>,
&'w Velocity<4>, &'w Velocity<3>,
&'w mut Position<4>, &'w mut Position<3>,
)>); &'w Velocity<4>,
&'w mut Position<4>,
)>,
);
impl<'w> Benchmark<'w> { impl<'w> Benchmark<'w> {
pub fn new() -> Self { pub fn new() -> Self {
@ -56,10 +59,10 @@ impl<'w> Benchmark<'w> {
pub fn run(&mut self) { pub fn run(&mut self) {
self.1.for_each_mut(&mut self.0, |mut item| { self.1.for_each_mut(&mut self.0, |mut item| {
item.1.0 += item.0.0; item.1 .0 += item.0 .0;
item.3.0 += item.2.0; item.3 .0 += item.2 .0;
item.5.0 += item.4.0; item.5 .0 += item.4 .0;
item.7.0 += item.6.0; item.7 .0 += item.6 .0;
}); });
} }
} }

View File

@ -13,18 +13,21 @@ struct Rotation(Vec3);
#[derive(Component, Copy, Clone)] #[derive(Component, Copy, Clone)]
struct Velocity<const X: usize>(Vec3); struct Velocity<const X: usize>(Vec3);
pub struct Benchmark<'w>(World, QueryState<( pub struct Benchmark<'w>(
&'w Velocity<0>, World,
&'w mut Position<0>, QueryState<(
&'w Velocity<1>, &'w Velocity<0>,
&'w mut Position<1>, &'w mut Position<0>,
&'w Velocity<2>, &'w Velocity<1>,
&'w mut Position<2>, &'w mut Position<1>,
&'w Velocity<3>, &'w Velocity<2>,
&'w mut Position<3>, &'w mut Position<2>,
&'w Velocity<4>, &'w Velocity<3>,
&'w mut Position<4>, &'w mut Position<3>,
)>); &'w Velocity<4>,
&'w mut Position<4>,
)>,
);
impl<'w> Benchmark<'w> { impl<'w> Benchmark<'w> {
pub fn new() -> Self { pub fn new() -> Self {
@ -54,10 +57,10 @@ impl<'w> Benchmark<'w> {
pub fn run(&mut self) { pub fn run(&mut self) {
for mut item in self.1.iter_mut(&mut self.0) { for mut item in self.1.iter_mut(&mut self.0) {
item.1.0 += item.0.0; item.1 .0 += item.0 .0;
item.3.0 += item.2.0; item.3 .0 += item.2 .0;
item.5.0 += item.4.0; item.5 .0 += item.4 .0;
item.7.0 += item.6.0; item.7 .0 += item.6 .0;
} }
} }
} }

View File

@ -15,18 +15,21 @@ struct Rotation(Vec3);
#[component(storage = "SparseSet")] #[component(storage = "SparseSet")]
struct Velocity<const X: usize>(Vec3); struct Velocity<const X: usize>(Vec3);
pub struct Benchmark<'w>(World, QueryState<( pub struct Benchmark<'w>(
&'w Velocity<0>, World,
&'w mut Position<0>, QueryState<(
&'w Velocity<1>, &'w Velocity<0>,
&'w mut Position<1>, &'w mut Position<0>,
&'w Velocity<2>, &'w Velocity<1>,
&'w mut Position<2>, &'w mut Position<1>,
&'w Velocity<3>, &'w Velocity<2>,
&'w mut Position<3>, &'w mut Position<2>,
&'w Velocity<4>, &'w Velocity<3>,
&'w mut Position<4>, &'w mut Position<3>,
)>); &'w Velocity<4>,
&'w mut Position<4>,
)>,
);
impl<'w> Benchmark<'w> { impl<'w> Benchmark<'w> {
pub fn new() -> Self { pub fn new() -> Self {
@ -56,10 +59,10 @@ impl<'w> Benchmark<'w> {
pub fn run(&mut self) { pub fn run(&mut self) {
for mut item in self.1.iter_mut(&mut self.0) { for mut item in self.1.iter_mut(&mut self.0) {
item.1.0 += item.0.0; item.1 .0 += item.0 .0;
item.3.0 += item.2.0; item.3 .0 += item.2 .0;
item.5.0 += item.4.0; item.5 .0 += item.4 .0;
item.7.0 += item.6.0; item.7 .0 += item.6 .0;
} }
} }
} }

View File

@ -0,0 +1,119 @@
use criterion::*;
mod heavy_compute;
mod iter_frag;
mod iter_frag_foreach;
mod iter_frag_foreach_sparse;
mod iter_frag_foreach_wide;
mod iter_frag_foreach_wide_sparse;
mod iter_frag_sparse;
mod iter_frag_wide;
mod iter_frag_wide_sparse;
mod iter_simple;
mod iter_simple_foreach;
mod iter_simple_foreach_sparse_set;
mod iter_simple_foreach_wide;
mod iter_simple_foreach_wide_sparse_set;
mod iter_simple_sparse_set;
mod iter_simple_system;
mod iter_simple_wide;
mod iter_simple_wide_sparse_set;
use heavy_compute::*;
criterion_group!(
iterations_benches,
iter_frag,
iter_frag_sparse,
iter_simple,
heavy_compute,
);
fn iter_simple(c: &mut Criterion) {
let mut group = c.benchmark_group("iter_simple");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("base", |b| {
let mut bench = iter_simple::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("wide", |b| {
let mut bench = iter_simple_wide::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("system", |b| {
let mut bench = iter_simple_system::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("sparse_set", |b| {
let mut bench = iter_simple_sparse_set::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("wide_sparse_set", |b| {
let mut bench = iter_simple_wide_sparse_set::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("foreach", |b| {
let mut bench = iter_simple_foreach::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("foreach_wide", |b| {
let mut bench = iter_simple_foreach_wide::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("foreach_sparse_set", |b| {
let mut bench = iter_simple_foreach_sparse_set::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("foreach_wide_sparse_set", |b| {
let mut bench = iter_simple_foreach_wide_sparse_set::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}
fn iter_frag(c: &mut Criterion) {
let mut group = c.benchmark_group("iter_fragmented");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("base", |b| {
let mut bench = iter_frag::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("wide", |b| {
let mut bench = iter_frag_wide::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("foreach", |b| {
let mut bench = iter_frag_foreach::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("foreach_wide", |b| {
let mut bench = iter_frag_foreach_wide::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}
fn iter_frag_sparse(c: &mut Criterion) {
let mut group = c.benchmark_group("iter_fragmented_sparse");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("base", |b| {
let mut bench = iter_frag_sparse::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("wide", |b| {
let mut bench = iter_frag_wide_sparse::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("foreach", |b| {
let mut bench = iter_frag_foreach_sparse::Benchmark::new();
b.iter(move || bench.run());
});
group.bench_function("foreach_wide", |b| {
let mut bench = iter_frag_foreach_wide_sparse::Benchmark::new();
b.iter(move || bench.run());
});
group.finish();
}

View File

@ -0,0 +1,24 @@
use criterion::criterion_group;
mod run_criteria;
mod schedule;
mod stages;
use run_criteria::*;
use schedule::*;
use stages::*;
criterion_group!(
scheduling_benches,
run_criteria_yes,
run_criteria_no,
run_criteria_yes_with_labels,
run_criteria_no_with_labels,
run_criteria_yes_with_query,
run_criteria_yes_with_resource,
empty_systems,
busy_systems,
contrived,
schedule,
build_schedule,
);

View File

@ -5,24 +5,13 @@ use bevy_ecs::{
system::Query, system::Query,
world::World, world::World,
}; };
use criterion::{criterion_group, criterion_main, Criterion}; use criterion::Criterion;
criterion_group!(
benches,
run_criteria_yes,
run_criteria_no,
run_criteria_yes_with_labels,
run_criteria_no_with_labels,
run_criteria_yes_with_query,
run_criteria_yes_with_resource
);
criterion_main!(benches);
fn run_stage(stage: &mut SystemStage, world: &mut World) { fn run_stage(stage: &mut SystemStage, world: &mut World) {
stage.run(world); stage.run(world);
} }
fn run_criteria_yes(criterion: &mut Criterion) { pub fn run_criteria_yes(criterion: &mut Criterion) {
let mut world = World::new(); let mut world = World::new();
let mut group = criterion.benchmark_group("run_criteria/yes"); let mut group = criterion.benchmark_group("run_criteria/yes");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
@ -54,7 +43,7 @@ fn run_criteria_yes(criterion: &mut Criterion) {
group.finish(); group.finish();
} }
fn run_criteria_no(criterion: &mut Criterion) { pub fn run_criteria_no(criterion: &mut Criterion) {
let mut world = World::new(); let mut world = World::new();
let mut group = criterion.benchmark_group("run_criteria/no"); let mut group = criterion.benchmark_group("run_criteria/no");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
@ -85,7 +74,7 @@ fn run_criteria_no(criterion: &mut Criterion) {
group.finish(); group.finish();
} }
fn run_criteria_yes_with_labels(criterion: &mut Criterion) { pub fn run_criteria_yes_with_labels(criterion: &mut Criterion) {
let mut world = World::new(); let mut world = World::new();
let mut group = criterion.benchmark_group("run_criteria/yes_with_labels"); let mut group = criterion.benchmark_group("run_criteria/yes_with_labels");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
@ -116,7 +105,7 @@ fn run_criteria_yes_with_labels(criterion: &mut Criterion) {
group.finish(); group.finish();
} }
fn run_criteria_no_with_labels(criterion: &mut Criterion) { pub fn run_criteria_no_with_labels(criterion: &mut Criterion) {
let mut world = World::new(); let mut world = World::new();
let mut group = criterion.benchmark_group("run_criteria/no_with_labels"); let mut group = criterion.benchmark_group("run_criteria/no_with_labels");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
@ -150,7 +139,7 @@ fn run_criteria_no_with_labels(criterion: &mut Criterion) {
#[derive(Component)] #[derive(Component)]
struct TestBool(pub bool); struct TestBool(pub bool);
fn run_criteria_yes_with_query(criterion: &mut Criterion) { pub fn run_criteria_yes_with_query(criterion: &mut Criterion) {
let mut world = World::new(); let mut world = World::new();
world.spawn().insert(TestBool(true)); world.spawn().insert(TestBool(true));
let mut group = criterion.benchmark_group("run_criteria/yes_using_query"); let mut group = criterion.benchmark_group("run_criteria/yes_using_query");
@ -187,7 +176,7 @@ fn run_criteria_yes_with_query(criterion: &mut Criterion) {
group.finish(); group.finish();
} }
fn run_criteria_yes_with_resource(criterion: &mut Criterion) { pub fn run_criteria_yes_with_resource(criterion: &mut Criterion) {
let mut world = World::new(); let mut world = World::new();
world.insert_resource(TestBool(true)); world.insert_resource(TestBool(true));
let mut group = criterion.benchmark_group("run_criteria/yes_using_resource"); let mut group = criterion.benchmark_group("run_criteria/yes_using_resource");

View File

@ -1,11 +1,63 @@
use bevy_app::App; use bevy_app::App;
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
use criterion::{criterion_group, criterion_main, Criterion}; use criterion::Criterion;
criterion_group!(benches, build_schedule); pub fn schedule(c: &mut Criterion) {
criterion_main!(benches); #[derive(Component)]
struct A(f32);
#[derive(Component)]
struct B(f32);
#[derive(Component)]
struct C(f32);
#[derive(Component)]
struct D(f32);
#[derive(Component)]
struct E(f32);
fn build_schedule(criterion: &mut Criterion) { fn ab(mut query: Query<(&mut A, &mut B)>) {
query.for_each_mut(|(mut a, mut b)| {
std::mem::swap(&mut a.0, &mut b.0);
});
}
fn cd(mut query: Query<(&mut C, &mut D)>) {
query.for_each_mut(|(mut c, mut d)| {
std::mem::swap(&mut c.0, &mut d.0);
});
}
fn ce(mut query: Query<(&mut C, &mut E)>) {
query.for_each_mut(|(mut c, mut e)| {
std::mem::swap(&mut c.0, &mut e.0);
});
}
let mut group = c.benchmark_group("schedule");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("base", |b| {
let mut world = World::default();
world.spawn_batch((0..10000).map(|_| (A(0.0), B(0.0))));
world.spawn_batch((0..10000).map(|_| (A(0.0), B(0.0), C(0.0))));
world.spawn_batch((0..10000).map(|_| (A(0.0), B(0.0), C(0.0), D(0.0))));
world.spawn_batch((0..10000).map(|_| (A(0.0), B(0.0), C(0.0), E(0.0))));
let mut stage = SystemStage::parallel();
stage.add_system(ab);
stage.add_system(cd);
stage.add_system(ce);
stage.run(&mut world);
b.iter(move || stage.run(&mut world));
});
group.finish();
}
pub fn build_schedule(criterion: &mut Criterion) {
// empty system // empty system
fn empty_system() {} fn empty_system() {}

View File

@ -4,10 +4,7 @@ use bevy_ecs::{
system::Query, system::Query,
world::World, world::World,
}; };
use criterion::{criterion_group, criterion_main, Criterion}; use criterion::Criterion;
criterion_group!(benches, empty_systems, busy_systems, contrived);
criterion_main!(benches);
fn run_stage(stage: &mut SystemStage, world: &mut World) { fn run_stage(stage: &mut SystemStage, world: &mut World) {
stage.run(world); stage.run(world);
@ -26,7 +23,7 @@ struct E(f32);
const ENTITY_BUNCH: usize = 5000; const ENTITY_BUNCH: usize = 5000;
fn empty_systems(criterion: &mut Criterion) { pub fn empty_systems(criterion: &mut Criterion) {
let mut world = World::new(); let mut world = World::new();
let mut group = criterion.benchmark_group("empty_systems"); let mut group = criterion.benchmark_group("empty_systems");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
@ -64,7 +61,7 @@ fn empty_systems(criterion: &mut Criterion) {
group.finish() group.finish()
} }
fn busy_systems(criterion: &mut Criterion) { pub fn busy_systems(criterion: &mut Criterion) {
fn ab(mut q: Query<(&mut A, &mut B)>) { fn ab(mut q: Query<(&mut A, &mut B)>) {
q.for_each_mut(|(mut a, mut b)| { q.for_each_mut(|(mut a, mut b)| {
std::mem::swap(&mut a.0, &mut b.0); std::mem::swap(&mut a.0, &mut b.0);
@ -113,7 +110,7 @@ fn busy_systems(criterion: &mut Criterion) {
group.finish() group.finish()
} }
fn contrived(criterion: &mut Criterion) { pub fn contrived(criterion: &mut Criterion) {
fn s_0(mut q_0: Query<(&mut A, &mut B)>) { fn s_0(mut q_0: Query<(&mut A, &mut B)>) {
q_0.for_each_mut(|(mut c_0, mut c_1)| { q_0.for_each_mut(|(mut c_0, mut c_1)| {
std::mem::swap(&mut c_0.0, &mut c_1.0); std::mem::swap(&mut c_0.0, &mut c_1.0);

View File

@ -4,20 +4,7 @@ use bevy_ecs::{
system::{Command, CommandQueue, Commands}, system::{Command, CommandQueue, Commands},
world::World, world::World,
}; };
use criterion::{black_box, criterion_group, criterion_main, Criterion}; use criterion::{black_box, Criterion};
criterion_group!(
benches,
empty_commands,
spawn_commands,
insert_commands,
fake_commands,
zero_sized_commands,
medium_sized_commands,
large_sized_commands,
get_or_spawn
);
criterion_main!(benches);
#[derive(Component)] #[derive(Component)]
struct A; struct A;
@ -26,7 +13,7 @@ struct B;
#[derive(Component)] #[derive(Component)]
struct C; struct C;
fn empty_commands(criterion: &mut Criterion) { pub fn empty_commands(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("empty_commands"); let mut group = criterion.benchmark_group("empty_commands");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4)); group.measurement_time(std::time::Duration::from_secs(4));
@ -43,7 +30,7 @@ fn empty_commands(criterion: &mut Criterion) {
group.finish(); group.finish();
} }
fn spawn_commands(criterion: &mut Criterion) { pub fn spawn_commands(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("spawn_commands"); let mut group = criterion.benchmark_group("spawn_commands");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4)); group.measurement_time(std::time::Duration::from_secs(4));
@ -89,7 +76,7 @@ struct Matrix([[f32; 4]; 4]);
#[derive(Default, Component)] #[derive(Default, Component)]
struct Vec3([f32; 3]); struct Vec3([f32; 3]);
fn insert_commands(criterion: &mut Criterion) { pub fn insert_commands(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("insert_commands"); let mut group = criterion.benchmark_group("insert_commands");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4)); group.measurement_time(std::time::Duration::from_secs(4));
@ -154,7 +141,7 @@ impl Command for FakeCommandB {
} }
} }
fn fake_commands(criterion: &mut Criterion) { pub fn fake_commands(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("fake_commands"); let mut group = criterion.benchmark_group("fake_commands");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4)); group.measurement_time(std::time::Duration::from_secs(4));
@ -200,7 +187,7 @@ impl Default for LargeStruct {
} }
} }
fn sized_commands_impl<T: Default + Command>(criterion: &mut Criterion) { pub fn sized_commands_impl<T: Default + Command>(criterion: &mut Criterion) {
let mut group = let mut group =
criterion.benchmark_group(format!("sized_commands_{}_bytes", std::mem::size_of::<T>())); criterion.benchmark_group(format!("sized_commands_{}_bytes", std::mem::size_of::<T>()));
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
@ -225,19 +212,19 @@ fn sized_commands_impl<T: Default + Command>(criterion: &mut Criterion) {
group.finish(); group.finish();
} }
fn zero_sized_commands(criterion: &mut Criterion) { pub fn zero_sized_commands(criterion: &mut Criterion) {
sized_commands_impl::<SizedCommand<()>>(criterion); sized_commands_impl::<SizedCommand<()>>(criterion);
} }
fn medium_sized_commands(criterion: &mut Criterion) { pub fn medium_sized_commands(criterion: &mut Criterion) {
sized_commands_impl::<SizedCommand<(u32, u32, u32)>>(criterion); sized_commands_impl::<SizedCommand<(u32, u32, u32)>>(criterion);
} }
fn large_sized_commands(criterion: &mut Criterion) { pub fn large_sized_commands(criterion: &mut Criterion) {
sized_commands_impl::<SizedCommand<LargeStruct>>(criterion); sized_commands_impl::<SizedCommand<LargeStruct>>(criterion);
} }
fn get_or_spawn(criterion: &mut Criterion) { pub fn get_or_spawn(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("get_or_spawn"); let mut group = criterion.benchmark_group("get_or_spawn");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4)); group.measurement_time(std::time::Duration::from_secs(4));

View File

@ -0,0 +1,27 @@
use criterion::criterion_group;
mod commands;
mod world_get;
use commands::*;
use world_get::*;
criterion_group!(
world_benches,
empty_commands,
spawn_commands,
insert_commands,
fake_commands,
zero_sized_commands,
medium_sized_commands,
large_sized_commands,
get_or_spawn,
world_entity,
world_get,
world_query_get,
world_query_iter,
world_query_for_each,
query_get_component_simple,
query_get_component,
query_get,
);

View File

@ -1,26 +1,15 @@
use bevy_ecs::{ use bevy_ecs::{
bundle::Bundle,
component::Component, component::Component,
entity::Entity, entity::Entity,
prelude::*,
system::{Query, SystemState}, system::{Query, SystemState},
bundle::Bundle,
world::World, world::World,
}; };
use criterion::{black_box, criterion_group, criterion_main, Criterion}; use criterion::{black_box, Criterion};
use rand::{prelude::SliceRandom, SeedableRng}; use rand::{prelude::SliceRandom, SeedableRng};
use rand_chacha::ChaCha8Rng; use rand_chacha::ChaCha8Rng;
criterion_group!(
benches,
world_entity,
world_get,
world_query_get,
world_query_iter,
world_query_for_each,
query_get_component,
query_get,
);
criterion_main!(benches);
#[derive(Component, Default)] #[derive(Component, Default)]
#[component(storage = "Table")] #[component(storage = "Table")]
struct Table(f32); struct Table(f32);
@ -52,7 +41,7 @@ fn setup_wide<T: Bundle + Default>(entity_count: u32) -> World {
black_box(world) black_box(world)
} }
fn world_entity(criterion: &mut Criterion) { pub fn world_entity(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("world_entity"); let mut group = criterion.benchmark_group("world_entity");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4)); group.measurement_time(std::time::Duration::from_secs(4));
@ -73,7 +62,7 @@ fn world_entity(criterion: &mut Criterion) {
group.finish(); group.finish();
} }
fn world_get(criterion: &mut Criterion) { pub fn world_get(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("world_get"); let mut group = criterion.benchmark_group("world_get");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4)); group.measurement_time(std::time::Duration::from_secs(4));
@ -104,7 +93,7 @@ fn world_get(criterion: &mut Criterion) {
group.finish(); group.finish();
} }
fn world_query_get(criterion: &mut Criterion) { pub fn world_query_get(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("world_query_get"); let mut group = criterion.benchmark_group("world_query_get");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4)); group.measurement_time(std::time::Duration::from_secs(4));
@ -157,37 +146,40 @@ fn world_query_get(criterion: &mut Criterion) {
} }
}); });
}); });
group.bench_function(format!("{}_entities_sparse_wide", entity_count), |bencher| { group.bench_function(
let mut world = setup_wide::<( format!("{}_entities_sparse_wide", entity_count),
WideSparse<0>, |bencher| {
WideSparse<1>, let mut world = setup_wide::<(
WideSparse<2>, WideSparse<0>,
WideSparse<3>, WideSparse<1>,
WideSparse<4>, WideSparse<2>,
WideSparse<5>, WideSparse<3>,
)>(entity_count); WideSparse<4>,
let mut query = world.query::<( WideSparse<5>,
&WideSparse<0>, )>(entity_count);
&WideSparse<1>, let mut query = world.query::<(
&WideSparse<2>, &WideSparse<0>,
&WideSparse<3>, &WideSparse<1>,
&WideSparse<4>, &WideSparse<2>,
&WideSparse<5>, &WideSparse<3>,
)>(); &WideSparse<4>,
&WideSparse<5>,
)>();
bencher.iter(|| { bencher.iter(|| {
for i in 0..entity_count { for i in 0..entity_count {
let entity = Entity::from_raw(i); let entity = Entity::from_raw(i);
assert!(query.get(&world, entity).is_ok()); assert!(query.get(&world, entity).is_ok());
} }
}); });
}); },
);
} }
group.finish(); group.finish();
} }
fn world_query_iter(criterion: &mut Criterion) { pub fn world_query_iter(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("world_query_iter"); let mut group = criterion.benchmark_group("world_query_iter");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4)); group.measurement_time(std::time::Duration::from_secs(4));
@ -226,7 +218,7 @@ fn world_query_iter(criterion: &mut Criterion) {
group.finish(); group.finish();
} }
fn world_query_for_each(criterion: &mut Criterion) { pub fn world_query_for_each(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("world_query_for_each"); let mut group = criterion.benchmark_group("world_query_for_each");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4)); group.measurement_time(std::time::Duration::from_secs(4));
@ -265,7 +257,49 @@ fn world_query_for_each(criterion: &mut Criterion) {
group.finish(); group.finish();
} }
fn query_get_component(criterion: &mut Criterion) { pub fn query_get_component_simple(criterion: &mut Criterion) {
#[derive(Component)]
struct A(f32);
let mut group = criterion.benchmark_group("query_get_component_simple");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));
group.bench_function("unchecked", |bencher| {
let mut world = World::new();
let entity = world.spawn().insert(A(0.0)).id();
let mut query = world.query::<&mut A>();
bencher.iter(|| {
for _x in 0..100000 {
let mut a = unsafe { query.get_unchecked(&mut world, entity).unwrap() };
a.0 += 1.0;
}
});
});
group.bench_function("system", |bencher| {
let mut world = World::new();
let entity = world.spawn().insert(A(0.0)).id();
fn query_system(In(entity): In<Entity>, mut query: Query<&mut A>) {
for _ in 0..100_000 {
let mut a = query.get_mut(entity).unwrap();
a.0 += 1.0;
}
}
let mut system = IntoSystem::into_system(query_system);
system.initialize(&mut world);
system.update_archetype_component_access(&world);
bencher.iter(|| system.run(entity, &mut world));
});
group.finish();
}
pub fn query_get_component(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("query_get_component"); let mut group = criterion.benchmark_group("query_get_component");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4)); group.measurement_time(std::time::Duration::from_secs(4));
@ -320,7 +354,7 @@ fn query_get_component(criterion: &mut Criterion) {
group.finish(); group.finish();
} }
fn query_get(criterion: &mut Criterion) { pub fn query_get(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("query_get"); let mut group = criterion.benchmark_group("query_get");
group.warm_up_time(std::time::Duration::from_millis(500)); group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4)); group.measurement_time(std::time::Duration::from_secs(4));