-
-
Notifications
You must be signed in to change notification settings - Fork 133
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
Physics Diagnostics #653
Merged
Merged
Physics Diagnostics #653
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- Diagnostics are now stored in resources like `SolverDiagnostics` and `CollisionDiagnostics`. - Timers and counters are updated in the relevant systems, instead of wrapping every timed system with two other system. - Each plugins is responsible for setting up its own diagnostics, but a `PhysicsDiagnostic` trait and `App::register_physics_diagnostics` are used to abstract setup logic for `Diagnostics`. - Added a lot more diagnostics.
…d `bevy_diagnostic` feature
6 tasks
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Objective
Fixes #564.
Expands significantly on #576.
For both benchmarking and optimizing Avian itself, and monitoring physics performance on the user side, it can be very useful to have timing information and various other statistics tracked by the physics engine. This is also done by engines such as Rapier and Box2D.
Solution
Summary:
CollisionDiagnostics
andSolverDiagnostics
.bevy_diagnostic
feature andPhysicsDiagnosticsPlugin
for optionally writing these diagnostics tobevy_diagnostic::DiagnosticsStore
.diagnostic_ui
feature andPhysicsDiagnosticsUiPlugin
for optionally displaying physics diagnostics with a debug UI.Physics Diagnostics Resources
The natural place for diagnostics in Bevy would be
bevy_diagnostic::DiagnosticsStore
. However:f64
, which makes counters a bit more awkward.Thus, most diagnostics are tracked in separate resources such as
SolverDiagnostics
:These are updated in the relevant systems. Timers should have a very small, fixed cost, so they are currently tracked by default and cannot be disabled (same as Box2D), aside from disabling e.g. the
SolverPlugin
itself. If it is deemed to have measurable overhead down the line, we could try putting timers behind a feature flag, though it does add some complexity.Integration With
DiagnosticsStore
It can still be valuable to also record physics diagnostics to
bevy_diagnostic::DiagnosticsStore
to benefit from the history and smoothing functionality, and to monitor things from a single shared resource. This is supported by adding thePhysicsDiagnosticsPlugin
with thebevy_diagnostic
feature enabled.There is some boilerplate required for registering the diagnostics, clearing the timers and counters, and writing them to the
DiagnosticsStore
. To keep things more manageable, this has been abstracted with aPhysicsDiagnostics
trait,register_physics_diagnostics
method, andimpl_diagnostic_paths!
macro.For the earlier
SolverDiagnostics
, the implementation looks like this:The
SolverPlugin
can then simply callapp.register_physics_diagnostics::<SolverDiagnostics>()
, and everything should work automatically. The timers will only be written to theDiagnosticsStore
ifPhysicsDiagnosticsPlugin
is enabled, keeping overhead small if the use ofDiagnosticsStore
is not needed.A nice benefit here is that each plugin is responsible for adding its own diagnostics, rather than there being a single place where all diagnostics are registered and stored. This is nice for modularity, and means that e.g.
SpatialQueryDiagnostics
are only added if theSpatialQueryPlugin
is added.Physics Diagnostics UI
Having all of these diagnostics available is nice, but viewing and displaying them in a useful way involves a decent amount of code and effort.
To make this easier (and prettier), an optional debug UI for displaying physics diagnostics is provided with the
diagnostic_ui
feature andPhysicsDiagnosticsUiPlugin
. It displays all active built-in physics diagnostics in neat groups, with both current and smoothed times shown.The visibility and settings of the UI can be configured using the
PhysicsDiagnosticsUiSettings
.Example Improvements
The
ExampleCommonPlugin
has been updated to replace the FPS counter with these physics diagnostics, and there are now text instructions to show what the different keys do.The diagnostics UI is hidden by default in the examples.
Differences to #576
#576 by @ptsd has an initial WIP diagnostics implementation with a simpler approach that more closely matches my original proposal in #564. It was a valuable base to build this PR on top of, but as I iterated on it, I ultimately went with quite a different approach.
That PR used a single
PhysicsDiagnosticsPlugin
that set up all diagnostics manually. Timers were implemented by adding system sets before and after various parts of the simulation, and adding systems there to record spans, which were then written to theDiagnosticsStore
.I didn't go with this approach, because:
Instead, I simply have each plugin define its own resource for its diagnostics where relevant. Timers are handled by tracking elapsed time inside systems with
bevy::utils::Instant
(for wide platform support), and stored asDuration
s. Writing this information to theDiagnosticsStore
is optional.This is more modular, has less overhead, and works with substepping. It does add some complexity to the actual diagnostic management though, and makes diagnostics more spread out over the codebase, for better and for worse.