 3507b21dce
			
		
	
	
		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>`.
		
	
			
		
			
				
	
	
		
			25 lines
		
	
	
		
			806 B
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			25 lines
		
	
	
		
			806 B
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use bevy_app::prelude::*;
 | |
| use bevy_ecs::entity::Entities;
 | |
| 
 | |
| use crate::{Diagnostic, DiagnosticId, Diagnostics, RegisterDiagnostic};
 | |
| 
 | |
| /// Adds "entity count" diagnostic to an App
 | |
| #[derive(Default)]
 | |
| pub struct EntityCountDiagnosticsPlugin;
 | |
| 
 | |
| impl Plugin for EntityCountDiagnosticsPlugin {
 | |
|     fn build(&self, app: &mut App) {
 | |
|         app.register_diagnostic(Diagnostic::new(Self::ENTITY_COUNT, "entity_count", 20))
 | |
|             .add_systems(Update, Self::diagnostic_system);
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl EntityCountDiagnosticsPlugin {
 | |
|     pub const ENTITY_COUNT: DiagnosticId =
 | |
|         DiagnosticId::from_u128(187513512115068938494459732780662867798);
 | |
| 
 | |
|     pub fn diagnostic_system(mut diagnostics: Diagnostics, entities: &Entities) {
 | |
|         diagnostics.add_measurement(Self::ENTITY_COUNT, || entities.len() as f64);
 | |
|     }
 | |
| }
 |