new Diagnostics system
This commit is contained in:
parent
0073f4a58b
commit
93bf728475
@ -5,7 +5,8 @@ fn main() {
|
||||
App::build()
|
||||
.add_defaults()
|
||||
.add_system(build_move_system())
|
||||
.add_system(bevy::diagnostics::build_fps_printer_system())
|
||||
.add_default_diagnostics()
|
||||
.print_diagnostics(std::time::Duration::from_secs_f64(1.0))
|
||||
.setup_world(setup)
|
||||
.run();
|
||||
}
|
||||
|
||||
@ -24,7 +24,6 @@ fn main() {
|
||||
.add_system(build_wander_system())
|
||||
.add_system(build_navigate_system())
|
||||
.add_system(build_move_system())
|
||||
.add_system(bevy::diagnostics::build_fps_printer_system())
|
||||
.run();
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,8 @@ fn main() {
|
||||
App::build()
|
||||
.add_defaults()
|
||||
.add_system(build_move_system())
|
||||
.add_system(bevy::diagnostics::build_fps_printer_system())
|
||||
.add_default_diagnostics()
|
||||
.print_diagnostics(std::time::Duration::from_secs_f64(1.0))
|
||||
.setup_world(setup)
|
||||
.run();
|
||||
}
|
||||
|
||||
@ -5,7 +5,8 @@ fn main() {
|
||||
.add_defaults()
|
||||
.setup_world(setup)
|
||||
.add_system(build_move_system())
|
||||
.add_system(bevy::diagnostics::build_fps_printer_system())
|
||||
.add_default_diagnostics()
|
||||
.print_diagnostics(std::time::Duration::from_secs_f64(1.0))
|
||||
.run();
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ use crate::{
|
||||
draw_target::draw_targets::*, mesh::Mesh, pass::passes::*, pipeline::pipelines::*,
|
||||
render_resource::resource_providers::*, renderer::Renderer, texture::Texture, *,
|
||||
},
|
||||
ui,
|
||||
ui, diagnostic::{Diagnostics, diagnostics},
|
||||
};
|
||||
|
||||
use bevy_transform::{prelude::LocalToWorld, transform_system_bundle};
|
||||
@ -20,7 +20,7 @@ use render_resource::{
|
||||
EntityRenderResourceAssignments, RenderResourceAssignments,
|
||||
};
|
||||
use shader::Shader;
|
||||
use std::collections::HashMap;
|
||||
use std::{time::Duration, collections::HashMap};
|
||||
|
||||
pub struct AppBuilder {
|
||||
pub world: Option<World>,
|
||||
@ -160,6 +160,7 @@ impl AppBuilder {
|
||||
pub fn add_default_resources(&mut self) -> &mut Self {
|
||||
let resources = self.resources.as_mut().unwrap();
|
||||
resources.insert(Time::new());
|
||||
resources.insert(Diagnostics::default());
|
||||
resources.insert(AssetStorage::<Mesh>::new());
|
||||
resources.insert(AssetStorage::<Texture>::new());
|
||||
resources.insert(AssetStorage::<Shader>::new());
|
||||
@ -173,6 +174,18 @@ impl AppBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_default_diagnostics(&mut self) -> &mut Self {
|
||||
let frame_time_diagnostic_system = {
|
||||
let resources = self.resources.as_mut().unwrap();
|
||||
diagnostics::frame_time_diagnostic_system(resources, 10)
|
||||
};
|
||||
self.add_system(frame_time_diagnostic_system)
|
||||
}
|
||||
|
||||
pub fn print_diagnostics(&mut self, wait: Duration) -> &mut Self {
|
||||
self.add_system(diagnostics::print_diagnostics_system(wait))
|
||||
}
|
||||
|
||||
pub fn batch_types2<T1, T2>(&mut self) -> &mut Self
|
||||
where
|
||||
T1: 'static,
|
||||
|
||||
@ -3,6 +3,7 @@ use std::time::{Duration, Instant};
|
||||
pub struct Time {
|
||||
pub delta: Duration,
|
||||
pub instant: Instant,
|
||||
pub delta_seconds_f64: f64,
|
||||
pub delta_seconds: f32,
|
||||
}
|
||||
|
||||
@ -11,6 +12,7 @@ impl Time {
|
||||
Time {
|
||||
delta: Duration::from_secs(0),
|
||||
instant: Instant::now(),
|
||||
delta_seconds_f64: 0.0,
|
||||
delta_seconds: 0.0,
|
||||
}
|
||||
}
|
||||
@ -21,7 +23,8 @@ impl Time {
|
||||
|
||||
pub fn stop(&mut self) {
|
||||
self.delta = Instant::now() - self.instant;
|
||||
self.delta_seconds =
|
||||
self.delta.as_secs() as f32 + (self.delta.subsec_nanos() as f32 / 1.0e9);
|
||||
self.delta_seconds_f64 =
|
||||
self.delta.as_secs() as f64 + (self.delta.subsec_nanos() as f64 / 1.0e9);
|
||||
self.delta_seconds = self.delta_seconds_f64 as f32;
|
||||
}
|
||||
}
|
||||
|
||||
94
src/diagnostic/diagnostics.rs
Normal file
94
src/diagnostic/diagnostics.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use super::{Diagnostic, DiagnosticId, Diagnostics};
|
||||
use crate::{
|
||||
core::Time,
|
||||
prelude::{Resources, SystemBuilder},
|
||||
};
|
||||
use legion::prelude::Schedulable;
|
||||
use std::time::Duration;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub const FPS: DiagnosticId = DiagnosticId(Uuid::from_bytes([
|
||||
157, 191, 0, 72, 223, 223, 70, 128, 137, 117, 54, 177, 132, 13, 170, 124,
|
||||
]));
|
||||
|
||||
pub const FRAME_TIME: DiagnosticId = DiagnosticId(Uuid::from_bytes([
|
||||
216, 184, 55, 12, 28, 116, 69, 201, 187, 137, 176, 77, 83, 89, 251, 241,
|
||||
]));
|
||||
|
||||
pub fn frame_time_diagnostic_system(
|
||||
resources: &Resources,
|
||||
max_history_length: usize,
|
||||
) -> Box<dyn Schedulable> {
|
||||
let mut diagnostics = resources.get_mut::<Diagnostics>().unwrap();
|
||||
diagnostics.add(Diagnostic::new(
|
||||
FRAME_TIME,
|
||||
"frame_time",
|
||||
max_history_length,
|
||||
));
|
||||
diagnostics.add(Diagnostic::new(FPS, "fps", max_history_length));
|
||||
SystemBuilder::new("FrameTimeDiagnostic")
|
||||
.read_resource::<Time>()
|
||||
.write_resource::<Diagnostics>()
|
||||
.build(move |_, _world, (time, ref mut diagnostics), _queries| {
|
||||
if time.delta_seconds_f64 == 0.0 {
|
||||
return;
|
||||
}
|
||||
|
||||
diagnostics.add_measurement(FRAME_TIME, time.delta_seconds_f64);
|
||||
if let Some(fps) = diagnostics
|
||||
.get(FRAME_TIME)
|
||||
.and_then(|frame_time_diagnostic| {
|
||||
frame_time_diagnostic
|
||||
.average()
|
||||
.and_then(|frame_time_average| {
|
||||
if frame_time_average > 0.0 {
|
||||
Some(1.0 / frame_time_average)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
{
|
||||
diagnostics.add_measurement(FPS, fps);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn print_diagnostics_system(wait: Duration) -> Box<dyn Schedulable> {
|
||||
let mut elasped = 0.0;
|
||||
let wait_seconds = wait.as_secs_f64();
|
||||
SystemBuilder::new("PrintDiagnostics")
|
||||
.read_resource::<Time>()
|
||||
.read_resource::<Diagnostics>()
|
||||
.build(move |_, _world, (time, diagnostics), _queries| {
|
||||
elasped += time.delta_seconds_f64;
|
||||
if elasped >= wait_seconds {
|
||||
elasped = 0.0;
|
||||
for diagnostic in diagnostics.iter() {
|
||||
if let Some(value) = diagnostic.value() {
|
||||
println!("{}: {}", diagnostic.name, value);
|
||||
if let Some(average) = diagnostic.average() {
|
||||
println!(" average: {}", average);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn print_diagnostics_debug_system(wait: Duration) -> Box<dyn Schedulable> {
|
||||
let mut elasped = 0.0;
|
||||
let wait_seconds = wait.as_secs_f64();
|
||||
SystemBuilder::new("PrintDiagnostics")
|
||||
.read_resource::<Time>()
|
||||
.read_resource::<Diagnostics>()
|
||||
.build(move |_, _world, (time, diagnostics), _queries| {
|
||||
elasped += time.delta_seconds_f64;
|
||||
if elasped >= wait_seconds {
|
||||
elasped = 0.0;
|
||||
for diagnostic in diagnostics.iter() {
|
||||
println!("{:#?}\n", diagnostic);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
124
src/diagnostic/mod.rs
Normal file
124
src/diagnostic/mod.rs
Normal file
@ -0,0 +1,124 @@
|
||||
pub mod diagnostics;
|
||||
|
||||
use std::{
|
||||
collections::{HashMap, VecDeque},
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
|
||||
pub struct DiagnosticId(Uuid);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DiagnosticMeasurement {
|
||||
pub time: SystemTime,
|
||||
pub value: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Diagnostic {
|
||||
pub id: DiagnosticId,
|
||||
pub name: String,
|
||||
history: VecDeque<DiagnosticMeasurement>,
|
||||
sum: f64,
|
||||
max_history_length: usize,
|
||||
}
|
||||
|
||||
impl Diagnostic {
|
||||
pub fn add_measurement(&mut self, value: f64) {
|
||||
let time = SystemTime::now();
|
||||
if self.history.len() == self.max_history_length {
|
||||
if let Some(removed_diagnostic) = self.history.pop_back() {
|
||||
self.sum -= removed_diagnostic.value;
|
||||
}
|
||||
}
|
||||
|
||||
self.sum += value;
|
||||
self.history.push_front(DiagnosticMeasurement {
|
||||
time,
|
||||
value,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn new(id: DiagnosticId, name: &str, max_history_length: usize) -> Diagnostic {
|
||||
Diagnostic {
|
||||
id,
|
||||
name: name.to_string(),
|
||||
history: VecDeque::with_capacity(max_history_length),
|
||||
max_history_length,
|
||||
sum: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value(&self) -> Option<f64> {
|
||||
self.history.back().map(|measurement| measurement.value)
|
||||
}
|
||||
|
||||
pub fn sum(&self) -> f64 {
|
||||
self.sum
|
||||
}
|
||||
|
||||
pub fn average(&self) -> Option<f64> {
|
||||
if self.history.len() > 0 {
|
||||
Some(self.sum / self.history.len() as f64)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn history_len(&self) -> usize {
|
||||
self.history.len()
|
||||
}
|
||||
|
||||
pub fn duration(&self) -> Option<Duration> {
|
||||
if self.history.len() < 2 {
|
||||
return None
|
||||
}
|
||||
|
||||
if let Some(oldest) = self.history.back() {
|
||||
if let Some(newest) = self.history.front() {
|
||||
return newest.time.duration_since(oldest.time).ok()
|
||||
}
|
||||
}
|
||||
|
||||
return None
|
||||
}
|
||||
|
||||
pub fn get_max_history_length(&self) -> usize {
|
||||
self.max_history_length
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Diagnostics {
|
||||
diagnostics: HashMap<DiagnosticId, Diagnostic>,
|
||||
}
|
||||
|
||||
impl Diagnostics {
|
||||
pub fn add(&mut self, diagnostic: Diagnostic) {
|
||||
self.diagnostics.insert(diagnostic.id, diagnostic);
|
||||
}
|
||||
|
||||
pub fn get(&self, id: DiagnosticId) -> Option<&Diagnostic> {
|
||||
self.diagnostics.get(&id)
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, id: DiagnosticId) -> Option<&mut Diagnostic> {
|
||||
self.diagnostics.get_mut(&id)
|
||||
}
|
||||
|
||||
pub fn get_measurement(&self, id: DiagnosticId) -> Option<&DiagnosticMeasurement> {
|
||||
self.diagnostics.get(&id).and_then(|diagnostic| diagnostic.history.front())
|
||||
}
|
||||
|
||||
pub fn add_measurement(&mut self, id: DiagnosticId, value: f64) {
|
||||
if let Some(diagnostic) = self.diagnostics.get_mut(&id) {
|
||||
diagnostic.add_measurement(value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item=&Diagnostic> {
|
||||
self.diagnostics.values()
|
||||
}
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
use crate::{core::Time, prelude::SystemBuilder};
|
||||
use legion::prelude::Schedulable;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
pub fn build_fps_printer_system() -> Box<dyn Schedulable> {
|
||||
let mut elapsed = 0.0;
|
||||
let mut frame_time_total = 0.0;
|
||||
let mut frame_time_count = 0;
|
||||
let frame_time_max = 10;
|
||||
let mut frame_time_values = VecDeque::new();
|
||||
SystemBuilder::new("FpsPrinter")
|
||||
.read_resource::<Time>()
|
||||
.build(move |_, _world, time, _queries| {
|
||||
elapsed += time.delta_seconds;
|
||||
frame_time_values.push_front(time.delta_seconds);
|
||||
frame_time_total += time.delta_seconds;
|
||||
frame_time_count += 1;
|
||||
if frame_time_count > frame_time_max {
|
||||
frame_time_count = frame_time_max;
|
||||
frame_time_total -= frame_time_values.pop_back().unwrap();
|
||||
}
|
||||
if elapsed > 1.0 {
|
||||
if frame_time_count > 0 && frame_time_total > 0.0 {
|
||||
println!(
|
||||
"fps: {}",
|
||||
1.0 / (frame_time_total / frame_time_count as f32)
|
||||
)
|
||||
}
|
||||
elapsed = 0.0;
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
pub mod app;
|
||||
pub mod asset;
|
||||
pub mod core;
|
||||
pub mod diagnostics;
|
||||
pub mod diagnostic;
|
||||
pub mod ecs;
|
||||
pub mod plugin;
|
||||
pub mod prelude;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user