mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
updates on diagnostics (log + new diagnostics) (#1085)
* move print diagnostics to log * entity count diagnostic * asset count diagnostic * remove useless `pub`s * use `BTreeMap` instead of `HashMap` * get entity count from world * keep ordered list of diagnostics
This commit is contained in:
parent
d3d6c35789
commit
b28365f966
17 changed files with 144 additions and 45 deletions
|
@ -191,8 +191,8 @@ name = "custom_diagnostic"
|
|||
path = "examples/diagnostics/custom_diagnostic.rs"
|
||||
|
||||
[[example]]
|
||||
name = "print_diagnostics"
|
||||
path = "examples/diagnostics/print_diagnostics.rs"
|
||||
name = "log_diagnostics"
|
||||
path = "examples/diagnostics/log_diagnostics.rs"
|
||||
|
||||
[[example]]
|
||||
name = "event"
|
||||
|
|
|
@ -19,6 +19,7 @@ filesystem_watcher = ["notify"]
|
|||
[dependencies]
|
||||
# bevy
|
||||
bevy_app = { path = "../bevy_app", version = "0.4.0" }
|
||||
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.4.0" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.4.0" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.4.0", features = ["bevy"] }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.4.0" }
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
use crate::{Asset, Assets};
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_diagnostic::{Diagnostic, DiagnosticId, Diagnostics};
|
||||
use bevy_ecs::{IntoSystem, Res, ResMut};
|
||||
|
||||
/// Adds "asset count" diagnostic to an App
|
||||
#[derive(Default)]
|
||||
pub struct AssetCountDiagnosticsPlugin<T: Asset> {
|
||||
marker: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Asset> Plugin for AssetCountDiagnosticsPlugin<T> {
|
||||
fn build(&self, app: &mut AppBuilder) {
|
||||
app.add_startup_system(Self::setup_system.system())
|
||||
.add_system(Self::diagnostic_system.system());
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Asset> AssetCountDiagnosticsPlugin<T> {
|
||||
pub fn diagnostic_id() -> DiagnosticId {
|
||||
DiagnosticId(T::TYPE_UUID)
|
||||
}
|
||||
|
||||
pub fn setup_system(mut diagnostics: ResMut<Diagnostics>) {
|
||||
diagnostics.add(Diagnostic::new(
|
||||
Self::diagnostic_id(),
|
||||
&format!("asset_count {}", std::any::type_name::<T>()),
|
||||
20,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn diagnostic_system(mut diagnostics: ResMut<Diagnostics>, assets: Res<Assets<T>>) {
|
||||
diagnostics.add_measurement(Self::diagnostic_id(), assets.len() as f64);
|
||||
}
|
||||
}
|
2
crates/bevy_asset/src/diagnostic/mod.rs
Normal file
2
crates/bevy_asset/src/diagnostic/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
mod asset_count_diagnostics_plugin;
|
||||
pub use asset_count_diagnostics_plugin::AssetCountDiagnosticsPlugin;
|
|
@ -1,5 +1,6 @@
|
|||
mod asset_server;
|
||||
mod assets;
|
||||
pub mod diagnostic;
|
||||
#[cfg(all(
|
||||
feature = "filesystem_watcher",
|
||||
all(not(target_arch = "wasm32"), not(target_os = "android"))
|
||||
|
|
|
@ -18,6 +18,7 @@ keywords = ["bevy"]
|
|||
bevy_app = { path = "../bevy_app", version = "0.4.0" }
|
||||
bevy_core = { path = "../bevy_core", version = "0.4.0" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.4.0" }
|
||||
bevy_log = { path = "../bevy_log", version = "0.4.0" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.4.0" }
|
||||
|
||||
# other
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use bevy_utils::{Duration, HashMap, Instant, Uuid};
|
||||
use std::collections::VecDeque;
|
||||
use std::collections::{BTreeSet, VecDeque};
|
||||
|
||||
/// Unique identifier for a [Diagnostic]
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct DiagnosticId(pub Uuid);
|
||||
|
||||
impl DiagnosticId {
|
||||
|
@ -102,10 +102,12 @@ impl Diagnostic {
|
|||
#[derive(Debug, Default)]
|
||||
pub struct Diagnostics {
|
||||
diagnostics: HashMap<DiagnosticId, Diagnostic>,
|
||||
ordered_diagnostics: BTreeSet<DiagnosticId>,
|
||||
}
|
||||
|
||||
impl Diagnostics {
|
||||
pub fn add(&mut self, diagnostic: Diagnostic) {
|
||||
self.ordered_diagnostics.insert(diagnostic.id);
|
||||
self.diagnostics.insert(diagnostic.id, diagnostic);
|
||||
}
|
||||
|
||||
|
@ -132,4 +134,10 @@ impl Diagnostics {
|
|||
pub fn iter(&self) -> impl Iterator<Item = &Diagnostic> {
|
||||
self.diagnostics.values()
|
||||
}
|
||||
|
||||
pub fn ordered_iter(&self) -> impl Iterator<Item = &Diagnostic> {
|
||||
self.ordered_diagnostics
|
||||
.iter()
|
||||
.filter_map(move |k| self.diagnostics.get(k))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
use crate::{Diagnostic, DiagnosticId, Diagnostics};
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_ecs::{IntoSystem, ResMut, Resources, World};
|
||||
|
||||
/// Adds "entity count" diagnostic to an App
|
||||
#[derive(Default)]
|
||||
pub struct EntityCountDiagnosticsPlugin;
|
||||
|
||||
impl Plugin for EntityCountDiagnosticsPlugin {
|
||||
fn build(&self, app: &mut AppBuilder) {
|
||||
app.add_startup_system(Self::setup_system.system())
|
||||
.add_system(Self::diagnostic_system.system());
|
||||
}
|
||||
}
|
||||
|
||||
impl EntityCountDiagnosticsPlugin {
|
||||
pub const ENTITY_COUNT: DiagnosticId =
|
||||
DiagnosticId::from_u128(187513512115068938494459732780662867798);
|
||||
|
||||
pub fn setup_system(mut diagnostics: ResMut<Diagnostics>) {
|
||||
diagnostics.add(Diagnostic::new(Self::ENTITY_COUNT, "entity_count", 20));
|
||||
}
|
||||
|
||||
pub fn diagnostic_system(world: &mut World, resources: &mut Resources) {
|
||||
if let Some(mut diagnostics) = resources.get_mut::<Diagnostics>() {
|
||||
diagnostics.add_measurement(Self::ENTITY_COUNT, world.entity_count() as f64);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
mod diagnostic;
|
||||
mod entity_count_diagnostics_plugin;
|
||||
mod frame_time_diagnostics_plugin;
|
||||
mod print_diagnostics_plugin;
|
||||
mod log_diagnostics_plugin;
|
||||
pub use diagnostic::*;
|
||||
pub use entity_count_diagnostics_plugin::EntityCountDiagnosticsPlugin;
|
||||
pub use frame_time_diagnostics_plugin::FrameTimeDiagnosticsPlugin;
|
||||
pub use print_diagnostics_plugin::PrintDiagnosticsPlugin;
|
||||
pub use log_diagnostics_plugin::LogDiagnosticsPlugin;
|
||||
|
||||
use bevy_app::prelude::*;
|
||||
|
||||
|
|
|
@ -2,24 +2,25 @@ use super::{Diagnostic, DiagnosticId, Diagnostics};
|
|||
use bevy_app::prelude::*;
|
||||
use bevy_core::{Time, Timer};
|
||||
use bevy_ecs::{IntoSystem, Res, ResMut};
|
||||
use bevy_log::{debug, info};
|
||||
use bevy_utils::Duration;
|
||||
|
||||
/// An App Plugin that prints diagnostics to the console
|
||||
pub struct PrintDiagnosticsPlugin {
|
||||
/// An App Plugin that logs diagnostics to the console
|
||||
pub struct LogDiagnosticsPlugin {
|
||||
pub debug: bool,
|
||||
pub wait_duration: Duration,
|
||||
pub filter: Option<Vec<DiagnosticId>>,
|
||||
}
|
||||
|
||||
/// State used by the [PrintDiagnosticsPlugin]
|
||||
pub struct PrintDiagnosticsState {
|
||||
/// State used by the [LogDiagnosticsPlugin]
|
||||
struct LogDiagnosticsState {
|
||||
timer: Timer,
|
||||
filter: Option<Vec<DiagnosticId>>,
|
||||
}
|
||||
|
||||
impl Default for PrintDiagnosticsPlugin {
|
||||
impl Default for LogDiagnosticsPlugin {
|
||||
fn default() -> Self {
|
||||
PrintDiagnosticsPlugin {
|
||||
LogDiagnosticsPlugin {
|
||||
debug: false,
|
||||
wait_duration: Duration::from_secs(1),
|
||||
filter: None,
|
||||
|
@ -27,9 +28,9 @@ impl Default for PrintDiagnosticsPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
impl Plugin for PrintDiagnosticsPlugin {
|
||||
impl Plugin for LogDiagnosticsPlugin {
|
||||
fn build(&self, app: &mut bevy_app::AppBuilder) {
|
||||
app.add_resource(PrintDiagnosticsState {
|
||||
app.add_resource(LogDiagnosticsState {
|
||||
timer: Timer::new(self.wait_duration, true),
|
||||
filter: self.filter.clone(),
|
||||
});
|
||||
|
@ -37,68 +38,66 @@ impl Plugin for PrintDiagnosticsPlugin {
|
|||
if self.debug {
|
||||
app.add_system_to_stage(
|
||||
stage::POST_UPDATE,
|
||||
Self::print_diagnostics_debug_system.system(),
|
||||
Self::log_diagnostics_debug_system.system(),
|
||||
);
|
||||
} else {
|
||||
app.add_system_to_stage(stage::POST_UPDATE, Self::print_diagnostics_system.system());
|
||||
app.add_system_to_stage(stage::POST_UPDATE, Self::log_diagnostics_system.system());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PrintDiagnosticsPlugin {
|
||||
impl LogDiagnosticsPlugin {
|
||||
pub fn filtered(filter: Vec<DiagnosticId>) -> Self {
|
||||
PrintDiagnosticsPlugin {
|
||||
LogDiagnosticsPlugin {
|
||||
filter: Some(filter),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn print_diagnostic(diagnostic: &Diagnostic) {
|
||||
fn log_diagnostic(diagnostic: &Diagnostic) {
|
||||
if let Some(value) = diagnostic.value() {
|
||||
print!("{:<65}: {:<10.6}", diagnostic.name, value);
|
||||
if let Some(average) = diagnostic.average() {
|
||||
print!(" (avg {:.6})", average);
|
||||
info!(
|
||||
"{:<65}: {:<10.6} (avg {:.6})",
|
||||
diagnostic.name, value, average
|
||||
);
|
||||
} else {
|
||||
info!("{:<65}: {:<10.6}", diagnostic.name, value);
|
||||
}
|
||||
|
||||
println!("\n");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_diagnostics_system(
|
||||
mut state: ResMut<PrintDiagnosticsState>,
|
||||
fn log_diagnostics_system(
|
||||
mut state: ResMut<LogDiagnosticsState>,
|
||||
time: Res<Time>,
|
||||
diagnostics: Res<Diagnostics>,
|
||||
) {
|
||||
if state.timer.tick(time.delta_seconds()).finished() {
|
||||
println!("Diagnostics:");
|
||||
println!("{}", "-".repeat(93));
|
||||
if let Some(ref filter) = state.filter {
|
||||
for diagnostic in filter.iter().map(|id| diagnostics.get(*id).unwrap()) {
|
||||
Self::print_diagnostic(diagnostic);
|
||||
Self::log_diagnostic(diagnostic);
|
||||
}
|
||||
} else {
|
||||
for diagnostic in diagnostics.iter() {
|
||||
Self::print_diagnostic(diagnostic);
|
||||
for diagnostic in diagnostics.ordered_iter() {
|
||||
Self::log_diagnostic(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_diagnostics_debug_system(
|
||||
mut state: ResMut<PrintDiagnosticsState>,
|
||||
fn log_diagnostics_debug_system(
|
||||
mut state: ResMut<LogDiagnosticsState>,
|
||||
time: Res<Time>,
|
||||
diagnostics: Res<Diagnostics>,
|
||||
) {
|
||||
if state.timer.tick(time.delta_seconds()).finished() {
|
||||
println!("Diagnostics (Debug):");
|
||||
println!("{}", "-".repeat(93));
|
||||
if let Some(ref filter) = state.filter {
|
||||
for diagnostic in filter.iter().map(|id| diagnostics.get(*id).unwrap()) {
|
||||
println!("{:#?}\n", diagnostic);
|
||||
debug!("{:#?}\n", diagnostic);
|
||||
}
|
||||
} else {
|
||||
for diagnostic in diagnostics.iter() {
|
||||
println!("{:#?}\n", diagnostic);
|
||||
for diagnostic in diagnostics.ordered_iter() {
|
||||
debug!("{:#?}\n", diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -252,9 +252,20 @@ impl Entities {
|
|||
}
|
||||
}
|
||||
|
||||
/// Number of freed entities in `self.meta`
|
||||
pub fn freed_len(&self) -> u32 {
|
||||
self.free_cursor.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Number of reserved entities outside of `self.meta`
|
||||
pub fn pending_len(&self) -> u32 {
|
||||
self.pending.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
// The following three methods allow iteration over `reserved` simultaneous to location
|
||||
// writes. This is a lazy hack, but we only use it in `World::flush` so the complexity and unsafety
|
||||
// involved in producing an `impl Iterator<Item=(u32, &mut Location)>` isn't a clear win.
|
||||
/// Number of reserved entities in `self.meta`
|
||||
pub fn reserved_len(&self) -> u32 {
|
||||
self.reserved_cursor.load(Ordering::Relaxed)
|
||||
}
|
||||
|
|
|
@ -500,6 +500,12 @@ impl World {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn entity_count(&self) -> u32 {
|
||||
self.entities.meta.len() as u32 - self.entities.freed_len()
|
||||
+ self.entities.reserved_len()
|
||||
+ self.entities.pending_len()
|
||||
}
|
||||
|
||||
/// Borrow the `T` component of `entity` without checking if it can be mutated
|
||||
///
|
||||
/// # Safety
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use bevy::{
|
||||
diagnostic::{FrameTimeDiagnosticsPlugin, PrintDiagnosticsPlugin},
|
||||
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||
prelude::*,
|
||||
};
|
||||
use rand::{rngs::StdRng, Rng, SeedableRng};
|
||||
|
@ -12,7 +12,7 @@ fn main() {
|
|||
App::build()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_plugin(FrameTimeDiagnosticsPlugin::default())
|
||||
.add_plugin(PrintDiagnosticsPlugin::default())
|
||||
.add_plugin(LogDiagnosticsPlugin::default())
|
||||
.add_startup_system(setup.system())
|
||||
.add_system(move_cubes.system())
|
||||
.run();
|
||||
|
|
|
@ -108,7 +108,7 @@ Example | File | Description
|
|||
Example | File | Description
|
||||
--- | --- | ---
|
||||
`custom_diagnostic` | [`diagnostics/custom_diagnostic.rs`](./diagnostics/custom_diagnostic.rs) | Shows how to create a custom diagnostic
|
||||
`print_diagnostics` | [`diagnostics/print_diagnostics.rs`](./diagnostics/print_diagnostics.rs) | Add a plugin that prints diagnostics to the console
|
||||
`log_diagnostics` | [`diagnostics/log_diagnostics.rs`](./diagnostics/log_diagnostics.rs) | Add a plugin that logs diagnostics to the console
|
||||
|
||||
## ECS (Entity Component System)
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ fn main() {
|
|||
// .add_plugins_with(HelloWorldPlugins, |group| {
|
||||
// group
|
||||
// .disable::<PrintWorldPlugin>()
|
||||
// .add_before::<PrintHelloPlugin, _>(bevy::diagnostic::PrintDiagnosticsPlugin::default())
|
||||
// .add_before::<PrintHelloPlugin, _>(bevy::diagnostic::LogDiagnosticsPlugin::default())
|
||||
// })
|
||||
.run();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use bevy::{
|
||||
diagnostic::{Diagnostic, DiagnosticId, Diagnostics, PrintDiagnosticsPlugin},
|
||||
diagnostic::{Diagnostic, DiagnosticId, Diagnostics, LogDiagnosticsPlugin},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
|
@ -8,7 +8,7 @@ fn main() {
|
|||
App::build()
|
||||
.add_plugins(DefaultPlugins)
|
||||
// The "print diagnostics" plugin is optional. It just visualizes our diagnostics in the console
|
||||
.add_plugin(PrintDiagnosticsPlugin::default())
|
||||
.add_plugin(LogDiagnosticsPlugin::default())
|
||||
.add_startup_system(setup_diagnostic_system.system())
|
||||
.add_system(my_system.system())
|
||||
.run();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use bevy::{
|
||||
diagnostic::{FrameTimeDiagnosticsPlugin, PrintDiagnosticsPlugin},
|
||||
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
|
@ -9,9 +9,13 @@ fn main() {
|
|||
// Adds frame time diagnostics
|
||||
.add_plugin(FrameTimeDiagnosticsPlugin::default())
|
||||
// Adds a system that prints diagnostics to the console
|
||||
.add_plugin(PrintDiagnosticsPlugin::default())
|
||||
.add_plugin(LogDiagnosticsPlugin::default())
|
||||
// Any plugin can register diagnostics
|
||||
// Uncomment this to add some render resource diagnostics:
|
||||
// .add_plugin(bevy::wgpu::diagnostic::WgpuResourceDiagnosticsPlugin::default())
|
||||
// Uncomment this to add an entity count diagnostics:
|
||||
// .add_plugin(bevy::diagnostic::EntityCountDiagnosticsPlugin::default())
|
||||
// Uncomment this to add an asset count diagnostics:
|
||||
// .add_plugin(bevy::asset::diagnostic::AssetCountDiagnosticsPlugin::<Texture>::default())
|
||||
.run();
|
||||
}
|
Loading…
Reference in a new issue