Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Optimize
wake_on_collision_ended
when large number of collisions ar…
…e occurring (#508) # 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](https://github.com/Jondolf/avian/blob/2f83cc15bd804ad82ecd7e080e337d052d1c3472/src/dynamics/sleeping/mod.rs#L280-L285) - 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](https://github.com/Jondolf/avian/blob/2f83cc15bd804ad82ecd7e080e337d052d1c3472/src/dynamics/sleeping/mod.rs#L280-L285) (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: <img width="569" alt="2500" src="https://github.com/user-attachments/assets/9785ddfb-0270-474a-bfda-c83a830f011e"> ~~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
- Loading branch information