Skip to content

Commit

Permalink
Wider ECS Benchmarks (bevyengine#5123)
Browse files Browse the repository at this point in the history
# Objective
As a part of evaluating bevyengine#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.
  • Loading branch information
james7132 authored and ItsDoot committed Feb 1, 2023
1 parent 44350bf commit acb65c0
Show file tree
Hide file tree
Showing 10 changed files with 659 additions and 0 deletions.
70 changes: 70 additions & 0 deletions benches/benches/bevy_ecs/ecs_bench_suite/frag_iter_foreach_wide.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 70 additions & 0 deletions benches/benches/bevy_ecs/ecs_bench_suite/frag_iter_wide.rs
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
40 changes: 40 additions & 0 deletions benches/benches/bevy_ecs/ecs_bench_suite/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,28 @@ 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");
Expand All @@ -43,6 +51,10 @@ fn bench_simple_iter(c: &mut Criterion) {
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());
Expand All @@ -51,14 +63,26 @@ fn bench_simple_iter(c: &mut Criterion) {
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();
}

Expand All @@ -70,10 +94,18 @@ fn bench_frag_iter_bc(c: &mut Criterion) {
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();
}

Expand All @@ -85,10 +117,18 @@ fn bench_sparse_frag_iter(c: &mut Criterion) {
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();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
});
}
}
Original file line number Diff line number Diff line change
@@ -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;
});
}
}
Loading

0 comments on commit acb65c0

Please sign in to comment.