Skip to content
This repository was archived by the owner on Nov 27, 2022. It is now read-only.

Commit c9bb9b4

Browse files
committed
initial specs benchmarking
1 parent 307bc08 commit c9bb9b4

File tree

11 files changed

+233
-259
lines changed

11 files changed

+233
-259
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ legion_2_4 = { package = "legion", version = "0.2.4" }
1818
bevy_ecs = "0.1"
1919
hecs = "0.2"
2020
shipyard = "0.4"
21-
specs = "0.16.1"
21+
specs = {version = "0.16.1", features = ["serde"] }
22+
specs-derive = "0.4.1"
2223

2324
[dev-dependencies]
2425
criterion = "0.3"

benches/benchmarks.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ fn bench_simple_insert(c: &mut Criterion) {
1919
let mut bench = shipyard::simple_insert::Benchmark::new();
2020
b.iter(move || bench.run());
2121
});
22+
group.bench_function("specs", |b| {
23+
let mut bench = specs::simple_insert::Benchmark::new();
24+
b.iter(move || bench.run());
25+
});
2226
}
2327

2428
fn bench_simple_iter(c: &mut Criterion) {
@@ -39,6 +43,10 @@ fn bench_simple_iter(c: &mut Criterion) {
3943
let mut bench = shipyard::simple_iter::Benchmark::new();
4044
b.iter(move || bench.run());
4145
});
46+
group.bench_function("specs", |b| {
47+
let mut bench = specs::simple_iter::Benchmark::new();
48+
b.iter(move || bench.run());
49+
});
4250
}
4351

4452
fn bench_frag_iter_bc(c: &mut Criterion) {
@@ -59,6 +67,10 @@ fn bench_frag_iter_bc(c: &mut Criterion) {
5967
let mut bench = shipyard::frag_iter::Benchmark::new();
6068
b.iter(move || bench.run());
6169
});
70+
group.bench_function("specs", |b| {
71+
let mut bench = specs::frag_iter::Benchmark::new();
72+
b.iter(move || bench.run());
73+
});
6274
}
6375

6476
fn bench_schedule(c: &mut Criterion) {
@@ -79,6 +91,10 @@ fn bench_schedule(c: &mut Criterion) {
7991
let mut bench = shipyard::schedule::Benchmark::new();
8092
b.iter(move || bench.run());
8193
});
94+
group.bench_function("specs", |b| {
95+
let mut bench = specs::schedule::Benchmark::new();
96+
b.iter(move || bench.run());
97+
});
8298
}
8399

84100
fn bench_heavy_compute(c: &mut Criterion) {
@@ -99,6 +115,10 @@ fn bench_heavy_compute(c: &mut Criterion) {
99115
let mut bench = shipyard::heavy_compute::Benchmark::new();
100116
b.iter(move || bench.run());
101117
});
118+
group.bench_function("specs", |b| {
119+
let mut bench = specs::heavy_compute::Benchmark::new();
120+
b.iter(move || bench.run());
121+
});
102122
}
103123

104124
fn bench_add_remove(c: &mut Criterion) {
@@ -115,6 +135,10 @@ fn bench_add_remove(c: &mut Criterion) {
115135
let mut bench = shipyard::add_remove::Benchmark::new();
116136
b.iter(move || bench.run());
117137
});
138+
group.bench_function("specs", |b| {
139+
let mut bench = specs::add_remove::Benchmark::new();
140+
b.iter(move || bench.run());
141+
});
118142

119143
// todo Bevy appears to crash in this benchmark
120144
// group.bench_function("bevy", |b| {

src/specs/add_remove.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,29 @@
11
use specs::prelude::*;
2-
2+
use specs_derive::*;
3+
#[derive(Component)]
4+
#[storage(VecStorage)]
35
struct A(f32);
4-
impl Component for A {
5-
type Storage = VecStorage<Self>;
6-
}
6+
#[derive(Component)]
7+
#[storage(VecStorage)]
78
struct B(f32);
8-
impl Component for B {
9-
type Storage = VecStorage<Self>;
10-
}
119

1210
pub struct Benchmark(World, Vec<Entity>);
1311

