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.

The end result after building package:fps.

I decided I’d like to have a few goals:

  1. 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.
  2. 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.
  3. 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:

A simple interface — let the user call eachFrame to get a Stream of frame events.

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:

I ended up printing 10 timestamps, which is not exactly what I wanted.
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:

60
60
60
60
60
60
60
60
60

Looks good! I’ve included the source code and an example repo on github.