How to Implement an FPS Counter

Learn why common FPS calculation methods fail and how to implement a robust rolling window approach for accurate performance monitoring.
How to Implement an FPS Counter
Posted: 2025-08-17
Updated: 2025-09-17
TL;DR: Don’t base your FPS calculations on a specific number of frames. Instead, maintain a rolling window of frames that happened during the last second. Use precise timers. Read on for more details.
I mentioned this in my post about the GMTK Game Jam 2025, but I wanted to cover it in detail.
Let’s say you want to display an FPS counter in your game, which you’ve seen many games do. First, let’s ask ourselves what it is that we want this piece of data to show us. We want to know how the game performs and whether it is, within most recent history, hitting the target of 30 or 60 FPS.
Sure, but then why don’t we just measure the amount of time it takes to process each frame? For 60 FPS, each frame needs to be prepared and rendered in less than 16.67 milliseconds. If we are consistently below that, we’re good. Well, FPS is a metric commonly shown to players and it’s widely accepted in the industry as a proxy for performance.
So, what we want to know is how quickly the game is able to produce new frames, but we’re going to display it as this proxy measure. And that is fine, so how do we do it?
If you search online for how to implement an FPS counter, you’ll probably run into one of the following methods, which I don’t think are the right approach.
Wrong ways
Method 1: FPS based on the latest frame
The pseudo-code would look like this:
float fps = 0;
Time prev = Time::current();
while (true) {
// handle input
// update game state
// render game and show FPS in UI
Time curr = Time::current();
fps = Duration::seconds(1) / (curr - prev);
prev = curr;
}
If we go back to thinking in terms of frame processing times, what is this telling us? It tells us the time it took to produce the latest frame. And that may be a useful thing to know. But if we care about the time taken for each individual frame, why not log all of them in a file for future analysis? If a single frame is really fast or really slow, the FPS counter will indicate that for a single frame, than come back to a normal value, and we most likely won’t notice.
FPS, by its name, is an aggregate measure, so we should be aggregating across multiple frames.
Method 2: FPS based on N latest frames
This method tracks the processing times for several most recent frames (eg. 5 or 10 of them) and displays an FPS based on the rolling average. One way to pseudo-code this would be:
const int windowFrames = ...;
float fps = 0;
Queue<Duration> processingTimes;
Time prev = Time::current();
while (true) {
// handle input
// update game state
// render game and show FPS in UI
Time curr = Time::current();
if (processingTimes.size() == windowFrames) processingTimes.pop();
processingTimes.push(curr - prev);
fps = Duration::seconds(1) / averageVal(processingTimes);
prev = curr;
}
We want to measure FPS based on the most recent performance history. What is the time length of this history? It depends on how quickly the frames are produced. So, the history size along which we measure depends on the values that are being measured!
Imagine what an FPS graph would look like, the x-axis being time and the y-axis being FPS. Well, it would be one misleading graph, as each value on the y-axis would have a dependency on itself since its own value extends how far back along the x-axis it looks.
OK way
Method 3: FPS based on one second, resetting each second
Another way to measure FPS you may find online is:
float fps = 0;
int frames = 0;
Time prev = Time::current();
while (true) {
// handle input
// update game state
// render game and show FPS in UI
Time curr = Time::current();
if (prev + Duration::seconds(1) < curr) {
fps = frames;
frames = 0;
while (prev + Duration::seconds(1) < curr) {
prev += Duration::seconds(1);
}
}
++frames;
}
What does this show us? It shows us how many frames get rendered each second, but it’s only updated each second. And this is mostly correct for what it’s supposed to show.
Right ways
Method 4: FPS based on frames within a rolling window
With all of that out of the way, the code is actually simple:
const Duration window = ...;
float fps = 0;
Queue<Time> frameTimestamps;
while (true) {
// handle input
// update game state
// render game and show FPS in UI
Time curr = Time::current();
frameTimestamps.push(curr);
while (frameTimestamps.next() + window < curr) frameTimestamps.pop();
fps = frameTimestamps.size() * Duration::seconds(1) / window;
}
A queue stores timestamps of the most recent frame completions. On each update, all frames that are further in the past than a single window are discarded.
Source: Hacker News















