new Diagnostics system
This commit is contained in:
		
							parent
							
								
									0073f4a58b
								
							
						
					
					
						commit
						93bf728475
					
				| @ -5,7 +5,8 @@ fn main() { | |||||||
|     App::build() |     App::build() | ||||||
|         .add_defaults() |         .add_defaults() | ||||||
|         .add_system(build_move_system()) |         .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) |         .setup_world(setup) | ||||||
|         .run(); |         .run(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -24,7 +24,6 @@ fn main() { | |||||||
|         .add_system(build_wander_system()) |         .add_system(build_wander_system()) | ||||||
|         .add_system(build_navigate_system()) |         .add_system(build_navigate_system()) | ||||||
|         .add_system(build_move_system()) |         .add_system(build_move_system()) | ||||||
|         .add_system(bevy::diagnostics::build_fps_printer_system()) |  | ||||||
|         .run(); |         .run(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,7 +5,8 @@ fn main() { | |||||||
|     App::build() |     App::build() | ||||||
|         .add_defaults() |         .add_defaults() | ||||||
|         .add_system(build_move_system()) |         .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) |         .setup_world(setup) | ||||||
|         .run(); |         .run(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,7 +5,8 @@ fn main() { | |||||||
|         .add_defaults() |         .add_defaults() | ||||||
|         .setup_world(setup) |         .setup_world(setup) | ||||||
|         .add_system(build_move_system()) |         .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(); |         .run(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ use crate::{ | |||||||
|         draw_target::draw_targets::*, mesh::Mesh, pass::passes::*, pipeline::pipelines::*, |         draw_target::draw_targets::*, mesh::Mesh, pass::passes::*, pipeline::pipelines::*, | ||||||
|         render_resource::resource_providers::*, renderer::Renderer, texture::Texture, *, |         render_resource::resource_providers::*, renderer::Renderer, texture::Texture, *, | ||||||
|     }, |     }, | ||||||
|     ui, |     ui, diagnostic::{Diagnostics, diagnostics}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| use bevy_transform::{prelude::LocalToWorld, transform_system_bundle}; | use bevy_transform::{prelude::LocalToWorld, transform_system_bundle}; | ||||||
| @ -20,7 +20,7 @@ use render_resource::{ | |||||||
|     EntityRenderResourceAssignments, RenderResourceAssignments, |     EntityRenderResourceAssignments, RenderResourceAssignments, | ||||||
| }; | }; | ||||||
| use shader::Shader; | use shader::Shader; | ||||||
| use std::collections::HashMap; | use std::{time::Duration, collections::HashMap}; | ||||||
| 
 | 
 | ||||||
| pub struct AppBuilder { | pub struct AppBuilder { | ||||||
|     pub world: Option<World>, |     pub world: Option<World>, | ||||||
| @ -160,6 +160,7 @@ impl AppBuilder { | |||||||
|     pub fn add_default_resources(&mut self) -> &mut Self { |     pub fn add_default_resources(&mut self) -> &mut Self { | ||||||
|         let resources = self.resources.as_mut().unwrap(); |         let resources = self.resources.as_mut().unwrap(); | ||||||
|         resources.insert(Time::new()); |         resources.insert(Time::new()); | ||||||
|  |         resources.insert(Diagnostics::default()); | ||||||
|         resources.insert(AssetStorage::<Mesh>::new()); |         resources.insert(AssetStorage::<Mesh>::new()); | ||||||
|         resources.insert(AssetStorage::<Texture>::new()); |         resources.insert(AssetStorage::<Texture>::new()); | ||||||
|         resources.insert(AssetStorage::<Shader>::new()); |         resources.insert(AssetStorage::<Shader>::new()); | ||||||
| @ -173,6 +174,18 @@ impl AppBuilder { | |||||||
|         self |         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 |     pub fn batch_types2<T1, T2>(&mut self) -> &mut Self | ||||||
|     where |     where | ||||||
|         T1: 'static, |         T1: 'static, | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ use std::time::{Duration, Instant}; | |||||||
| pub struct Time { | pub struct Time { | ||||||
|     pub delta: Duration, |     pub delta: Duration, | ||||||
|     pub instant: Instant, |     pub instant: Instant, | ||||||
|  |     pub delta_seconds_f64: f64, | ||||||
|     pub delta_seconds: f32, |     pub delta_seconds: f32, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -11,6 +12,7 @@ impl Time { | |||||||
|         Time { |         Time { | ||||||
|             delta: Duration::from_secs(0), |             delta: Duration::from_secs(0), | ||||||
|             instant: Instant::now(), |             instant: Instant::now(), | ||||||
|  |             delta_seconds_f64: 0.0, | ||||||
|             delta_seconds: 0.0, |             delta_seconds: 0.0, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -21,7 +23,8 @@ impl Time { | |||||||
| 
 | 
 | ||||||
|     pub fn stop(&mut self) { |     pub fn stop(&mut self) { | ||||||
|         self.delta = Instant::now() - self.instant; |         self.delta = Instant::now() - self.instant; | ||||||
|         self.delta_seconds = |         self.delta_seconds_f64 = | ||||||
|             self.delta.as_secs() as f32 + (self.delta.subsec_nanos() as f32 / 1.0e9); |             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 app; | ||||||
| pub mod asset; | pub mod asset; | ||||||
| pub mod core; | pub mod core; | ||||||
| pub mod diagnostics; | pub mod diagnostic; | ||||||
| pub mod ecs; | pub mod ecs; | ||||||
| pub mod plugin; | pub mod plugin; | ||||||
| pub mod prelude; | pub mod prelude; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Carter Anderson
						Carter Anderson