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

Optimize wake_on_collision_ended when large number of collisions are occurring #508

Merged

Conversation

datael
Copy link
Contributor

@datael datael commented Sep 7, 2024

Objective

  • With a large number of colliding bodies, I was seeing wake_on_collision_ended use almost as much time as run_substep_schedule in some cases
  • I narrowed the slowness down to evaluation of this if condition
    • Evaluating this once takes around 3μs on my laptop which isn't a huge deal on its own, but when there's 2500 colliders it started to add up to multiple milliseconds

Solution

  • In wake_on_collision_ended, skip the body of the first for loop (over sleeping) if the following both hold true:
    • The body does not already have a Sleeping component
    • TimeSleeping is 0.0

I believe this is ok because the side-effects of that loop is to remove the Sleeping component and to reset TimeSleeping to zero, which is exactly the condition it now tests for. Therefore, if the entity is already in that state, there's no point in executing the relatively costly if statement here (as mentioned above).

  • Since it now also already knows if the Sleeping component is present, I gated the commands.entity(entity).remove::<Sleeping>(); calls so that it only adds that command if the component is present

    • This should save a few lookups on Bevy's end, but isn't strictly necessary for this PR
  • It may also be worth gating the sleeping query on Without<SleepingDisabled> but I wasn't sure how correct that was

    • If we think it's worth it, we could add that too so that bodies with sleeping disabled aren't even considered here

Results

Large numbers of colliders (here, 2500) showed a near 1000x improvement in execution time of wake_on_collision_ended, going from multiple milliseconds to a few microseconds when none of the bodies are sleeping:
2500

Performance regressed for small numbers of colliders (here, 100), however this is regression at the microseconds level (3.5μs to 15.5μs median), so I posit that this is a worthy tradeoff:
(removed; I had the traces backwards)


Changelog

  • SleepingPlugin's wake_on_collision_ended system
    • sleeping query now includes Has<Sleeping>
    • first loop in system body skips anything that isn't already sleeping or about to sleep
    • don't remove Sleeping component if Has<Sleeping>resolved to false

To implement the previous commit we added retrieval of whether and entity has a Sleeping component. Since we therefore now already know whether the entity has a Sleeping component, there's no point in trying to remove it if it doesn't
@datael
Copy link
Contributor Author

datael commented Sep 7, 2024

Correction: This is still an improvement for 100 colliders, though as mentioned in the original post it's in the region of microseconds so isn't particularly notable:

Screenshot 2024-09-07 at 19 01 34

@datael
Copy link
Contributor Author

datael commented Sep 7, 2024

Assuming I'm looking at the correct section of the trace, gating the removal of Sleeping on the entity actually having it is also an improvement over previous, but this is even more negligible than the 100 collider case

Screenshot 2024-09-07 at 19 06 31

Copy link
Sponsor Contributor

@janhohenheim janhohenheim left a comment

Choose a reason for hiding this comment

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

Good work, looks sound to me :)

@Jondolf Jondolf added C-Performance Improvements or questions related to performance A-Dynamics Relates to rigid body dynamics: motion, mass, constraint solving, joints, CCD, and so on labels Sep 7, 2024
@datael
Copy link
Contributor Author

datael commented Sep 7, 2024

As a sanity check and to rule out that it wasn't something particular in my scene, this is the move_marbles example in avian2d:

Screenshot 2024-09-07 at 20 03 45

@datael datael marked this pull request as ready for review September 7, 2024 11:05
Copy link
Owner

@Jondolf Jondolf left a comment

Choose a reason for hiding this comment

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

Thank you, the results look great! Just to be sure, I also quickly tested that it didn't break the actual wake-up logic, and it seems to work like normal :)

@Jondolf Jondolf merged commit a5616dd into Jondolf:main Sep 7, 2024
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Dynamics Relates to rigid body dynamics: motion, mass, constraint solving, joints, CCD, and so on C-Performance Improvements or questions related to performance
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants