Print frames per second

Description

In our last change we locked the number of world updates to a fixed rate. However, we still render everytime we receive MainEventsCleared, even if the world hasn't changed.

Depending on whether you have vsync enabled, you'll be rendering at the refresh rate of your monitor, or many thousands of times per second if not.

We can monitor this by incrementing a counter every frame and printing out the aggregate periodically. We can use this value as a crude measure of performance as we try to scale up our world shortly.

Commands

git clone git@github.com:atsheehan/iridium
cd iridium
git checkout a6ce3dc648a55bdd05a04cea5764f5588b50d563
cargo run --release

Code Changes

Modified src/main.rsGitHub

@@ -1,10 +1,12 @@
11 mod math;
22 mod render;
3+ mod time;
34 mod world;
45
56 use std::time::{Duration, Instant};
67
78 use render::Renderer;
9+ use time::FrameCounter;
810 use winit::{
911 event::{ElementState, Event, KeyEvent, WindowEvent},
1012 event_loop::{ControlFlow, EventLoop},
@@ -25,6 +27,7 @@
2527 let mut world = World::new(20, 20);
2628
2729 let mut last_instant = Instant::now();
30+ let mut fps_counter = FrameCounter::new(last_instant);
2831
2932 event_loop.set_control_flow(ControlFlow::Poll);
3033 event_loop
@@ -98,9 +101,11 @@
98101 renderer.set_viewport();
99102 }
100103 Event::AboutToWait => {
101- while Instant::now() - last_instant > FRAME_DURATION {
104+ let mut current_instant = Instant::now();
105+ while current_instant - last_instant > FRAME_DURATION {
102106 world.update();
103107 last_instant += FRAME_DURATION;
108+ current_instant = Instant::now();
104109 }
105110
106111 renderer.set_camera(world.camera());
@@ -111,6 +116,7 @@
111116 }
112117
113118 renderer.present();
119+ fps_counter.finish_frame(current_instant);
114120 }
115121 _ => (),
116122 })
@@ -1,10 +1,12 @@
1 mod math;
2 mod render;
 
3 mod world;
4
5 use std::time::{Duration, Instant};
6
7 use render::Renderer;
 
8 use winit::{
9 event::{ElementState, Event, KeyEvent, WindowEvent},
10 event_loop::{ControlFlow, EventLoop},
@@ -25,6 +27,7 @@
25 let mut world = World::new(20, 20);
26
27 let mut last_instant = Instant::now();
 
28
29 event_loop.set_control_flow(ControlFlow::Poll);
30 event_loop
@@ -98,9 +101,11 @@
98 renderer.set_viewport();
99 }
100 Event::AboutToWait => {
101- while Instant::now() - last_instant > FRAME_DURATION {
 
102 world.update();
103 last_instant += FRAME_DURATION;
 
104 }
105
106 renderer.set_camera(world.camera());
@@ -111,6 +116,7 @@
111 }
112
113 renderer.present();
 
114 }
115 _ => (),
116 })
@@ -1,10 +1,12 @@
1 mod math;
2 mod render;
3+ mod time;
4 mod world;
5
6 use std::time::{Duration, Instant};
7
8 use render::Renderer;
9+ use time::FrameCounter;
10 use winit::{
11 event::{ElementState, Event, KeyEvent, WindowEvent},
12 event_loop::{ControlFlow, EventLoop},
@@ -25,6 +27,7 @@
27 let mut world = World::new(20, 20);
28
29 let mut last_instant = Instant::now();
30+ let mut fps_counter = FrameCounter::new(last_instant);
31
32 event_loop.set_control_flow(ControlFlow::Poll);
33 event_loop
@@ -98,9 +101,11 @@
101 renderer.set_viewport();
102 }
103 Event::AboutToWait => {
104+ let mut current_instant = Instant::now();
105+ while current_instant - last_instant > FRAME_DURATION {
106 world.update();
107 last_instant += FRAME_DURATION;
108+ current_instant = Instant::now();
109 }
110
111 renderer.set_camera(world.camera());
@@ -111,6 +116,7 @@
116 }
117
118 renderer.present();
119+ fps_counter.finish_frame(current_instant);
120 }
121 _ => (),
122 })

Added src/time.rsGitHub

1+ use std::time::{Duration, Instant};
2+
3+ const FPS_INTERVAL: Duration = Duration::from_secs(3);
4+
5+ pub(crate) struct FrameCounter {
6+ last_instant: Instant,
7+ counter: u32,
8+ }
9+
10+ impl FrameCounter {
11+ pub(crate) fn new(start: Instant) -> Self {
12+ Self {
13+ counter: 0,
14+ last_instant: start,
15+ }
16+ }
17+
18+ pub(crate) fn finish_frame(&mut self, current_instant: Instant) {
19+ self.counter += 1;
20+
21+ let time_since_last_printout = current_instant - self.last_instant;
22+
23+ if time_since_last_printout > FPS_INTERVAL {
24+ let frames_per_second = self.counter as f32 / time_since_last_printout.as_secs_f32();
25+ println!("FPS: {}", frames_per_second);
26+
27+ self.counter = 0;
28+ self.last_instant = current_instant;
29+ }
30+ }
31+ }
1+ use std::time::{Duration, Instant};
2+
3+ const FPS_INTERVAL: Duration = Duration::from_secs(3);
4+
5+ pub(crate) struct FrameCounter {
6+ last_instant: Instant,
7+ counter: u32,
8+ }
9+
10+ impl FrameCounter {
11+ pub(crate) fn new(start: Instant) -> Self {
12+ Self {
13+ counter: 0,
14+ last_instant: start,
15+ }
16+ }
17+
18+ pub(crate) fn finish_frame(&mut self, current_instant: Instant) {
19+ self.counter += 1;
20+
21+ let time_since_last_printout = current_instant - self.last_instant;
22+
23+ if time_since_last_printout > FPS_INTERVAL {
24+ let frames_per_second = self.counter as f32 / time_since_last_printout.as_secs_f32();
25+ println!("FPS: {}", frames_per_second);
26+
27+ self.counter = 0;
28+ self.last_instant = current_instant;
29+ }
30+ }
31+ }