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
	 Carter Anderson
						Carter Anderson