Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Spawn specific entities: spawn or insert operations, refactor spawn internals, world clearing #2673

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 95 additions & 2 deletions benches/benches/bevy_ecs/commands.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use bevy::ecs::{
entity::Entity,
system::{Command, CommandQueue, Commands},
world::World,
};
Expand All @@ -8,10 +9,12 @@ criterion_group!(
benches,
empty_commands,
spawn_commands,
insert_commands,
fake_commands,
zero_sized_commands,
medium_sized_commands,
large_sized_commands
get_or_spawn,
);
criterion_main!(benches);

Expand Down Expand Up @@ -76,6 +79,58 @@ fn spawn_commands(criterion: &mut Criterion) {
group.finish();
}

#[derive(Default)]
struct Matrix([[f32; 4]; 4]);

#[derive(Default)]
struct Vec3([f32; 3]);

fn insert_commands(criterion: &mut Criterion) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love this as a name: it reads as "the time it takes to insert Commands to the queue", not "how long does it take to insert components via commands". Perhaps batch_component_insertion?

Copy link
Member Author

@cart cart Aug 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

batch_component_insertion only applies to one of the two benchmarks in the group. It is intended to be a comparison of the various insertion approaches (non batched and batched).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm open to alternative names though (provided they describe that situation).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this should be component_insertion then. Eventually, I'd like to have non-Commands component insertion, which would also be very nice to include here. The fact that it uses commands to do insertion is mostly incidental IMO.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its worth calling out that this file is called "commands", which scopes it to "command benchmarks" imo. Happy to reorganize, but currently these benchmarks are all organized under a "commands" bucket.

let mut group = criterion.benchmark_group("insert_commands");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));

let entity_count = 10_000;
group.bench_function(format!("insert"), |bencher| {
let mut world = World::default();
let mut command_queue = CommandQueue::default();
let mut entities = Vec::new();
for i in 0..entity_count {
entities.push(world.spawn().id());
}

bencher.iter(|| {
let mut commands = Commands::new(&mut command_queue, &world);
for entity in entities.iter() {
commands.entity(*entity).insert_bundle((Matrix::default(), Vec3::default()));
}
drop(commands);
command_queue.apply(&mut world);
});
});
group.bench_function(format!("insert_batch"), |bencher| {
let mut world = World::default();
let mut command_queue = CommandQueue::default();
let mut entities = Vec::new();
for i in 0..entity_count {
entities.push(world.spawn().id());
}

bencher.iter(|| {
let mut commands = Commands::new(&mut command_queue, &world);
let mut values = Vec::with_capacity(entity_count);
for entity in entities.iter() {
values.push((*entity, (Matrix::default(), Vec3::default())));
}
commands.insert_or_spawn_batch(values);
drop(commands);
cart marked this conversation as resolved.
Show resolved Hide resolved
command_queue.apply(&mut world);
});
});

group.finish();
}

struct FakeCommandA;
struct FakeCommandB(u64);

Expand Down Expand Up @@ -106,7 +161,7 @@ fn fake_commands(criterion: &mut Criterion) {
bencher.iter(|| {
let mut commands = Commands::new(&mut command_queue, &world);
for i in 0..command_count {
if black_box(i % 2 == 0)
if black_box(i % 2 == 0) {
commands.add(FakeCommandA);
} else {
commands.add(FakeCommandB(0));
Expand All @@ -125,7 +180,7 @@ fn fake_commands(criterion: &mut Criterion) {
struct SizedCommand<T: Default + Send + Sync + 'static>(T);

impl<T: Default + Send + Sync + 'static> Command for SizedCommand<T> {
fn write(self: Box<Self>, world: &mut World) {
fn write(self, world: &mut World) {
black_box(self);
black_box(world);
}
Expand Down Expand Up @@ -175,3 +230,41 @@ fn medium_sized_commands(criterion: &mut Criterion) {
fn large_sized_commands(criterion: &mut Criterion) {
sized_commands_impl::<SizedCommand<LargeStruct>>(criterion);
}

fn get_or_spawn(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("get_or_spawn");
group.warm_up_time(std::time::Duration::from_millis(500));
group.measurement_time(std::time::Duration::from_secs(4));

group.bench_function("individual", |bencher| {
let mut world = World::default();
let mut command_queue = CommandQueue::default();

bencher.iter(|| {
let mut commands = Commands::new(&mut command_queue, &world);
for i in 0..10_000 {
commands
.get_or_spawn(Entity::new(i))
.insert_bundle((Matrix::default(), Vec3::default()));
}
command_queue.apply(&mut world);
});
});

group.bench_function("batched", |bencher| {
let mut world = World::default();
let mut command_queue = CommandQueue::default();

bencher.iter(|| {
let mut commands = Commands::new(&mut command_queue, &world);
let mut values = Vec::with_capacity(10_000);
for i in 0..10_000 {
values.push((Entity::new(i), (Matrix::default(), Vec3::default())));
}
commands.insert_or_spawn_batch(values);
command_queue.apply(&mut world);
});
});

group.finish();
}
16 changes: 16 additions & 0 deletions crates/bevy_ecs/src/archetype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ impl ArchetypeId {
ArchetypeId(0)
}

#[inline]
pub const fn invalid() -> ArchetypeId {
ArchetypeId(usize::MAX)
}

cart marked this conversation as resolved.
Show resolved Hide resolved
#[inline]
pub const fn resource() -> ArchetypeId {
ArchetypeId(1)
Expand Down Expand Up @@ -309,6 +314,11 @@ impl Archetype {
.get(component_id)
.map(|info| info.archetype_component_id)
}

pub(crate) fn clear_entities(&mut self) {
self.entities.clear();
self.table_info.entity_rows.clear();
}
}

/// A generational id that changes every time the set of archetypes changes
Expand Down Expand Up @@ -519,6 +529,12 @@ impl Archetypes {
pub fn archetype_components_len(&self) -> usize {
self.archetype_component_count
}

pub fn clear_entities(&mut self) {
for archetype in self.archetypes.iter_mut() {
archetype.clear_entities();
}
}
}

impl Index<ArchetypeId> for Archetypes {
Expand Down
Loading