1412
impl Benchmark {
1513
pub fn new() -> Self {
16-
let mut world = World::default();
14+
let mut world = World::new();
1715
world.register::<A>();
16+
world.register::<B>();
1817
let entities = (0..10000)
1918
.map(|_| world.create_entity().with(A(0.0)).build())
2019
.collect();
21-
world.register::<B>();
2220
Self(world, entities)
2321
}
2422

2523
pub fn run(&mut self) {
2624
let mut b_storage = self.0.write_storage::<B>();
2725
for entity in &self.1 {
28-
b_storage.insert(*entity, B(0.0));
26+
b_storage.insert(*entity, B(0.0)).unwrap();
2927
}
3028

3129
for entity in &self.1 {

src/specs/frag_iter.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,29 @@
11
use specs::prelude::*;
2+
use specs_derive::*;
23

34
macro_rules! create_entities {
45
($world:ident; $( $variants:ident ),*) => {
56
$(
7+
#[derive(Component)]
8+
#[storage(VecStorage)]
69
struct $variants(f32);
7-
impl Component for $variants {
8-
type Storage = DenseVecStorage<Self>;
9-
}
10+
$world.register::<$variants>();
1011
(0..20)
1112
.for_each(|_| {$world.create_entity().with($variants(0.0)).with(Data(1.0)).build();});
1213
)*
1314
};
1415
}
15-
16+
#[derive(Component)]
17+
#[storage(VecStorage)]
1618
struct Data(f32);
17-
impl Component for Data {
18-
type Storage = VecStorage<Self>;
19-
}
2019

2120
struct FragIterSystem;
2221

2322
impl<'a> System<'a> for FragIterSystem {
2423
type SystemData = WriteStorage<'a, Data>;
2524

2625
fn run(&mut self, mut data_storage: Self::SystemData) {
27-
for mut data in (&mut data_storage).join() {
26+
for data in (&mut data_storage).join() {
2827
data.0 *= 2.0;
2928
}
3029
}
@@ -33,8 +32,8 @@ pub struct Benchmark(World, FragIterSystem);
3332

3433
impl Benchmark {
3534
pub fn new() -> Self {
36-
let mut world = World::default();
37-
35+
let mut world = World::new();
36+
world.register::<Data>();
3837
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);
3938

4039
Self(world, FragIterSystem)

src/specs/heavy_compute.rs

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,60 @@
11
use cgmath::*;
22
use specs::prelude::*;
3-
4-
#[derive(Copy, Clone)]
3+
use specs_derive::*;
4+
#[derive(Copy, Clone, Component)]
5+
#[storage(VecStorage)]
6+
struct Transform(Matrix4<f32>);
7+
#[derive(Copy, Clone, Component)]
8+
#[storage(VecStorage)]
59
struct Position(Vector3<f32>);
610

7-
#[derive(Copy, Clone)]
11+
#[derive(Copy, Clone, Component)]
12+
#[storage(VecStorage)]
813
struct Rotation(Vector3<f32>);
914

10-
#[derive(Copy, Clone)]
15+
#[derive(Copy, Clone, Component)]
16+
#[storage(VecStorage)]
1117
struct Velocity(Vector3<f32>);
1218

13-
pub struct Benchmark(World, Query<(Write<Position>, Write<Matrix4<f32>>)>);
19+
struct HeavyComputeSystem;
1420

15-
impl Benchmark {
16-
pub fn new() -> Self {
17-
let mut world = World::default();
21+
impl<'a> System<'a> for HeavyComputeSystem {
22+
type SystemData = (WriteStorage<'a, Position>, WriteStorage<'a, Transform>);
23+
24+
fn run(&mut self, (mut pos_store, mut mat_store): Self::SystemData) {
25+
use cgmath::Transform;
26+
for (pos, mat) in (&mut pos_store, &mut mat_store).join() {
27+
for _ in 0..100 {
28+
mat.0 = mat.0.invert().unwrap();
29+
}
30+
pos.0 = mat.0.transform_vector(pos.0);
31+
}
32+
}
33+
}
1834

19-
world.extend((0..1000).map(|_| {
20-
(
21-
Matrix4::<f32>::from_angle_x(Rad(1.2)),
22-
Position(Vector3::unit_x()),
23-
Rotation(Vector3::unit_x()),
24-
Velocity(Vector3::unit_x()),
25-
)
26-
}));
27-
world.pack(PackOptions::force());
35+
pub struct Benchmark(World, HeavyComputeSystem);
2836

29-
let query = <(Write<Position>, Write<Matrix4<f32>>)>::query();
37+
impl Benchmark {
38+
pub fn new() -> Self {
39+
let mut world = World::new();
40+
world.register::<Transform>();
41+
world.register::<Position>();
42+
world.register::<Rotation>();
43+
world.register::<Velocity>();
44+
(0..1000).for_each(|_| {
45+
world
46+
.create_entity()
47+
.with(Transform(Matrix4::<f32>::from_angle_x(Rad(1.2))))
48+
.with(Position(Vector3::unit_x()))
49+
.with(Rotation(Vector3::unit_x()))
50+
.with(Velocity(Vector3::unit_x()))
51+
.build();
52+
});
3053

31-
Self(world, query)
54+
Self(world, HeavyComputeSystem)
3255
}
3356

3457
pub fn run(&mut self) {
35-
self.1.par_for_each_mut(&mut self.0, |(pos, mat)| {
36-
for _ in 0..100 {
37-
*mat = mat.invert().unwrap();
38-
}
39-
pos.0 = mat.transform_vector(pos.0);
40-
});
58+
self.1.run_now(&self.0);
4159
}
4260
}

src/specs/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,5 @@ pub mod add_remove;
22
pub mod frag_iter;
33
pub mod heavy_compute;
44
pub mod schedule;
5-
pub mod serialize_binary;
6-
pub mod serialize_text;
75
pub mod simple_insert;
86
pub mod simple_iter;

src/specs/schedule.rs

Lines changed: 85 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,109 @@
1-
use legion::*;
2-
use storage::PackOptions;
3-
1+
use specs::prelude::*;
2+
use specs_derive::*;
3+
#[derive(Component)]
4+
#[storage(VecStorage)]
45
struct A(f32);
6+
#[derive(Component)]
7+
#[storage(VecStorage)]
58
struct B(f32);
9+
#[derive(Component)]
10+
#[storage(VecStorage)]
611
struct C(f32);
12+
#[derive(Component)]
13+
#[storage(VecStorage)]
714
struct D(f32);
15+
#[derive(Component)]
16+
#[storage(VecStorage)]
817
struct E(f32);
918

10-
#[system(for_each)]
11-
fn ab(a: &mut A, b: &mut B) {
12-
std::mem::swap(&mut a.0, &mut b.0);
13-
}
19+
struct ABSystem;
1420

15-
#[system(for_each)]
16-
fn cd(c: &mut C, d: &mut D) {
17-
std::mem::swap(&mut c.0, &mut d.0);
18-
}
21+
impl<'a> System<'a> for ABSystem {
22+
type SystemData = (WriteStorage<'a, A>, WriteStorage<'a, B>);
1923

20-
#[system(for_each)]
21-
fn ce(c: &mut C, e: &mut E) {
22-
std::mem::swap(&mut c.0, &mut e.0);
24+
fn run(&mut self, (mut a_store, mut b_store): Self::SystemData) {
25+
for (a, b) in (&mut a_store, &mut b_store).join() {
26+
std::mem::swap(&mut a.0, &mut b.0);
27+
}
28+
}
2329
}
2430

25-
pub struct Benchmark(World, Resources, Schedule);
31+
struct CDSystem;
2632

27-
impl Benchmark {
28-
pub fn new() -> Self {
29-
let mut world = World::default();
33+
impl<'a> System<'a> for CDSystem {
34+
type SystemData = (WriteStorage<'a, C>, WriteStorage<'a, D>);
3035

31-
world.extend((0..10000).map(|_| (A(0.0), B(0.0))));
36+
fn run(&mut self, (mut c_store, mut d_store): Self::SystemData) {
37+
for (c, d) in (&mut c_store, &mut d_store).join() {
38+
std::mem::swap(&mut c.0, &mut d.0);
39+
}
40+
}
41+
}
42+
struct CESystem;
3243

33-
world.extend((0..10000).map(|_| (A(0.0), B(0.0), C(0.0))));
44+
impl<'a> System<'a> for CESystem {
45+
type SystemData = (WriteStorage<'a, C>, WriteStorage<'a, E>);
3446

35-
world.extend((0..10000).map(|_| (A(0.0), B(0.0), C(0.0), D(0.0))));
47+
fn run(&mut self, (mut c_store, mut e_store): Self::SystemData) {
48+
for (c, e) in (&mut c_store, &mut e_store).join() {
49+
std::mem::swap(&mut c.0, &mut e.0);
50+
}
51+
}
52+
}
3653

37-
world.extend((0..10000).map(|_| (A(0.0), B(0.0), C(0.0), E(0.0))));
54+
pub struct Benchmark<'a>(World, Dispatcher<'a, 'a>);
3855

39-
world.pack(PackOptions::force());
56+
impl Benchmark<'_> {
57+
pub fn new() -> Self {
58+
let mut world = World::new();
59+
world.register::<A>();
60+
world.register::<B>();
61+
world.register::<C>();
62+
world.register::<D>();
63+
world.register::<E>();
64+
(0..10000).for_each(|_| {
65+
world.create_entity().with(A(0.0)).build();
66+
});
67+
(0..10000).for_each(|_| {
68+
world.create_entity().with(A(0.0)).with(B(0.0)).build();
69+
});
70+
(0..10000).for_each(|_| {
71+
world
72+
.create_entity()
73+
.with(A(0.0))
74+
.with(B(0.0))
75+
.with(C(0.0))
76+
.build();
77+
});
78+
(0..10000).for_each(|_| {
79+
world
80+
.create_entity()
81+
.with(A(0.0))
82+
.with(B(0.0))
83+
.with(C(0.0))
84+
.with(D(0.0))
85+
.build();
86+
});
87+
(0..10000).for_each(|_| {
88+
world
89+
.create_entity()
90+
.with(A(0.0))
91+
.with(B(0.0))
92+
.with(C(0.0))
93+
.with(E(0.0))
94+
.build();
95+
});
4096

41-
let schedule = Schedule::builder()
42-
.add_system(ab_system())
43-
.add_system(cd_system())
44-
.add_system(ce_system())
97+
let dispatcher = DispatcherBuilder::new()
98+
.with(ABSystem, "ab", &[])
99+
.with(CDSystem, "cd", &[])
100+
.with(CESystem, "ce", &[])
45101
.build();
46102

47-
Self(world, Resources::default(), schedule)
103+
Self(world, dispatcher)
48104
}
49105

50106
pub fn run(&mut self) {
51-
self.2.execute(&mut self.0, &mut self.1);
107+
self.1.dispatch_par(&self.0)
52108
}
53109
}

0 commit comments

Comments
 (0)