iDevGames Forums
Best way to calculate framerate - Printable Version

+- iDevGames Forums (http://www.idevgames.com/forums)
+-- Forum: Development Zone (/forum-3.html)
+--- Forum: Game Programming Fundamentals (/forum-7.html)
+--- Thread: Best way to calculate framerate (/thread-3912.html)

Pages: 1 2


Best way to calculate framerate - ferum - Sep 5, 2006 07:06 AM

My program is based in SDL with fixed-interval game update cycles (like this), and written in C. I was wondering how best to calculate the framerate.

The only way that I could think of would be to have an int FPS that was incremented after every call to my display function, then have an SDL timer that fired every second that printed the number and set it back to zero.

What is the best way to do it?


Best way to calculate framerate - TomorrowPlusX - Sep 5, 2006 07:53 AM

This works pretty well for me, but I doubt it's the "best".

Code:
void Application::postDisplay( void )
{
    static unsigned int frameCounter = 1;
    static float lastCheckTime = 0;
    
    float elapsed = simtime::now() - lastCheckTime;
    if ( elapsed > 1.0 )
    {
        _currentFPS = (float) frameCounter / (float) elapsed;

        lastCheckTime = simtime::now();
        frameCounter = 0;
    }

    ++frameCounter;
}

It's called from the function Application::loop() which is called continuously from a timer.

Code:
void Application::loop( void )
{
    if ( !_ready ) return;
    
    /*
        Run our keys
    */
    if ( !_suppressKeys )
    {
        KeyVec::iterator it( _keys.begin() ), end( _keys.end() );
        for ( ; it != end; ++it ) it->match();
    }

    /*
        Update time and find out how much time
        has elapsed since last iteration of loop.
        
        Then add whatever was left over from last iteration.
    */

    _currentTime = CFAbsoluteTimeGetCurrent();
    
    float dt = _currentTime - _lastTime;
    _lastTime = _currentTime;

    float availableTime = dt + _timeRemainder;    
    if ( availableTime < simtime::interval() )
    {
        _timeRemainder += dt;
    }
    else
    {
        float steps = availableTime / simtime::interval();
        int numSteps = lrintf( steps );
        
        for ( int i=0; i < numSteps && !_performingPostRedisplay; i++ )
        {
            /*
                Update time, run timers, step.
            */
            
            simtime::update();
            processTimers();
            step();
            _hud->step();

            postStep();
        }

        /*
            Increment remainder
        */
        _timeRemainder = (steps - float( numSteps )) * simtime::interval();
    }

    /*
        We always draw, in the end.
    */

    display();
    _hud->display();    

    postDisplay();
}



Best way to calculate framerate - ferum - Sep 5, 2006 10:26 AM

hmm... I don't know C++, What does "::" mean?


Best way to calculate framerate - aarku - Sep 5, 2006 10:35 AM

http://www.unifycommunity.com/wiki/index.php?title=FramesPerSecond

Read the comments there. That's the best way I've used. (No complaints!)

-Jon


Best way to calculate framerate - akb825 - Sep 5, 2006 12:17 PM

Um... that's JavaScript... Last I heard, SDL doesn't work too well with JavaScript. Wink

If you're using C, I suggest using gettimeofday. Here's a little snippet of code that should work.
Code:
double lastTime, currentTime, fps;
struct timeval time;
gettimeofday(&time, NULL);
lastTime = time.tv_sec + time.tv_usec*1e-6;
...
//in render loop
gettimeofday(&time, NULL);
currentTime = time.tv_sec + time.tv_usec*1e-6;
fps = 1/(currentTime - lastTime);
lastTime = currentTime;
lastTime and currentTime must be doubles (floats don't have enough precision), but fps could potentially be a float if you want.

BTW, to answer your question about C++, :: is scope resolution, whether with a class or namespace.


Best way to calculate framerate - ferum - Sep 5, 2006 12:25 PM

Ok what's wrong with my port of that code to non-Unity-dependent C?
It keeps telling me the frame rate is either 1, less than 1, or infinity.
here's my port:
Code:
#define updateInterval 0.5
float accum = 0.0;
int frames = 0;
float timeLeft = updateInterval;
double FPS_lastFrameTime;
    
void FPSupdate (void)
{
    timeLeft -= (currentTime - FPS_lastFrameTime);
    accum += 1 / (currentTime - FPS_lastFrameTime);
    ++frames;
    FPS_lastFrameTime = currentTime;
    if(timeLeft <= 0.0)
    {
        printf("%f\n", (accum / frames));
        timeLeft = updateInterval;
        accum = 0.0;
        frames = 0;
    }
    return;
}

currentTime and FPS_lastFrameTime are in milliseconds, and FPSupdate is called at the end of my display function.


Best way to calculate framerate - akb825 - Sep 5, 2006 01:43 PM

First off, if your times are in milliseconds, you should be subtracting timeLeft by (currentTime - FPS_lastFrameTime)/1000.0f, and you should be adding accum by 1000.0f/(currentTime - FPS_lastFrameTime). If your program is going over 1000 fps, you will get an infinite framerate at times, as well, since the difference is 0. (very possible if it's a simple program) Also, the problem with doing everything in milliseconds is it's usually too rough of an interval. (for example, if it takes 9 ms for a render, it's going at 111.111 fps, while if it takes 10 ms it's going at 100 fps) The advantage of using my method is it theoretically has 1000 times the precision since it has a resolution down to 1 microsecond, and everything is already done in seconds.


Best way to calculate framerate - PowerMacX - Sep 5, 2006 07:37 PM

Here is what I use:
Code:
void Game::CalculateFPS()
{
    static float lastTime = 0.0f;
    float currentTime = SDL_GetTicks();
    _fps = _fps*0.9+(100.0f/(currentTime - lastTime));
    lastTime = currentTime;
}

In plain C, it would look something like this:
Code:
float getFPS()
{
    static float fps = 0.0f;
    static float lastTime = 0.0f;
    float currentTime = SDL_GetTicks();
    fps = fps*0.9+(100.0f/(currentTime - lastTime));
    lastTime = currentTime;
    return fps;
}



Best way to calculate framerate - aarku - Sep 6, 2006 10:51 AM

akb825 Wrote:Um... that's JavaScript... Last I heard, SDL doesn't work too well with JavaScript. Wink
Yeah, real clever. The algorithm is the important part, thus I pointed towards the comments in the code, which explain the algorithm.

/kick akb825

-Jon


Best way to calculate framerate - AnotherJake - Sep 6, 2006 01:03 PM

Here's yet another way to do it in C which will update a string every half second for convenience:

Code:
#define UPDATE_INTERVAL  0.5

char    fpsString[32];

void RenderFrame(void)
{
    double           currTime, deltaFPSTime, frameRate;
    static long      frameCount = 0;
    static double    lastFPSUpdate = 0.0;

    currTime = CurrentTime();
    frameCount++;
    deltaFPSTime = currTime - lastFPSUpdate;
    if (deltaFPSTime >= UPDATE_INTERVAL)
    {
        frameRate = (double)frameCount / deltaFPSTime;
        sprintf(fpsString, "FPS: %0.1f", frameRate);
        lastFPSUpdate = currTime;
        frameCount = 0;
    }

    // draw stuff
}

double CurrentTime(void)
{
    struct timeval time;

    gettimeofday(&time, NULL);
    return (double)time.tv_sec + (0.000001 * (double)time.tv_usec);
}



Best way to calculate framerate - kelvin - Sep 6, 2006 04:03 PM

Not that I've done this before, but I just thought of a way to get live FPS with good accuracy...

Set up a sliding window calculation:
1) Set up a Queue of timestamps.
2) Every frame put a timestamp in the Queue.

To calculate your sliding window FPS:
Lets say your window is 3 seconds.
1) poll the Queue and discard timestamps until you reach a timestamp that is within the last 3 seconds.
2) divide the Queue count by 3.0
3) there's no step 3!

