Skip to content

Commit abe4cb1

Browse files
joseph-gioItsDoot
authored andcommitted
Add benchmarks for schedule dependency resolution (bevyengine#4961)
# Objective - Add benchmarks to test the performance of `Schedule`'s system dependency resolution. ## Solution - Do a series of benchmarks while increasing the number of systems in the schedule to see how the run-time scales. - Split the benchmarks into a group with no dependencies, and a group with many dependencies.
1 parent fd6ed92 commit abe4cb1

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

benches/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ glam = "0.20"
1111
rand = "0.8"
1212
rand_chacha = "0.3"
1313
criterion = { version = "0.3", features = ["html_reports"] }
14+
bevy_app = { path = "../crates/bevy_app" }
1415
bevy_ecs = { path = "../crates/bevy_ecs" }
1516
bevy_reflect = { path = "../crates/bevy_reflect" }
1617
bevy_tasks = { path = "../crates/bevy_tasks" }
@@ -46,6 +47,11 @@ name = "world_get"
4647
path = "benches/bevy_ecs/world_get.rs"
4748
harness = false
4849

50+
[[bench]]
51+
name = "schedule"
52+
path = "benches/bevy_ecs/schedule.rs"
53+
harness = false
54+
4955
[[bench]]
5056
name = "reflect_list"
5157
path = "benches/bevy_reflect/list.rs"

benches/benches/bevy_ecs/schedule.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use bevy_app::App;
2+
use bevy_ecs::prelude::*;
3+
use criterion::{criterion_group, criterion_main, Criterion};
4+
5+
criterion_group!(benches, build_schedule);
6+
criterion_main!(benches);
7+
8+
fn build_schedule(criterion: &mut Criterion) {
9+
// empty system
10+
fn empty_system() {}
11+
12+
// Use multiple different kinds of label to ensure that dynamic dispatch
13+
// doesn't somehow get optimized away.
14+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, SystemLabel)]
15+
struct NumLabel(usize);
16+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, SystemLabel)]
17+
struct DummyLabel;
18+
19+
let mut group = criterion.benchmark_group("build_schedule");
20+
group.warm_up_time(std::time::Duration::from_millis(500));
21+
group.measurement_time(std::time::Duration::from_secs(15));
22+
23+
// Method: generate a set of `graph_size` systems which have a One True Ordering.
24+
// Add system to the stage with full constraints. Hopefully this should be maximimally
25+
// difficult for bevy to figure out.
26+
let labels: Vec<_> = (0..1000).map(NumLabel).collect();
27+
28+
// Benchmark graphs of different sizes.
29+
for graph_size in [100, 500, 1000] {
30+
// Basic benchmark without constraints.
31+
group.bench_function(format!("{graph_size}_schedule_noconstraints"), |bencher| {
32+
bencher.iter(|| {
33+
let mut app = App::new();
34+
for _ in 0..graph_size {
35+
app.add_system(empty_system);
36+
}
37+
app.update();
38+
});
39+
});
40+
41+
// Benchmark with constraints.
42+
group.bench_function(format!("{graph_size}_schedule"), |bencher| {
43+
bencher.iter(|| {
44+
let mut app = App::new();
45+
app.add_system(empty_system.label(DummyLabel));
46+
47+
// Build a fully-connected dependency graph describing the One True Ordering.
48+
// Not particularly realistic but this can be refined later.
49+
for i in 0..graph_size {
50+
let mut sys = empty_system.label(labels[i]).before(DummyLabel);
51+
for a in 0..i {
52+
sys = sys.after(labels[a]);
53+
}
54+
for b in i + 1..graph_size {
55+
sys = sys.before(labels[b]);
56+
}
57+
app.add_system(sys);
58+
}
59+
// Run the app for a single frame.
60+
// This is necessary since dependency resolution does not occur until the game runs.
61+
// FIXME: Running the game clutters up the benchmarks, so ideally we'd be
62+
// able to benchmark the dependency resolution directly.
63+
app.update();
64+
});
65+
});
66+
}
67+
68+
group.finish();
69+
}

0 commit comments

Comments
 (0)