Building a reactive FPS Counter in Dart
As an example of how to build FRP (functional-reactive program[s]) in Dart, I decided to try building an FPS counter — that is, an utility to determine what the frame rate of a running application is.
I decided I’d like to have a few goals:
- The library, hereby package:fps, should be platform agnostic. That is, I didn’t want to require the use of the browser (requestAnimationFrame) — it should work also in the standalone command-line VM and Flutter.
- I wanted it to be extensible — it should be relatively trivial to get the average FPS over a duration of time so the number doesn’t spike back and forth while running.
- I wanted to be able to specify a target FPS (say 60), and be able to dynamically change that target if it’s clear the application won’t be able to perform.
Here’s what I wanted my API to look like:
Determining frames-per-second means I want to check, at sporadic moments in my application, how long it’s been since I last was able to check. Assume the following:
- Rendering is normally measured in seconds, or how many frames fit
- 1000 milliseconds (ms) is one second
- Time it takes to render a frame is the difference between two timestamps
- We can start with emitting a timestamp every “frame”
In Dart, which is single-threaded and based on an event loop, we’ll assume that if we can get control of the event loop at least once every <duration> (idle time) that all previous work was effectively the frame.
I tried implementing it rather naively — I created a new StreamController, and used Future.delayed (which delegates to a Timer on all platforms) to inform when the next frame is:
Note: This is not always accurate — on web specifically we can do this much better with window.animationFrame, but again, I wanted something that would run cross-platform out of the box.
OK, so instead of adding the timestamp, I need to calculate and output the frames per second. I could have done this inline, but instead to make it yet-more-extensible I’ve implemented it via a simple StreamTransformer, which is code I can use on-top of any Stream via transform:
I now get output something like this:
Looks good! I’ve included the source code and an example repo on github.