This method for calculating FPS will give you a live average of the last 3 seconds with higher accuracy than any other method. If you set your window to 1 second, you get an exact number of frames for the last second. The nice thing about the live average is that you can see your FPS for EVERY SINGLE FRAME. if you were so inclined, you could graph the result and get a non-chunky live view of your throughput.

Implementation details:
Fear not, I've also thought of a novel way to implement this sliding window. Use a ring buffer (will eliminate allocations) of doubles (ints might be slightly faster) for your Queue. This will be very very fast and keep FPS calculation to a minimum. Also, doing the poll dump is trivial and fast. Just traverse and compare. If you are calculating FPS every frame with a 1 second window, you'll on average do just 1 inequality check and 2 adds.

When you reach a Queue overflow, simply over-write the head of the Queue and move the head down the line. When you do this, you get a capped FPS (I'd say 1024 (you can wrap it with a bit manipulation) is a nice sized ring buffer to allocate) calculation.

When you think about it, saving memory to calculate FPS is really not beneficial at all. You're trying to calculate how fast you are going! Why slow down (even infinitesimally) for some useless approximate calculation? Nowadays 4KB for a sliding window is practically free. And the calculation... well, this implementation is about as cheap as you can get. (and it's live!)

[edit:] I just thought of something else: Since your Queue is sorted (in theory) you can traverse it like a binary tree. If you are using the ring buffer implementation with 1024 spaces, you'll never have to compare more than 11 entries!

