Wider ECS Benchmarks (#5123)
# Objective As a part of evaluating #4800, at the behest of @cart, it was noted that the ECS microbenchmarks all focus on singular component queries, whereas in reality most systems will have wider queries with multiple components in each. ## Solution Use const generics to add wider variants of existing benchmarks.
This commit is contained in:
parent
6e50b249a4
commit
ba3d8bedc5
@ -0,0 +1,70 @@
|
|||||||
|
use bevy_ecs::prelude::*;
|
||||||
|
|
||||||
|
macro_rules! create_entities {
|
||||||
|
($world:ident; $( $variants:ident ),*) => {
|
||||||
|
$(
|
||||||
|
#[derive(Component)]
|
||||||
|
struct $variants(f32);
|
||||||
|
for _ in 0..20 {
|
||||||
|
$world.spawn().insert_bundle((
|
||||||
|
$variants(0.0),
|
||||||
|
Data::<0>(1.0),
|
||||||
|
Data::<1>(1.0),
|
||||||
|
Data::<2>(1.0),
|
||||||
|
Data::<3>(1.0),
|
||||||
|
Data::<4>(1.0),
|
||||||
|
Data::<5>(1.0),
|
||||||
|
Data::<6>(1.0),
|
||||||
|
Data::<7>(1.0),
|
||||||
|
Data::<8>(1.0),
|
||||||
|
Data::<9>(1.0),
|
||||||
|
Data::<10>(1.0),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct Data<const X: usize>(f32);
|
||||||
|
|
||||||
|
pub struct Benchmark<'w>(World, QueryState<(
|
||||||
|
&'w mut Data<0>,
|
||||||
|
&'w mut Data<1>,
|
||||||
|
&'w mut Data<2>,
|
||||||
|
&'w mut Data<3>,
|
||||||
|
&'w mut Data<4>,
|
||||||
|
&'w mut Data<5>,
|
||||||
|
&'w mut Data<6>,
|
||||||
|
&'w mut Data<7>,
|
||||||
|
&'w mut Data<8>,
|
||||||
|
&'w mut Data<9>,
|
||||||
|
&'w mut Data<10>,
|
||||||
|
)>);
|
||||||
|
|
||||||
|
impl<'w> Benchmark<'w> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut world = World::new();
|
||||||
|
|
||||||
|
create_entities!(world; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);
|
||||||
|
|
||||||
|
let query = world.query();
|
||||||
|
Self(world, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
self.1.for_each_mut(&mut self.0, |mut data| {
|
||||||
|
data.0.0 *= 2.0;
|
||||||
|
data.1.0 *= 2.0;
|
||||||
|
data.2.0 *= 2.0;
|
||||||
|
data.3.0 *= 2.0;
|
||||||
|
data.4.0 *= 2.0;
|
||||||
|
data.5.0 *= 2.0;
|
||||||
|
data.6.0 *= 2.0;
|
||||||
|
data.7.0 *= 2.0;
|
||||||
|
data.8.0 *= 2.0;
|
||||||
|
data.9.0 *= 2.0;
|
||||||
|
data.10.0 *= 2.0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
70
benches/benches/bevy_ecs/ecs_bench_suite/frag_iter_wide.rs
Normal file
70
benches/benches/bevy_ecs/ecs_bench_suite/frag_iter_wide.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
use bevy_ecs::prelude::*;
|
||||||
|
|
||||||
|
macro_rules! create_entities {
|
||||||
|
($world:ident; $( $variants:ident ),*) => {
|
||||||
|
$(
|
||||||
|
#[derive(Component)]
|
||||||
|
struct $variants(f32);
|
||||||
|
for _ in 0..20 {
|
||||||
|
$world.spawn().insert_bundle((
|
||||||
|
$variants(0.0),
|
||||||
|
Data::<0>(1.0),
|
||||||
|
Data::<1>(1.0),
|
||||||
|
Data::<2>(1.0),
|
||||||
|
Data::<3>(1.0),
|
||||||
|
Data::<4>(1.0),
|
||||||
|
Data::<5>(1.0),
|
||||||
|
Data::<6>(1.0),
|
||||||
|
Data::<7>(1.0),
|
||||||
|
Data::<8>(1.0),
|
||||||
|
Data::<9>(1.0),
|
||||||
|
Data::<10>(1.0),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct Data<const X: usize>(f32);
|
||||||
|
|
||||||
|
pub struct Benchmark<'w>(World, QueryState<(
|
||||||
|
&'w mut Data<0>,
|
||||||
|
&'w mut Data<1>,
|
||||||
|
&'w mut Data<2>,
|
||||||
|
&'w mut Data<3>,
|
||||||
|
&'w mut Data<4>,
|
||||||
|
&'w mut Data<5>,
|
||||||
|
&'w mut Data<6>,
|
||||||
|
&'w mut Data<7>,
|
||||||
|
&'w mut Data<8>,
|
||||||
|
&'w mut Data<9>,
|
||||||
|
&'w mut Data<10>,
|
||||||
|
)>);
|
||||||
|
|
||||||
|
impl<'w> Benchmark<'w> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut world = World::new();
|
||||||
|
|
||||||
|
create_entities!(world; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);
|
||||||
|
|
||||||
|
let query = world.query();
|
||||||
|
Self(world, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
for mut data in self.1.iter_mut(&mut self.0) {
|
||||||
|
data.0.0 *= 2.0;
|
||||||
|
data.1.0 *= 2.0;
|
||||||
|
data.2.0 *= 2.0;
|
||||||
|
data.3.0 *= 2.0;
|
||||||
|
data.4.0 *= 2.0;
|
||||||
|
data.5.0 *= 2.0;
|
||||||
|
data.6.0 *= 2.0;
|
||||||
|
data.7.0 *= 2.0;
|
||||||
|
data.8.0 *= 2.0;
|
||||||
|
data.9.0 *= 2.0;
|
||||||
|
data.10.0 *= 2.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,9 @@ mod add_remove_big_table;
|
|||||||
mod add_remove_sparse_set;
|
mod add_remove_sparse_set;
|
||||||
mod add_remove_table;
|
mod add_remove_table;
|
||||||
mod frag_iter;
|
mod frag_iter;
|
||||||
|
mod frag_iter_wide;
|
||||||
mod frag_iter_foreach;
|
mod frag_iter_foreach;
|
||||||
|
mod frag_iter_foreach_wide;
|
||||||
mod get_component;
|
mod get_component;
|
||||||
mod get_component_system;
|
mod get_component_system;
|
||||||
mod heavy_compute;
|
mod heavy_compute;
|
||||||
@ -13,12 +15,18 @@ mod schedule;
|
|||||||
mod simple_insert;
|
mod simple_insert;
|
||||||
mod simple_insert_unbatched;
|
mod simple_insert_unbatched;
|
||||||
mod simple_iter;
|
mod simple_iter;
|
||||||
|
mod simple_iter_wide;
|
||||||
mod simple_iter_foreach;
|
mod simple_iter_foreach;
|
||||||
|
mod simple_iter_foreach_wide;
|
||||||
mod simple_iter_sparse;
|
mod simple_iter_sparse;
|
||||||
|
mod simple_iter_sparse_wide;
|
||||||
mod simple_iter_sparse_foreach;
|
mod simple_iter_sparse_foreach;
|
||||||
|
mod simple_iter_sparse_foreach_wide;
|
||||||
mod simple_iter_system;
|
mod simple_iter_system;
|
||||||
mod sparse_frag_iter;
|
mod sparse_frag_iter;
|
||||||
|
mod sparse_frag_iter_wide;
|
||||||
mod sparse_frag_iter_foreach;
|
mod sparse_frag_iter_foreach;
|
||||||
|
mod sparse_frag_iter_foreach_wide;
|
||||||
|
|
||||||
fn bench_simple_insert(c: &mut Criterion) {
|
fn bench_simple_insert(c: &mut Criterion) {
|
||||||
let mut group = c.benchmark_group("simple_insert");
|
let mut group = c.benchmark_group("simple_insert");
|
||||||
@ -43,6 +51,10 @@ fn bench_simple_iter(c: &mut Criterion) {
|
|||||||
let mut bench = simple_iter::Benchmark::new();
|
let mut bench = simple_iter::Benchmark::new();
|
||||||
b.iter(move || bench.run());
|
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| {
|
group.bench_function("system", |b| {
|
||||||
let mut bench = simple_iter_system::Benchmark::new();
|
let mut bench = simple_iter_system::Benchmark::new();
|
||||||
b.iter(move || bench.run());
|
b.iter(move || bench.run());
|
||||||
@ -51,14 +63,26 @@ fn bench_simple_iter(c: &mut Criterion) {
|
|||||||
let mut bench = simple_iter_sparse::Benchmark::new();
|
let mut bench = simple_iter_sparse::Benchmark::new();
|
||||||
b.iter(move || bench.run());
|
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| {
|
group.bench_function("foreach", |b| {
|
||||||
let mut bench = simple_iter_foreach::Benchmark::new();
|
let mut bench = simple_iter_foreach::Benchmark::new();
|
||||||
b.iter(move || bench.run());
|
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| {
|
group.bench_function("sparse_foreach", |b| {
|
||||||
let mut bench = simple_iter_sparse_foreach::Benchmark::new();
|
let mut bench = simple_iter_sparse_foreach::Benchmark::new();
|
||||||
b.iter(move || bench.run());
|
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();
|
group.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,10 +94,18 @@ fn bench_frag_iter_bc(c: &mut Criterion) {
|
|||||||
let mut bench = frag_iter::Benchmark::new();
|
let mut bench = frag_iter::Benchmark::new();
|
||||||
b.iter(move || bench.run());
|
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| {
|
group.bench_function("foreach", |b| {
|
||||||
let mut bench = frag_iter_foreach::Benchmark::new();
|
let mut bench = frag_iter_foreach::Benchmark::new();
|
||||||
b.iter(move || bench.run());
|
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();
|
group.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,10 +117,18 @@ fn bench_sparse_frag_iter(c: &mut Criterion) {
|
|||||||
let mut bench = sparse_frag_iter::Benchmark::new();
|
let mut bench = sparse_frag_iter::Benchmark::new();
|
||||||
b.iter(move || bench.run());
|
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| {
|
group.bench_function("foreach", |b| {
|
||||||
let mut bench = sparse_frag_iter_foreach::Benchmark::new();
|
let mut bench = sparse_frag_iter_foreach::Benchmark::new();
|
||||||
b.iter(move || bench.run());
|
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();
|
group.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
use bevy_ecs::prelude::*;
|
||||||
|
use glam::*;
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
struct Transform(Mat4);
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
struct Position<const X: usize>(Vec3);
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
struct Rotation(Vec3);
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
struct Velocity<const X: usize>(Vec3);
|
||||||
|
|
||||||
|
pub struct Benchmark<'w>(World, QueryState<(
|
||||||
|
&'w Velocity<0>,
|
||||||
|
&'w mut Position<0>,
|
||||||
|
&'w Velocity<1>,
|
||||||
|
&'w mut Position<1>,
|
||||||
|
&'w Velocity<2>,
|
||||||
|
&'w mut Position<2>,
|
||||||
|
&'w Velocity<3>,
|
||||||
|
&'w mut Position<3>,
|
||||||
|
&'w Velocity<4>,
|
||||||
|
&'w mut Position<4>,
|
||||||
|
)>);
|
||||||
|
|
||||||
|
impl<'w> Benchmark<'w> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut world = World::new();
|
||||||
|
|
||||||
|
// TODO: batch this
|
||||||
|
for _ in 0..10_000 {
|
||||||
|
world.spawn().insert_bundle((
|
||||||
|
Transform(Mat4::from_scale(Vec3::ONE)),
|
||||||
|
Rotation(Vec3::X),
|
||||||
|
Position::<0>(Vec3::X),
|
||||||
|
Velocity::<0>(Vec3::X),
|
||||||
|
Position::<1>(Vec3::X),
|
||||||
|
Velocity::<1>(Vec3::X),
|
||||||
|
Position::<2>(Vec3::X),
|
||||||
|
Velocity::<2>(Vec3::X),
|
||||||
|
Position::<3>(Vec3::X),
|
||||||
|
Velocity::<3>(Vec3::X),
|
||||||
|
Position::<4>(Vec3::X),
|
||||||
|
Velocity::<4>(Vec3::X),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let query = world.query();
|
||||||
|
Self(world, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
self.1.for_each_mut(&mut self.0, |mut item| {
|
||||||
|
item.1.0 += item.0.0;
|
||||||
|
item.3.0 += item.2.0;
|
||||||
|
item.5.0 += item.4.0;
|
||||||
|
item.7.0 += item.6.0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
use bevy_ecs::prelude::*;
|
||||||
|
use glam::*;
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
struct Transform(Mat4);
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
#[component(storage = "SparseSet")]
|
||||||
|
struct Position<const X: usize>(Vec3);
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
struct Rotation(Vec3);
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
#[component(storage = "SparseSet")]
|
||||||
|
struct Velocity<const X: usize>(Vec3);
|
||||||
|
|
||||||
|
pub struct Benchmark<'w>(World, QueryState<(
|
||||||
|
&'w Velocity<0>,
|
||||||
|
&'w mut Position<0>,
|
||||||
|
&'w Velocity<1>,
|
||||||
|
&'w mut Position<1>,
|
||||||
|
&'w Velocity<2>,
|
||||||
|
&'w mut Position<2>,
|
||||||
|
&'w Velocity<3>,
|
||||||
|
&'w mut Position<3>,
|
||||||
|
&'w Velocity<4>,
|
||||||
|
&'w mut Position<4>,
|
||||||
|
)>);
|
||||||
|
|
||||||
|
impl<'w> Benchmark<'w> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut world = World::new();
|
||||||
|
|
||||||
|
// TODO: batch this
|
||||||
|
for _ in 0..10_000 {
|
||||||
|
world.spawn().insert_bundle((
|
||||||
|
Transform(Mat4::from_scale(Vec3::ONE)),
|
||||||
|
Rotation(Vec3::X),
|
||||||
|
Position::<0>(Vec3::X),
|
||||||
|
Velocity::<0>(Vec3::X),
|
||||||
|
Position::<1>(Vec3::X),
|
||||||
|
Velocity::<1>(Vec3::X),
|
||||||
|
Position::<2>(Vec3::X),
|
||||||
|
Velocity::<2>(Vec3::X),
|
||||||
|
Position::<3>(Vec3::X),
|
||||||
|
Velocity::<3>(Vec3::X),
|
||||||
|
Position::<4>(Vec3::X),
|
||||||
|
Velocity::<4>(Vec3::X),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let query = world.query();
|
||||||
|
Self(world, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
self.1.for_each_mut(&mut self.0, |mut item| {
|
||||||
|
item.1.0 += item.0.0;
|
||||||
|
item.3.0 += item.2.0;
|
||||||
|
item.5.0 += item.4.0;
|
||||||
|
item.7.0 += item.6.0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
use bevy_ecs::prelude::*;
|
||||||
|
use glam::*;
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
struct Transform(Mat4);
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
#[component(storage = "SparseSet")]
|
||||||
|
struct Position<const X: usize>(Vec3);
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
struct Rotation(Vec3);
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
#[component(storage = "SparseSet")]
|
||||||
|
struct Velocity<const X: usize>(Vec3);
|
||||||
|
|
||||||
|
pub struct Benchmark<'w>(World, QueryState<(
|
||||||
|
&'w Velocity<0>,
|
||||||
|
&'w mut Position<0>,
|
||||||
|
&'w Velocity<1>,
|
||||||
|
&'w mut Position<1>,
|
||||||
|
&'w Velocity<2>,
|
||||||
|
&'w mut Position<2>,
|
||||||
|
&'w Velocity<3>,
|
||||||
|
&'w mut Position<3>,
|
||||||
|
&'w Velocity<4>,
|
||||||
|
&'w mut Position<4>,
|
||||||
|
)>);
|
||||||
|
|
||||||
|
impl<'w> Benchmark<'w> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut world = World::new();
|
||||||
|
|
||||||
|
// TODO: batch this
|
||||||
|
for _ in 0..10_000 {
|
||||||
|
world.spawn().insert_bundle((
|
||||||
|
Transform(Mat4::from_scale(Vec3::ONE)),
|
||||||
|
Rotation(Vec3::X),
|
||||||
|
Position::<0>(Vec3::X),
|
||||||
|
Velocity::<0>(Vec3::X),
|
||||||
|
Position::<1>(Vec3::X),
|
||||||
|
Velocity::<1>(Vec3::X),
|
||||||
|
Position::<2>(Vec3::X),
|
||||||
|
Velocity::<2>(Vec3::X),
|
||||||
|
Position::<3>(Vec3::X),
|
||||||
|
Velocity::<3>(Vec3::X),
|
||||||
|
Position::<4>(Vec3::X),
|
||||||
|
Velocity::<4>(Vec3::X),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let query = world.query();
|
||||||
|
Self(world, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
for mut item in self.1.iter_mut(&mut self.0) {
|
||||||
|
item.1.0 += item.0.0;
|
||||||
|
item.3.0 += item.2.0;
|
||||||
|
item.5.0 += item.4.0;
|
||||||
|
item.7.0 += item.6.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
benches/benches/bevy_ecs/ecs_bench_suite/simple_iter_wide.rs
Normal file
63
benches/benches/bevy_ecs/ecs_bench_suite/simple_iter_wide.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
use bevy_ecs::prelude::*;
|
||||||
|
use glam::*;
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
struct Transform(Mat4);
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
struct Position<const X: usize>(Vec3);
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
struct Rotation(Vec3);
|
||||||
|
|
||||||
|
#[derive(Component, Copy, Clone)]
|
||||||
|
struct Velocity<const X: usize>(Vec3);
|
||||||
|
|
||||||
|
pub struct Benchmark<'w>(World, QueryState<(
|
||||||
|
&'w Velocity<0>,
|
||||||
|
&'w mut Position<0>,
|
||||||
|
&'w Velocity<1>,
|
||||||
|
&'w mut Position<1>,
|
||||||
|
&'w Velocity<2>,
|
||||||
|
&'w mut Position<2>,
|
||||||
|
&'w Velocity<3>,
|
||||||
|
&'w mut Position<3>,
|
||||||
|
&'w Velocity<4>,
|
||||||
|
&'w mut Position<4>,
|
||||||
|
)>);
|
||||||
|
|
||||||
|
impl<'w> Benchmark<'w> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut world = World::new();
|
||||||
|
|
||||||
|
// TODO: batch this
|
||||||
|
for _ in 0..10_000 {
|
||||||
|
world.spawn().insert_bundle((
|
||||||
|
Transform(Mat4::from_scale(Vec3::ONE)),
|
||||||
|
Rotation(Vec3::X),
|
||||||
|
Position::<0>(Vec3::X),
|
||||||
|
Velocity::<0>(Vec3::X),
|
||||||
|
Position::<1>(Vec3::X),
|
||||||
|
Velocity::<1>(Vec3::X),
|
||||||
|
Position::<2>(Vec3::X),
|
||||||
|
Velocity::<2>(Vec3::X),
|
||||||
|
Position::<3>(Vec3::X),
|
||||||
|
Velocity::<3>(Vec3::X),
|
||||||
|
Position::<4>(Vec3::X),
|
||||||
|
Velocity::<4>(Vec3::X),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let query = world.query();
|
||||||
|
Self(world, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
for mut item in self.1.iter_mut(&mut self.0) {
|
||||||
|
item.1.0 += item.0.0;
|
||||||
|
item.3.0 += item.2.0;
|
||||||
|
item.5.0 += item.4.0;
|
||||||
|
item.7.0 += item.6.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
use bevy_ecs::prelude::*;
|
||||||
|
|
||||||
|
macro_rules! create_entities {
|
||||||
|
($world:ident; $( $variants:ident ),*) => {
|
||||||
|
$(
|
||||||
|
#[derive(Component)]
|
||||||
|
struct $variants(f32);
|
||||||
|
for _ in 0..5 {
|
||||||
|
$world.spawn().insert($variants(0.0));
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct Data<const X: usize>(f32);
|
||||||
|
|
||||||
|
pub struct Benchmark<'w>(World, QueryState<(
|
||||||
|
&'w mut Data<0>,
|
||||||
|
&'w mut Data<1>,
|
||||||
|
&'w mut Data<2>,
|
||||||
|
&'w mut Data<3>,
|
||||||
|
&'w mut Data<4>,
|
||||||
|
&'w mut Data<5>,
|
||||||
|
&'w mut Data<6>,
|
||||||
|
&'w mut Data<7>,
|
||||||
|
&'w mut Data<8>,
|
||||||
|
&'w mut Data<9>,
|
||||||
|
&'w mut Data<10>,
|
||||||
|
)>);
|
||||||
|
|
||||||
|
impl<'w> Benchmark<'w> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut world = World::new();
|
||||||
|
for _ in 0..5 {
|
||||||
|
world.spawn().insert_bundle((
|
||||||
|
Data::<0>(1.0),
|
||||||
|
Data::<1>(1.0),
|
||||||
|
Data::<2>(1.0),
|
||||||
|
Data::<3>(1.0),
|
||||||
|
Data::<4>(1.0),
|
||||||
|
Data::<5>(1.0),
|
||||||
|
Data::<6>(1.0),
|
||||||
|
Data::<7>(1.0),
|
||||||
|
Data::<8>(1.0),
|
||||||
|
Data::<9>(1.0),
|
||||||
|
Data::<10>(1.0),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
create_entities!(world; C00, C01, C02, C03, C04, C05, C06, C07, C08, C09);
|
||||||
|
create_entities!(world; C10, C11, C12, C13, C14, C15, C16, C17, C18, C19);
|
||||||
|
create_entities!(world; C20, C21, C22, C23, C24, C25, C26, C27, C28, C29);
|
||||||
|
create_entities!(world; C30, C31, C32, C33, C34, C35, C36, C37, C38, C39);
|
||||||
|
create_entities!(world; C40, C41, C42, C43, C44, C45, C46, C47, C48, C49);
|
||||||
|
create_entities!(world; C50, C51, C52, C53, C54, C55, C56, C57, C58, C59);
|
||||||
|
create_entities!(world; C60, C61, C62, C63, C64, C65, C66, C67, C68, C69);
|
||||||
|
create_entities!(world; C70, C71, C72, C73, C74, C75, C76, C77, C78, C79);
|
||||||
|
create_entities!(world; C80, C81, C82, C83, C84, C85, C86, C87, C88, C89);
|
||||||
|
create_entities!(world; C90, C91, C92, C93, C94, C95, C96, C97, C98, C99);
|
||||||
|
let query = world.query();
|
||||||
|
Self(world, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
self.1.for_each_mut(&mut self.0, |mut data| {
|
||||||
|
data.0.0 *= 2.0;
|
||||||
|
data.1.0 *= 2.0;
|
||||||
|
data.2.0 *= 2.0;
|
||||||
|
data.3.0 *= 2.0;
|
||||||
|
data.4.0 *= 2.0;
|
||||||
|
data.5.0 *= 2.0;
|
||||||
|
data.6.0 *= 2.0;
|
||||||
|
data.7.0 *= 2.0;
|
||||||
|
data.8.0 *= 2.0;
|
||||||
|
data.9.0 *= 2.0;
|
||||||
|
data.10.0 *= 2.0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
use bevy_ecs::prelude::*;
|
||||||
|
|
||||||
|
macro_rules! create_entities {
|
||||||
|
($world:ident; $( $variants:ident ),*) => {
|
||||||
|
$(
|
||||||
|
#[derive(Component)]
|
||||||
|
struct $variants(f32);
|
||||||
|
for _ in 0..5 {
|
||||||
|
$world.spawn().insert($variants(0.0));
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#[derive(Component)]
|
||||||
|
struct Data<const X: usize>(f32);
|
||||||
|
|
||||||
|
pub struct Benchmark<'w>(World, QueryState<(
|
||||||
|
&'w mut Data<0>,
|
||||||
|
&'w mut Data<1>,
|
||||||
|
&'w mut Data<2>,
|
||||||
|
&'w mut Data<3>,
|
||||||
|
&'w mut Data<4>,
|
||||||
|
&'w mut Data<5>,
|
||||||
|
&'w mut Data<6>,
|
||||||
|
&'w mut Data<7>,
|
||||||
|
&'w mut Data<8>,
|
||||||
|
&'w mut Data<9>,
|
||||||
|
&'w mut Data<10>,
|
||||||
|
)>);
|
||||||
|
|
||||||
|
impl<'w> Benchmark<'w> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut world = World::new();
|
||||||
|
|
||||||
|
for _ in 0..5 {
|
||||||
|
world.spawn().insert_bundle((
|
||||||
|
Data::<0>(1.0),
|
||||||
|
Data::<1>(1.0),
|
||||||
|
Data::<2>(1.0),
|
||||||
|
Data::<3>(1.0),
|
||||||
|
Data::<4>(1.0),
|
||||||
|
Data::<5>(1.0),
|
||||||
|
Data::<6>(1.0),
|
||||||
|
Data::<7>(1.0),
|
||||||
|
Data::<8>(1.0),
|
||||||
|
Data::<9>(1.0),
|
||||||
|
Data::<10>(1.0),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
create_entities!(world; C00, C01, C02, C03, C04, C05, C06, C07, C08, C09);
|
||||||
|
create_entities!(world; C10, C11, C12, C13, C14, C15, C16, C17, C18, C19);
|
||||||
|
create_entities!(world; C20, C21, C22, C23, C24, C25, C26, C27, C28, C29);
|
||||||
|
create_entities!(world; C30, C31, C32, C33, C34, C35, C36, C37, C38, C39);
|
||||||
|
create_entities!(world; C40, C41, C42, C43, C44, C45, C46, C47, C48, C49);
|
||||||
|
create_entities!(world; C50, C51, C52, C53, C54, C55, C56, C57, C58, C59);
|
||||||
|
create_entities!(world; C60, C61, C62, C63, C64, C65, C66, C67, C68, C69);
|
||||||
|
create_entities!(world; C70, C71, C72, C73, C74, C75, C76, C77, C78, C79);
|
||||||
|
create_entities!(world; C80, C81, C82, C83, C84, C85, C86, C87, C88, C89);
|
||||||
|
create_entities!(world; C90, C91, C92, C93, C94, C95, C96, C97, C98, C99);
|
||||||
|
let query = world.query();
|
||||||
|
Self(world, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
for mut data in self.1.iter_mut(&mut self.0) {
|
||||||
|
data.0.0 *= 2.0;
|
||||||
|
data.1.0 *= 2.0;
|
||||||
|
data.2.0 *= 2.0;
|
||||||
|
data.3.0 *= 2.0;
|
||||||
|
data.4.0 *= 2.0;
|
||||||
|
data.5.0 *= 2.0;
|
||||||
|
data.6.0 *= 2.0;
|
||||||
|
data.7.0 *= 2.0;
|
||||||
|
data.8.0 *= 2.0;
|
||||||
|
data.9.0 *= 2.0;
|
||||||
|
data.10.0 *= 2.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ use bevy_ecs::{
|
|||||||
component::Component,
|
component::Component,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
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_group, criterion_main, Criterion};
|
||||||
@ -26,6 +27,12 @@ struct Table(f32);
|
|||||||
#[derive(Component, Default)]
|
#[derive(Component, Default)]
|
||||||
#[component(storage = "SparseSet")]
|
#[component(storage = "SparseSet")]
|
||||||
struct Sparse(f32);
|
struct Sparse(f32);
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
#[component(storage = "Table")]
|
||||||
|
struct WideTable<const X: usize>(f32);
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
#[component(storage = "SparseSet")]
|
||||||
|
struct WideSparse<const X: usize>(f32);
|
||||||
|
|
||||||
const RANGE: std::ops::Range<u32> = 5..6;
|
const RANGE: std::ops::Range<u32> = 5..6;
|
||||||
|
|
||||||
@ -39,6 +46,12 @@ fn setup<T: Component + Default>(entity_count: u32) -> World {
|
|||||||
black_box(world)
|
black_box(world)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn setup_wide<T: Bundle + Default>(entity_count: u32) -> World {
|
||||||
|
let mut world = World::default();
|
||||||
|
world.spawn_batch((0..entity_count).map(|_| T::default()));
|
||||||
|
black_box(world)
|
||||||
|
}
|
||||||
|
|
||||||
fn world_entity(criterion: &mut Criterion) {
|
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));
|
||||||
@ -108,10 +121,60 @@ fn world_query_get(criterion: &mut Criterion) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
group.bench_function(format!("{}_entities_table_wide", entity_count), |bencher| {
|
||||||
|
let mut world = setup_wide::<(
|
||||||
|
WideTable<0>,
|
||||||
|
WideTable<1>,
|
||||||
|
WideTable<2>,
|
||||||
|
WideTable<3>,
|
||||||
|
WideTable<4>,
|
||||||
|
WideTable<5>,
|
||||||
|
)>(entity_count);
|
||||||
|
let mut query = world.query::<(
|
||||||
|
&WideTable<0>,
|
||||||
|
&WideTable<1>,
|
||||||
|
&WideTable<2>,
|
||||||
|
&WideTable<3>,
|
||||||
|
&WideTable<4>,
|
||||||
|
&WideTable<5>,
|
||||||
|
)>();
|
||||||
|
|
||||||
|
bencher.iter(|| {
|
||||||
|
for i in 0..entity_count {
|
||||||
|
let entity = Entity::from_raw(i);
|
||||||
|
assert!(query.get(&world, entity).is_ok());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
|
group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
|
||||||
let mut world = setup::<Sparse>(entity_count);
|
let mut world = setup::<Sparse>(entity_count);
|
||||||
let mut query = world.query::<&Sparse>();
|
let mut query = world.query::<&Sparse>();
|
||||||
|
|
||||||
|
bencher.iter(|| {
|
||||||
|
for i in 0..entity_count {
|
||||||
|
let entity = Entity::from_raw(i);
|
||||||
|
assert!(query.get(&world, entity).is_ok());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
group.bench_function(format!("{}_entities_sparse_wide", entity_count), |bencher| {
|
||||||
|
let mut world = setup_wide::<(
|
||||||
|
WideSparse<0>,
|
||||||
|
WideSparse<1>,
|
||||||
|
WideSparse<2>,
|
||||||
|
WideSparse<3>,
|
||||||
|
WideSparse<4>,
|
||||||
|
WideSparse<5>,
|
||||||
|
)>(entity_count);
|
||||||
|
let mut query = world.query::<(
|
||||||
|
&WideSparse<0>,
|
||||||
|
&WideSparse<1>,
|
||||||
|
&WideSparse<2>,
|
||||||
|
&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);
|
||||||
|
Loading…
Reference in New Issue
Block a user