Skip to content

Commit 08ef2f0

Browse files
committed
Add cart's fork of ecs_bench_suite (#4225)
# Objective Better benchmarking for ECS. Fix #2062. ## Solution Port @cart's fork of ecs_bench_suite to the official bench suite for bevy_ecs, replace cgmath with glam, update to latest bevy.
1 parent ac8bbaf commit 08ef2f0

22 files changed

+996
-0
lines changed

benches/Cargo.toml

+6
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,16 @@ publish = false
77
license = "MIT OR Apache-2.0"
88

99
[dev-dependencies]
10+
glam = "0.20"
1011
criterion = "0.3"
1112
bevy_ecs = { path = "../crates/bevy_ecs" }
1213
bevy_tasks = { path = "../crates/bevy_tasks" }
1314

15+
[[bench]]
16+
name = "ecs_bench_suite"
17+
path = "benches/bevy_ecs/ecs_bench_suite/mod.rs"
18+
harness = false
19+
1420
[[bench]]
1521
name = "system_stage"
1622
path = "benches/bevy_ecs/stages.rs"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use bevy::prelude::*;
2+
3+
#[derive(Component)]
4+
struct A(f32);
5+
#[derive(Component)]
6+
struct B(f32);
7+
8+
pub struct Benchmark(World, Vec<Entity>);
9+
10+
impl Benchmark {
11+
pub fn new() -> Self {
12+
let mut world = World::default();
13+
14+
let entities = world
15+
.spawn_batch((0..10000).map(|_| (A(0.0),)))
16+
.collect::<Vec<_>>();
17+
18+
Self(world, entities)
19+
}
20+
21+
pub fn run(&mut self) {
22+
for entity in &self.1 {
23+
self.0.insert_one(*entity, B(0.0)).unwrap();
24+
}
25+
26+
for entity in &self.1 {
27+
self.0.remove_one::<B>(*entity).unwrap();
28+
}
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use bevy_ecs::prelude::*;
2+
use glam::*;
3+
4+
#[derive(Component, Copy, Clone)]
5+
struct A(Mat4);
6+
#[derive(Component, Copy, Clone)]
7+
struct B(Mat4);
8+
9+
#[derive(Component, Copy, Clone)]
10+
struct C(Mat4);
11+
#[derive(Component, Copy, Clone)]
12+
struct D(Mat4);
13+
14+
#[derive(Component, Copy, Clone)]
15+
struct E(Mat4);
16+
17+
#[derive(Component, Copy, Clone)]
18+
#[component(storage = "SparseSet")]
19+
struct F(Mat4);
20+
pub struct Benchmark(World, Vec<Entity>);
21+
22+
impl Benchmark {
23+
pub fn new() -> Self {
24+
let mut world = World::default();
25+
let mut entities = Vec::with_capacity(10_000);
26+
for _ in 0..10_000 {
27+
entities.push(
28+
world
29+
.spawn()
30+
.insert_bundle((
31+
A(Mat4::from_scale(Vec3::ONE)),
32+
B(Mat4::from_scale(Vec3::ONE)),
33+
C(Mat4::from_scale(Vec3::ONE)),
34+
D(Mat4::from_scale(Vec3::ONE)),
35+
E(Mat4::from_scale(Vec3::ONE)),
36+
))
37+
.id(),
38+
);
39+
}
40+
41+
Self(world, entities)
42+
}
43+
44+
pub fn run(&mut self) {
45+
for entity in &self.1 {
46+
self.0
47+
.entity_mut(*entity)
48+
.insert(F(Mat4::from_scale(Vec3::ONE)));
49+
}
50+
51+
for entity in &self.1 {
52+
self.0.entity_mut(*entity).remove::<F>();
53+
}
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use bevy_ecs::prelude::*;
2+
use glam::*;
3+
4+
#[derive(Component, Copy, Clone)]
5+
struct A(Mat4);
6+
#[derive(Component, Copy, Clone)]
7+
struct B(Mat4);
8+
9+
#[derive(Component, Copy, Clone)]
10+
struct C(Mat4);
11+
#[derive(Component, Copy, Clone)]
12+
struct D(Mat4);
13+
14+
#[derive(Component, Copy, Clone)]
15+
struct E(Mat4);
16+
17+
#[derive(Component, Copy, Clone)]
18+
struct F(Mat4);
19+
pub struct Benchmark(World, Vec<Entity>);
20+
21+
impl Benchmark {
22+
pub fn new() -> Self {
23+
let mut world = World::default();
24+
let mut entities = Vec::with_capacity(10_000);
25+
for _ in 0..10_000 {
26+
entities.push(
27+
world
28+
.spawn()
29+
.insert_bundle((
30+
A(Mat4::from_scale(Vec3::ONE)),
31+
B(Mat4::from_scale(Vec3::ONE)),
32+
C(Mat4::from_scale(Vec3::ONE)),
33+
D(Mat4::from_scale(Vec3::ONE)),
34+
E(Mat4::from_scale(Vec3::ONE)),
35+
))
36+
.id(),
37+
);
38+
}
39+
40+
Self(world, entities)
41+
}
42+
43+
pub fn run(&mut self) {
44+
for entity in &self.1 {
45+
self.0
46+
.entity_mut(*entity)
47+
.insert(F(Mat4::from_scale(Vec3::ONE)));
48+
}
49+
50+
for entity in &self.1 {
51+
self.0.entity_mut(*entity).remove::<F>();
52+
}
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use bevy_ecs::prelude::*;
2+
3+
#[derive(Component)]
4+
struct A(f32);
5+
#[derive(Component)]
6+
#[component(storage = "SparseSet")]
7+
struct B(f32);
8+
9+
pub struct Benchmark(World, Vec<Entity>);
10+
11+
impl Benchmark {
12+
pub fn new() -> Self {
13+
let mut world = World::default();
14+
let mut entities = Vec::with_capacity(10_000);
15+
for _ in 0..10_000 {
16+
entities.push(world.spawn().insert(A(0.0)).id());
17+
}
18+
19+
Self(world, entities)
20+
}
21+
22+
pub fn run(&mut self) {
23+
for entity in &self.1 {
24+
self.0.entity_mut(*entity).insert(B(0.0));
25+
}
26+
27+
for entity in &self.1 {
28+
self.0.entity_mut(*entity).remove::<B>();
29+
}
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use bevy_ecs::prelude::*;
2+
3+
#[derive(Component)]
4+
struct A(f32);
5+
#[derive(Component)]
6+
struct B(f32);
7+
8+
pub struct Benchmark(World, Vec<Entity>);
9+
10+
impl Benchmark {
11+
pub fn new() -> Self {
12+
let mut world = World::default();
13+
let mut entities = Vec::with_capacity(10_000);
14+
for _ in 0..10_000 {
15+
entities.push(world.spawn().insert(A(0.0)).id());
16+
}
17+
18+
Self(world, entities)
19+
}
20+
21+
pub fn run(&mut self) {
22+
for entity in &self.1 {
23+
self.0.entity_mut(*entity).insert(B(0.0));
24+
}
25+
26+
for entity in &self.1 {
27+
self.0.entity_mut(*entity).remove::<B>();
28+
}
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use bevy_ecs::prelude::*;
2+
3+
macro_rules! create_entities {
4+
($world:ident; $( $variants:ident ),*) => {
5+
$(
6+
#[derive(Component)]
7+
struct $variants(f32);
8+
for _ in 0..20 {
9+
$world.spawn().insert_bundle(($variants(0.0), Data(1.0)));
10+
}
11+
)*
12+
};
13+
}
14+
15+
#[derive(Component)]
16+
struct Data(f32);
17+
18+
pub struct Benchmark<'w>(World, QueryState<&'w mut Data>);
19+
20+
impl<'w> Benchmark<'w> {
21+
pub fn new() -> Self {
22+
let mut world = World::new();
23+
24+
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);
25+
26+
let query = world.query::<&mut Data>();
27+
Self(world, query)
28+
}
29+
30+
pub fn run(&mut self) {
31+
for mut data in self.1.iter_mut(&mut self.0) {
32+
data.0 *= 2.0;
33+
}
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use bevy_ecs::prelude::*;
2+
3+
macro_rules! create_entities {
4+
($world:ident; $( $variants:ident ),*) => {
5+
$(
6+
#[derive(Component)]
7+
struct $variants(f32);
8+
for _ in 0..20 {
9+
$world.spawn().insert_bundle(($variants(0.0), Data(1.0)));
10+
}
11+
)*
12+
};
13+
}
14+
15+
#[derive(Component)]
16+
struct Data(f32);
17+
18+
pub struct Benchmark<'w>(World, QueryState<&'w mut Data>);
19+
20+
impl<'w> Benchmark<'w> {
21+
pub fn new() -> Self {
22+
let mut world = World::new();
23+
24+
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);
25+
26+
let query = world.query::<&mut Data>();
27+
Self(world, query)
28+
}
29+
30+
pub fn run(&mut self) {
31+
self.1.for_each_mut(&mut self.0, |mut data| {
32+
data.0 *= 2.0;
33+
});
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use bevy_ecs::prelude::*;
2+
3+
#[derive(Component)]
4+
struct A(f32);
5+
6+
pub struct Benchmark<'w>(World, Entity, QueryState<&'w mut A>);
7+
8+
impl<'w> Benchmark<'w> {
9+
pub fn new() -> Self {
10+
let mut world = World::new();
11+
12+
let entity = world.spawn().insert(A(0.0)).id();
13+
let query = world.query::<&mut A>();
14+
Self(world, entity, query)
15+
}
16+
17+
pub fn run(&mut self) {
18+
for _x in 0..100000 {
19+
let mut a = unsafe { self.2.get_unchecked(&mut self.0, self.1).unwrap() };
20+
a.0 += 1.0;
21+
}
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use bevy_ecs::prelude::*;
2+
3+
#[derive(Component)]
4+
struct A(f32);
5+
6+
pub struct Benchmark(World, Entity, Box<dyn System<In = Entity, Out = ()>>);
7+
8+
impl Benchmark {
9+
pub fn new() -> Self {
10+
let mut world = World::new();
11+
12+
let entity = world.spawn().insert(A(0.0)).id();
13+
fn query_system(In(entity): In<Entity>, mut query: Query<&mut A>) {
14+
for _ in 0..100_000 {
15+
let mut a = query.get_mut(entity).unwrap();
16+
a.0 += 1.0;
17+
}
18+
}
19+
20+
let mut system = IntoSystem::into_system(query_system);
21+
system.initialize(&mut world);
22+
for archetype in world.archetypes().iter() {
23+
system.new_archetype(archetype);
24+
}
25+
Self(world, entity, Box::new(system))
26+
}
27+
28+
pub fn run(&mut self) {
29+
self.2.run(self.1, &mut self.0);
30+
}
31+
}

0 commit comments

Comments
 (0)