[edit again:] Perhaps the best way to do the poll dump is to do an exponential search up, then an exponential search down. Since the index you're looking for is *most likely* near the head of the queue, you'll probably find it faster searching up than down.


Best way to calculate framerate - kelvin - Sep 6, 2006 04:14 PM

TomorrowPlusX Wrote:This works pretty well for me, but I doubt it's the "best".

Code:
void Application::postDisplay( void )
{
    static unsigned int frameCounter = 1;
    static float lastCheckTime = 0;
    
    float elapsed = simtime::now() - lastCheckTime;
    if ( elapsed > 1.0 )
    {
        _currentFPS = (float) frameCounter / (float) elapsed;

You've got a divide by zero error waiting to happen on fast machines.

Note: this goes for all the above implementations in this thread. (except mine of course)


Best way to calculate framerate - OneSadCookie - Sep 6, 2006 04:20 PM

It's not an error to do a floating-point divide by zero (you'll get infinity or -infinity, but that's not a major issue)


Best way to calculate framerate - Greywhind - Sep 6, 2006 06:12 PM

Here's how I do it using SDL (I think this is all of it... didn't check carefully...):

Keep a variable that is updated at the end of each frame called "startFrame" (at the end of each game loop, this code should be run:
Code:
startFrame = SDL_GetTicks();
Then at the beginning of each game loop, get the current frame rate like so:
Code:
// the framerate:
int framerate = (1000/(SDL_GetTicks() - startFrame));

If I missed something, please forgive me - I'm somewhat busy at the moment and didn't have much time to write this.


Best way to calculate framerate - PowerMacX - Sep 6, 2006 06:24 PM

kelvin Wrote:Not that I've done this before, but I just thought of a way to get live FPS with good accuracy...

Set up a sliding window calculation:
1) Set up a Queue of timestamps.
2) Every frame put a timestamp in the Queue.

To calculate your sliding window FPS:
Lets say your window is 3 seconds.
1) poll the Queue and discard timestamps until you reach a timestamp that is within the last 3 seconds.
2) divide the Queue count by 3.0
3) there's no step 3!

This method for calculating FPS will give you a live average of the last 3 seconds with higher accuracy than any other method. If you set your window to 1 second, you get an exact number of frames for the last second. The nice thing about the live average is that you can see your FPS for EVERY SINGLE FRAME. if you were so inclined, you could graph the result and get a non-chunky live view of your throughput.

Or... you could just use exponential smoothing (what I posted earlier) to get very similar results. Wink Actually, not only is exponential smoothing a lot simpler to implement, it also suffers less lag so maybe not just "similar" but "better" results:

http://www.robertwcolby.com/EMAreport.html