Skip to content

Commit

Permalink
perf: faster insertion/removal of the Play component by using `Spar…
Browse files Browse the repository at this point in the history
…seStorage` (#34)
  • Loading branch information
jcornaz authored Jan 29, 2022
1 parent bbc666d commit 7f37562
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 2 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ bevy_asset = { version = "0.6.0", default-features = false }
[dev-dependencies]
bevy = { version = "0.6.0", default-features = false, features = ["render", "x11", "png"] }
rstest = "0.12.0"
criterion = "0.3.5"

[[bench]]
name = "play_component"
harness = false
104 changes: 104 additions & 0 deletions benches/play_component.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use bevy::prelude::*;
use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion};
use std::time::Duration;

use benimator::{Play, SpriteSheetAnimation, SpriteSheetAnimationState};

fn create_app<B: Bundle + Default>(size: usize) -> App {
let mut app = App::new();
app.world.spawn_batch((0..size).map(|_| B::default()));
app
}

#[derive(Default, Bundle)]
struct PlayingBundle {
play: Play,
state: SpriteSheetAnimationState,
sprite: TextureAtlasSprite,
handle: Handle<SpriteSheetAnimation>,
}

#[derive(Default, Bundle)]
struct PausedBundle {
state: SpriteSheetAnimationState,
sprite: TextureAtlasSprite,
handle: Handle<SpriteSheetAnimation>,
}

pub fn benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("play perfs");

group
.significance_level(0.02)
.confidence_level(0.98)
.measurement_time(Duration::from_secs(20));

for size in [0, 5_000, 10_000] {
group
.bench_with_input(
BenchmarkId::new("update when playing", size),
&size,
|b, size| {
let mut app = create_app::<PlayingBundle>(*size);
b.iter(|| app.update())
},
)
.bench_with_input(
BenchmarkId::new("update when paused", size),
&size,
|b, size| {
let mut app = create_app::<PausedBundle>(*size);
b.iter(|| app.update())
},
)
.bench_with_input(
BenchmarkId::new("remove play component", size),
&size,
|b, size| {
let setup = || {
let mut app = create_app::<PlayingBundle>(*size);
app.update(); // <-- Make sure, the world is properly initialized
let entities: Vec<Entity> = app
.world
.query_filtered::<Entity, With<Play>>()
.iter(&app.world)
.collect();
(app, entities)
};
let routine = |(mut app, entities): (App, Vec<Entity>)| {
for entity in entities {
app.world.entity_mut(entity).remove::<Play>();
}
};
b.iter_batched(setup, routine, BatchSize::LargeInput)
},
)
.bench_with_input(
BenchmarkId::new("insert play component", size),
&size,
|b, size| {
let setup = || {
let mut app = create_app::<PausedBundle>(*size);
app.update(); // <-- Make sure, the world is properly initialized
let entities: Vec<Entity> = app
.world
.query_filtered::<Entity, Without<Play>>()
.iter(&app.world)
.collect();
(app, entities)
};
let routine = |(mut app, entities): (App, Vec<Entity>)| {
for entity in entities {
app.world.entity_mut(entity).insert(Play);
}
};
b.iter_batched(setup, routine, BatchSize::LargeInput)
},
);
}

group.finish();
}

criterion_group!(benches, benchmark);
criterion_main!(benches);
4 changes: 3 additions & 1 deletion deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ vulnerability = "deny"
unmaintained = "deny"
yanked = "deny"
notice = "deny"
ignore = []
ignore = [
"RUSTSEC-2021-0127", # unmaintained crate `serde_cbor` used by criterion: https://github.com/bheisler/criterion.rs/issues/534
]

[licenses]
default = "deny"
Expand Down
7 changes: 6 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ extern crate rstest;

use bevy_app::prelude::*;
use bevy_asset::AddAsset;
use bevy_ecs::component::SparseStorage;
use bevy_ecs::prelude::*;
use bevy_reflect::Reflect;

Expand Down Expand Up @@ -142,10 +143,14 @@ pub enum AnimationPostUpdateSystem {
/// Insert the components to play the animation, and remove it to pause it.
///
/// If the animation mode is [`AnimationMode::Once`] this component is automatically removed at the end of the animation.
#[derive(Debug, Copy, Clone, Default, Reflect, Component)]
#[derive(Debug, Copy, Clone, Default, Reflect)]
#[reflect(Component)]
pub struct Play;

impl Component for Play {
type Storage = SparseStorage;
}

impl Plugin for AnimationPlugin {
fn build(&self, app: &mut App) {
app.add_asset::<SpriteSheetAnimation>()
Expand Down

0 comments on commit 7f37562

Please sign in to comment.