Advertisement
Advertisement


Calculating frames per second in a game


Question

What's a good algorithm for calculating frames per second in a game? I want to show it as a number in the corner of the screen. If I just look at how long it took to render the last frame the number changes too fast.

Bonus points if your answer updates each frame and doesn't converge differently when the frame rate is increasing vs decreasing.

2020/07/25
1
110
7/25/2020 1:36:32 PM


This is what I have used in many games.

#define MAXSAMPLES 100
int tickindex=0;
int ticksum=0;
int ticklist[MAXSAMPLES];

/* need to zero out the ticklist array before starting */
/* average will ramp up until the buffer is full */
/* returns average ticks per frame over the MAXSAMPLES last frames */

double CalcAverageTick(int newtick)
{
    ticksum-=ticklist[tickindex];  /* subtract value falling off */
    ticksum+=newtick;              /* add new value */
    ticklist[tickindex]=newtick;   /* save new value so it can be subtracted later */
    if(++tickindex==MAXSAMPLES)    /* inc buffer index */
        tickindex=0;

    /* return average */
    return((double)ticksum/MAXSAMPLES);
}
2017/12/04

Well, certainly

frames / sec = 1 / (sec / frame)

But, as you point out, there's a lot of variation in the time it takes to render a single frame, and from a UI perspective updating the fps value at the frame rate is not usable at all (unless the number is very stable).

What you want is probably a moving average or some sort of binning / resetting counter.

For example, you could maintain a queue data structure which held the rendering times for each of the last 30, 60, 100, or what-have-you frames (you could even design it so the limit was adjustable at run-time). To determine a decent fps approximation you can determine the average fps from all the rendering times in the queue:

fps = # of rendering times in queue / total rendering time

When you finish rendering a new frame you enqueue a new rendering time and dequeue an old rendering time. Alternately, you could dequeue only when the total of the rendering times exceeded some preset value (e.g. 1 sec). You can maintain the "last fps value" and a last updated timestamp so you can trigger when to update the fps figure, if you so desire. Though with a moving average if you have consistent formatting, printing the "instantaneous average" fps on each frame would probably be ok.

Another method would be to have a resetting counter. Maintain a precise (millisecond) timestamp, a frame counter, and an fps value. When you finish rendering a frame, increment the counter. When the counter hits a pre-set limit (e.g. 100 frames) or when the time since the timestamp has passed some pre-set value (e.g. 1 sec), calculate the fps:

fps = # frames / (current time - start time)

Then reset the counter to 0 and set the timestamp to the current time.

2008/09/17

Increment a counter every time you render a screen and clear that counter for some time interval over which you want to measure the frame-rate.

Ie. Every 3 seconds, get counter/3 and then clear the counter.

2008/09/17

There are at least two ways to do it:


The first is the one others have mentioned here before me. I think it's the simplest and preferred way. You just to keep track of

  • cn: counter of how many frames you've rendered
  • time_start: the time since you've started counting
  • time_now: the current time

Calculating the fps in this case is as simple as evaluating this formula:

  • FPS = cn / (time_now - time_start).

Then there is the uber cool way you might like to use some day:

Let's say you have 'i' frames to consider. I'll use this notation: f[0], f[1],..., f[i-1] to describe how long it took to render frame 0, frame 1, ..., frame (i-1) respectively.

Example where i = 3

|f[0]      |f[1]         |f[2]   |
+----------+-------------+-------+------> time

Then, mathematical definition of fps after i frames would be

(1) fps[i]   = i     / (f[0] + ... + f[i-1])

And the same formula but only considering i-1 frames.

(2) fps[i-1] = (i-1) / (f[0] + ... + f[i-2]) 

Now the trick here is to modify the right side of formula (1) in such a way that it will contain the right side of formula (2) and substitute it for it's left side.

Like so (you should see it more clearly if you write it on a paper):

fps[i] = i / (f[0] + ... + f[i-1])
       = i / ((f[0] + ... + f[i-2]) + f[i-1])
       = (i/(i-1)) / ((f[0] + ... + f[i-2])/(i-1) + f[i-1]/(i-1))
       = (i/(i-1)) / (1/fps[i-1] + f[i-1]/(i-1))
       = ...
       = (i*fps[i-1]) / (f[i-1] * fps[i-1] + i - 1)

So according to this formula (my math deriving skill are a bit rusty though), to calculate the new fps you need to know the fps from the previous frame, the duration it took to render the last frame and the number of frames you've rendered.

2011/10/17

This might be overkill for most people, that's why I hadn't posted it when I implemented it. But it's very robust and flexible.

It stores a Queue with the last frame times, so it can accurately calculate an average FPS value much better than just taking the last frame into consideration.

It also allows you to ignore one frame, if you are doing something that you know is going to artificially screw up that frame's time.

It also allows you to change the number of frames to store in the Queue as it runs, so you can test it out on the fly what is the best value for you.

// Number of past frames to use for FPS smooth calculation - because 
// Unity's smoothedDeltaTime, well - it kinda sucks
private int frameTimesSize = 60;
// A Queue is the perfect data structure for the smoothed FPS task;
// new values in, old values out
private Queue<float> frameTimes;
// Not really needed, but used for faster updating then processing 
// the entire queue every frame
private float __frameTimesSum = 0;
// Flag to ignore the next frame when performing a heavy one-time operation 
// (like changing resolution)
private bool _fpsIgnoreNextFrame = false;

//=============================================================================
// Call this after doing a heavy operation that will screw up with FPS calculation
void FPSIgnoreNextFrame() {
    this._fpsIgnoreNextFrame = true;
}

//=============================================================================
// Smoothed FPS counter updating
void Update()
{
    if (this._fpsIgnoreNextFrame) {
        this._fpsIgnoreNextFrame = false;
        return;
    }

    // While looping here allows the frameTimesSize member to be changed dinamically
    while (this.frameTimes.Count >= this.frameTimesSize) {
        this.__frameTimesSum -= this.frameTimes.Dequeue();
    }
    while (this.frameTimes.Count < this.frameTimesSize) {
        this.__frameTimesSum += Time.deltaTime;
        this.frameTimes.Enqueue(Time.deltaTime);
    }
}

//=============================================================================
// Public function to get smoothed FPS values
public int GetSmoothedFPS() {
    return (int)(this.frameTimesSize / this.__frameTimesSum * Time.timeScale);
}
2015/06/23

Source: https://stackoverflow.com/questions/87304
Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Email: [email protected]