Added benchmark for large schedule
Objective
We currently have no benchmarks for large worlds with many entities, components and systems. Having a benchmark for a world with many components is especially useful for the performance improvements needed for relations. This is also a response to this comment from cart.
I'd like both a small bevy_ecs-scoped executor benchmark that generates thousands of components used by hundreds of systems.
Solution
I use dynamic components and components to construct a benchmark with 2000 components, 4000 systems, and 10000 entities.
Some notes
- ~I use a lot of random entities, which creates unpredictable performance, I should use a seeded PRNG.~
- Not entirely sure if everything is ran concurrently currently. And there are many conflicts, meaning there's probably a lot of first-come-first-serve going on. Not entirely sure if these benchmarks are very reproducible.
- Maybe add some more safety comments
- Also component_reads_and_writes() is about to be deprecated #16339, but there's no other way to currently do what I'm trying to do.
- Also component_reads_and_writes() is about to be deprecated Migrate
component_reads_and_writes#16339, but there's no other way to currently do what I'm trying to do.
One option is to remember access_components yourself. You could give base_system a Local<Vec<ComponentId>> param and build it with LocalBuilder(access_components.collect()), or you could give it an ordinary &[ComponentId] param and do let access_components: Vec<_> = access_components.collect(); then .build_system(move |query: Query<FilteredEntityMut>| base_system(&access_components, query)).
That might also help reduce noise when testing changes to the implementation of Access, since the performance of component_reads_and_writes() will change, but a real system wouldn't be calling it.
- Also component_reads_and_writes() is about to be deprecated Migrate
component_reads_and_writes#16339, but there's no other way to currently do what I'm trying to do.One option is to remember
access_componentsyourself. You could givebase_systemaLocal<Vec<ComponentId>>param and build it withLocalBuilder(access_components.collect()), or you could give it an ordinary&[ComponentId]param and dolet access_components: Vec<_> = access_components.collect();then.build_system(move |query: Query<FilteredEntityMut>| base_system(&access_components, query)).That might also help reduce noise when testing changes to the implementation of
Access, since the performance ofcomponent_reads_and_writes()will change, but a real system wouldn't be calling it.
I'm a fan of passing it as an argument, I'll do that. I'm hesitant to use Locals in this case because that's effectively adding another little bit of complexity (I believe Locals are Resources underneath, not entirely sure) which could potentially add to the variance of the benchmark.
I'm a fan of passing it as an argument, I'll do that. I'm hesitant to use
Locals in this case because that's effectively adding another little bit of complexity (I believe Locals are Resources underneath, not entirely sure) which could potentially add to the variance of the benchmark.
I agree that using a closure is simpler! But in case you're curious: Locals store their value right in the param state, not in a Resource or anything. So accessing them should be just a pointer offset from the system struct, same as a closure capture.
It might be worth trying this as a stress test example since it's so noisy. That way we could bench using tracy and run it for longer to reduce the noise.
Okay, I made some changes and I'm a lot happier with it. Two questions remain:
- I don't like pulling in all DefaultPlugins to be able to log fps, I want to do this with MinimalPlugins, but I have not gotten that to work yet
- Next I'm wondering about the defaults, currently, we have e = 10000, c = 2000, and s = 500, but I'm not sure if that's very representative. It's configurable right now, but I'd like to have the default make some sense. I'm also wondering if the current base_system might be too heavy to be representative.
I'll also do a separate bench for just comparing access comparisons, but that'll be a separate PR.