Skip to content

Commit d76c3aa

Browse files
hymmalice-i-cecile
andauthored
get_components_mut (#21780)
# Objective - Add a checked version of `EntityMut::get_components_mut` and `EntityWorldMut::get_components_mut` that does not allocate ## Solution - Add a iterator over the access type to `QueryData`. This is then used to iterate over the pairs of access to check if they are compatible or not. ## Testing - Added a unit test ### Bench checked vs unchecked (50000 entities) | #components | unchecked | checked | times slower | |-------------|-----------|----------|----------| | 2 | 509 us | 1123 us | 2.2x | | 5 | 903 us | 2902us | 3.2x | | 10 | 1700 us | 11424 us | 6.72x | so at 10 components each call was taking about 0.22us vs 0.03 us --- ## ToDo * [x] add release note * [x] add migration guide * [x] add macro for more benches * [x] add bench results to pr description * [ ] look into if this will help with uncached queries * [x] see if we can optimize it a bit --------- Co-authored-by: Alice Cecile <[email protected]>
1 parent d44b9f8 commit d76c3aa

File tree

16 files changed

+906
-23
lines changed

16 files changed

+906
-23
lines changed

benches/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ autobenches = false
1111
# The primary crate that runs and analyzes our benchmarks. This is a regular dependency because the
1212
# `bench!` macro refers to it in its documentation.
1313
criterion = { version = "0.8.0", features = ["html_reports"] }
14+
seq-macro = "0.3.6"
1415

1516
[dev-dependencies]
1617
# Bevy crates

benches/benches/bevy_ecs/world/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,8 @@ criterion_group!(
3535
query_get_many::<2>,
3636
query_get_many::<5>,
3737
query_get_many::<10>,
38+
query_get_components_mut_2,
39+
query_get_components_mut_5,
40+
query_get_components_mut_10,
3841
entity_set_build_and_lookup,
3942
);

benches/benches/bevy_ecs/world/world_get.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1+
use benches::bench;
12
use core::hint::black_box;
23

34
use bevy_ecs::{
45
bundle::{Bundle, NoBundleEffect},
56
component::Component,
67
entity::Entity,
78
system::{Query, SystemState},
8-
world::World,
9+
world::{EntityMut, World},
910
};
1011
use criterion::Criterion;
1112
use rand::{prelude::SliceRandom, SeedableRng};
1213
use rand_chacha::ChaCha8Rng;
14+
use seq_macro::seq;
1315

1416
#[derive(Component, Default)]
1517
#[component(storage = "Table")]
@@ -357,3 +359,64 @@ pub fn query_get_many<const N: usize>(criterion: &mut Criterion) {
357359
});
358360
}
359361
}
362+
363+
macro_rules! query_get_components_mut {
364+
($function_name:ident, $val:literal) => {
365+
pub fn $function_name(criterion: &mut Criterion) {
366+
let mut group = criterion.benchmark_group(bench!("world_query_get_components_mut"));
367+
group.warm_up_time(core::time::Duration::from_millis(500));
368+
group.measurement_time(core::time::Duration::from_secs(4));
369+
370+
for entity_count in RANGE.map(|i| i * 10_000) {
371+
seq!(N in 0..$val {
372+
let (mut world, entities) = setup_wide::<(
373+
#(WideTable<N>,)*
374+
)>(entity_count);
375+
});
376+
let mut query = world.query::<EntityMut>();
377+
group.bench_function(format!("{}_components_{entity_count}_entities", $val), |bencher| {
378+
bencher.iter(|| {
379+
for entity in &entities {
380+
seq!(N in 0..$val {
381+
assert!(query
382+
.get_mut(&mut world, *entity)
383+
.unwrap()
384+
.get_components_mut::<(
385+
#(&mut WideTable<N>,)*
386+
)>()
387+
.is_ok());
388+
});
389+
}
390+
});
391+
});
392+
group.bench_function(
393+
format!("unchecked_{}_components_{entity_count}_entities", $val),
394+
|bencher| {
395+
bencher.iter(|| {
396+
for entity in &entities {
397+
// SAFETY: no duplicate components are listed
398+
unsafe {
399+
seq!(N in 0..$val {
400+
assert!(query
401+
.get_mut(&mut world, *entity)
402+
.unwrap()
403+
.get_components_mut_unchecked::<(
404+
#(&mut WideTable<N>,)*
405+
)>()
406+
.is_ok());
407+
});
408+
}
409+
}
410+
});
411+
},
412+
);
413+
}
414+
415+
group.finish();
416+
}
417+
};
418+
}
419+
420+
query_get_components_mut!(query_get_components_mut_2, 2);
421+
query_get_components_mut!(query_get_components_mut_5, 5);
422+
query_get_components_mut!(query_get_components_mut_10, 10);

crates/bevy_ecs/macros/src/query_data.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,12 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
267267
#(#field_members: <#read_only_field_types>::fetch(&_state.#field_aliases, &mut _fetch.#field_aliases, _entity, _table_row)?,)*
268268
})
269269
}
270+
271+
fn iter_access(
272+
_state: &Self::State,
273+
) -> impl core::iter::Iterator<Item = #path::query::EcsAccessType<'_>> {
274+
core::iter::empty() #(.chain(<#field_types>::iter_access(&_state.#field_aliases)))*
275+
}
270276
}
271277

272278
impl #user_impl_generics #path::query::ReleaseStateQueryData
@@ -332,6 +338,12 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
332338
#(#field_members: <#field_types>::fetch(&_state.#field_aliases, &mut _fetch.#field_aliases, _entity, _table_row)?,)*
333339
})
334340
}
341+
342+
fn iter_access(
343+
_state: &Self::State,
344+
) -> impl core::iter::Iterator<Item = #path::query::EcsAccessType<'_>> {
345+
core::iter::empty() #(.chain(<#field_types>::iter_access(&_state.#field_aliases)))*
346+
}
335347
}
336348

337349
impl #user_impl_generics #path::query::ReleaseStateQueryData

crates/bevy_ecs/src/event/trigger.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ unsafe impl<
301301
return;
302302
}
303303
if let Ok(entity) = world.get_entity(current_entity)
304-
&& let Some(item) = entity.get_components::<T>()
304+
&& let Ok(item) = entity.get_components::<T>()
305305
&& let Some(traverse_to) = T::traverse(item, event)
306306
{
307307
current_entity = traverse_to;

0 commit comments

Comments
 (0)