mirror of
https://github.com/bevyengine/bevy
synced 2024-12-23 19:43:07 +00:00
3507b21dce
# Objective I was trying to add some `Diagnostics` to have a better break down of performance but I noticed that the current implementation uses a `ResMut` which forces the functions to all run sequentially whereas before they could run in parallel. This created too great a performance penalty to be usable. ## Solution This PR reworks how the diagnostics work with a couple of breaking changes. The idea is to change how `Diagnostics` works by changing it to a `SystemParam`. This allows us to hold a `Deferred` buffer of measurements that can be applied later, avoiding the need for multiple mutable references to the hashmap. This means we can run systems that write diagnostic measurements in parallel. Firstly, we rename the old `Diagnostics` to `DiagnosticsStore`. This clears up the original name for the new interface while allowing us to preserve more closely the original API. Then we create a new `Diagnostics` struct which implements `SystemParam` and contains a deferred `SystemBuffer`. This can be used very similar to the old `Diagnostics` for writing new measurements. ```rust fn system(diagnostics: ResMut<Diagnostics>) { diagnostics.new_measurement(ID, || 10.0)} // changes to fn system(mut diagnostics: Diagnostics) { diagnostics.new_measurement(ID, || 10.0)} ``` For reading the diagnostics, the user needs to change from `Diagnostics` to `DiagnosticsStore` but otherwise the function calls are the same. Finally, we add a new method to the `App` for registering diagnostics. This replaces the old method of creating a startup system and adding it manually. Testing it, this PR does indeed allow Diagnostic systems to be run in parallel. ## Changelog - Change `Diagnostics` to implement `SystemParam` which allows diagnostic systems to run in parallel. ## Migration Guide - Register `Diagnostic`'s using the new `app.register_diagnostic(Diagnostic::new(DIAGNOSTIC_ID, "diagnostic_name", 10));` - In systems for writing new measurements, change `mut diagnostics: ResMut<Diagnostics>` to `mut diagnostics: Diagnostics` to allow the systems to run in parallel. - In systems for reading measurements, change `diagnostics: Res<Diagnostics>` to `diagnostics: Res<DiagnosticsStore>`.
47 lines
1.6 KiB
Rust
47 lines
1.6 KiB
Rust
use crate::{Diagnostic, DiagnosticId, Diagnostics, RegisterDiagnostic};
|
|
use bevy_app::prelude::*;
|
|
use bevy_core::FrameCount;
|
|
use bevy_ecs::prelude::*;
|
|
use bevy_time::Time;
|
|
|
|
/// Adds "frame time" diagnostic to an App, specifically "frame time", "fps" and "frame count"
|
|
#[derive(Default)]
|
|
pub struct FrameTimeDiagnosticsPlugin;
|
|
|
|
impl Plugin for FrameTimeDiagnosticsPlugin {
|
|
fn build(&self, app: &mut bevy_app::App) {
|
|
app.register_diagnostic(
|
|
Diagnostic::new(Self::FRAME_TIME, "frame_time", 20).with_suffix("ms"),
|
|
)
|
|
.register_diagnostic(Diagnostic::new(Self::FPS, "fps", 20))
|
|
.register_diagnostic(
|
|
Diagnostic::new(Self::FRAME_COUNT, "frame_count", 1).with_smoothing_factor(0.0),
|
|
)
|
|
.add_systems(Update, Self::diagnostic_system);
|
|
}
|
|
}
|
|
|
|
impl FrameTimeDiagnosticsPlugin {
|
|
pub const FPS: DiagnosticId = DiagnosticId::from_u128(288146834822086093791974408528866909483);
|
|
pub const FRAME_COUNT: DiagnosticId =
|
|
DiagnosticId::from_u128(54021991829115352065418785002088010277);
|
|
pub const FRAME_TIME: DiagnosticId =
|
|
DiagnosticId::from_u128(73441630925388532774622109383099159699);
|
|
|
|
pub fn diagnostic_system(
|
|
mut diagnostics: Diagnostics,
|
|
time: Res<Time>,
|
|
frame_count: Res<FrameCount>,
|
|
) {
|
|
diagnostics.add_measurement(Self::FRAME_COUNT, || frame_count.0 as f64);
|
|
|
|
let delta_seconds = time.raw_delta_seconds_f64();
|
|
if delta_seconds == 0.0 {
|
|
return;
|
|
}
|
|
|
|
diagnostics.add_measurement(Self::FRAME_TIME, || delta_seconds * 1000.0);
|
|
|
|
diagnostics.add_measurement(Self::FPS, || 1.0 / delta_seconds);
|
|
}
|
|
}
|