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

Added stress test for large ecs worlds #16591

Merged
merged 17 commits into from
Dec 10, 2024

Conversation

Trashtalk217
Copy link
Contributor

@Trashtalk217 Trashtalk217 commented Dec 1, 2024

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 Migrate component_reads_and_writes #16339, but there's no other way to currently do what I'm trying to do.

@Trashtalk217 Trashtalk217 added A-ECS Entities, components, systems, and events C-Performance A change motivated by improving speed, memory usage or compile times C-Benchmarks Stress tests and benchmarks used to measure how fast things are and removed C-Performance A change motivated by improving speed, memory usage or compile times labels Dec 1, 2024
@BenjaminBrienen BenjaminBrienen added D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Needs-Review Needs reviewer attention (from anyone!) to move forward S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Dec 1, 2024
@chescock
Copy link
Contributor

chescock commented Dec 2, 2024

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.

@Trashtalk217
Copy link
Contributor Author

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.

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.

@chescock
Copy link
Contributor

chescock commented Dec 3, 2024

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.

@hymm
Copy link
Contributor

hymm commented Dec 3, 2024

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.

@Trashtalk217
Copy link
Contributor Author

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.

@Trashtalk217 Trashtalk217 changed the title Added benchmark for large schedule Added stress test for large ecs worlds Dec 7, 2024
@Trashtalk217 Trashtalk217 removed the S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged label Dec 7, 2024
Copy link
Contributor

@nakedible nakedible left a comment

Choose a reason for hiding this comment

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

Minor comments, fine to merge as is by me.

examples/stress_tests/many_components.rs Outdated Show resolved Hide resolved
examples/stress_tests/many_components.rs Outdated Show resolved Hide resolved
examples/stress_tests/many_components.rs Show resolved Hide resolved
Copy link
Member

@BD103 BD103 left a comment

Choose a reason for hiding this comment

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

Looks good! Some small nits, but nothing blocking :)

examples/stress_tests/many_components.rs Outdated Show resolved Hide resolved
examples/stress_tests/many_components.rs Outdated Show resolved Hide resolved
examples/stress_tests/many_components.rs Outdated Show resolved Hide resolved
examples/stress_tests/many_components.rs Outdated Show resolved Hide resolved
@BD103 BD103 added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Dec 9, 2024
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Dec 10, 2024
Merged via the queue into bevyengine:main with commit 1f884de Dec 10, 2024
31 of 32 checks passed
@Trashtalk217 Trashtalk217 deleted the scheduling_benchmark branch December 10, 2024 14:48
BD103 added a commit to BD103/bevy that referenced this pull request Dec 10, 2024
# 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](bevyengine#14385 (comment)).

> 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 bevyengine#16339,
but there's no other way to currently do what I'm trying to do.

---------

Co-authored-by: Chris Russell <[email protected]>
Co-authored-by: BD103 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Benchmarks Stress tests and benchmarks used to measure how fast things are D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants