Speedup resource lookup in Res and ResMut#23174
Speedup resource lookup in Res and ResMut#23174Trashtalk217 wants to merge 4 commits intobevyengine:mainfrom
Res and ResMut#23174Conversation
|
Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke! If it's expected, please add the M-Deliberate-Rendering-Change label. If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it. |
|
Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke! If it's expected, please add the M-Deliberate-Rendering-Change label. If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it. |
1 similar comment
|
Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke! If it's expected, please add the M-Deliberate-Rendering-Change label. If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it. |
| #[inline] | ||
| unsafe fn validate_param( | ||
| &mut component_id: &mut Self::State, | ||
| &mut (component_id, entity): &mut Self::State, |
There was a problem hiding this comment.
The redundant work in validate_param, which is done immediately before get_param never felt great to me. This isn't a problem exclusive to Res/ResMut, but it is certainly present.
I think doing validation as part of get_param is more defensible from a performance perspective.
I think it is worth doing some benchmarks where we skip validation (as-in, across all SystemParams), just to see what price we're paying here.
This is not true: #[test]
fn resource_component_stable() {
#[derive(Resource)]
struct Foo;
let mut world = World::new();
let component_id = world.register_component::<Foo>();
world.insert_resource(Foo);
let res_id1 = world.resource_entities().get(component_id).copied();
world.remove_resource_by_id(component_id);
world.insert_resource(Foo);
let res_id2 = world.resource_entities().get(component_id).copied();
assert_eq!(res_id1, res_id2); // Currently fails
}If resource entities are meant to be stable then:
|
Or alternatively, have a way to invalidate all of these caches that does not regress perf. |
Res en ResMutRes and ResMut

Objective
See #23039. Resources as components introduced an extra entity lookup for each resource access.
Solution
Store the resource entity in the system param state of
ResandResMut. This is possible because resource entities are stable, so the state doesn't have to be updated.Benchmarking
I quickly ran
and got a frametime of 33.4 ms (on main 34.6 ms). This is a minor reduction, but it might help. Others should double-check that this isn't a fluke, because my benchmarking isn't the most airtight.
Testing
All tests pass.