Problem with calculating the fps of my application

I'm trying to make a custom framework from scratch. It already has some basic functions. Now, I want to display the time and fps of my application. I followed exactly episode 10 of Handmade Hero, but for some reason, my fps is way too high (around 57 million frames per second). My pc is i7-8700, gtx 1070ti (I know it's very fast, but the fps is still too high). Here's the code:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
LARGE_INTEGER perfCountFrequencyResult;
QueryPerformanceCounter(&perfCountFrequencyResult);
int64_t perfCountFrequency = perfCountFrequencyResult.QuadPart;

// Open window (1280x720)

LARGE_INTEGER lastCounter;
QueryPerformanceCounter(&lastCounter);
int64_t lastCycleCount = __rdtsc();
while (app.isRunning)
{
    // Draw around 5 bitmaps (256x256) and a couple of triangles to the screen using OpenGL

    int64_t endCycleCount = __rdtsc();
    LARGE_INTEGER endCounter;
    QueryPerformanceCounter(&endCounter);

    int64_t cycleElapsed = endCycleCount - lastCycleCount;
    int64_t counterElapsed = endCounter.QuadPart - lastCounter.QuadPart;
    float msPerframe = ((1000.0 * (float)counterElapsed) / (float)perfCountFrequency);
    float fps = (float)perfCountFrequency / (float)counterElapsed;
    float mcpf = ((float)cycleElapsed / 1000000.0);
        
    printf("%fms/f / %fFPS / %fMC/F\n", msPerframe, fps, mcpf); // A sample: (0.000018ms/f / 56302504.000000FPS / 22.228949MC/F)

    lastCounter = endCounter;
    lastCycleCount = endCycleCount;
}

Is there anything wrong with my code? Or it's just that I'm doing too little work and my pc is too fast?

Edited by longtran2904 on Reason: Initial post
I've just increased the number of sprites to draw each frame. My application is now extremely buggy and I can see clearly each frame that gets render, but the displayed fps for some reason are still way too high (0.000311ms/f / 3210382.750000FPS / 391.519745MC/F). There's must be something wrong with the timing code above.
I have done this same mistake before multiple times!

Your perfCountFrequencyResult contains QPC counter, not QPC frequency.
Instead you should query frequency there:
QueryPerformanceFrequency(&perfCountFrequencyResult);

Also don't cast counters & cycles to float - that can potentially loose precision. Either do everything in ints, or do it in doubles and then cast only final number to float.

Edited by Mārtiņš Možeiko on
Thanks, I fix it! Another thing that happens to me is that I update the keyboard input using the PeekMessage function (like Casey did) in the game loop, but because the game is running quite fast (144 fps) and windows send messages at a lower rate (I think?) so I can't check for input reliably in the game loop. Do you have any fixes?
What do you mean with you cannot check in game loop?
When windows delivers message you remember what happened in your own structures - was it key down event, key up, which key, etc..
Then in your game loop you can this info at any time. No matter what is your rendering frequency.

In simplest implementation you need to known three different things about each key:
1) was it pressed (transitioned from up to down) // is set to true only once in frame when key is pressed down
2) was it released (transition from down to up) // is set to true only once in frame when key is released
3) is it being pressed down // is set to true all the time when key is being kept pressed down

So just figure out how you want to store this info in your structures, and update values when windows key messages are delivered. And later you can write code like:
1
2
3
if (WasKeyPressed[KEY_A]) { printf("You pressed key A\n"); }
if (WasKeyReleased[KEY_A]) { printf("You released key A\n"); }
if (IsKeyHeldDown[KEY_A]) { printf("You are holding key A down\n"); } else { /* key is up */ }


Edited by Mārtiņš Možeiko on
I had 2 bools (isDown and wasDown) and only updated it in the PeekMessage loop. So because Windows sends messages at a lower rate, then these bools are not updated fast enough. For example, if I press a key down, Windows sends a message, then it stops for a couple of frames, then it sends another message, then stops for another couple of frames, so I think that the message loop is at a lower rate than my fps. In this example, the wasDown is not updated fast enough, so for a couple of frames after the key was being pressed, the wasDown is still equal to false.

Edited by longtran2904 on
Do not use bools in such way. Do not use repeat setting, unless you're implementing text input.
Keep those kind of bools persistent across frames - like I mentioned above.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
static bool WasKeyPressed[512], WasKeyReleased[512], IsKeyHeldDown[512];

// ... in your WindowProc
switch (message) {
  case WM_KEYUP:
  case WM_KEYDOWN: {
    bool wasUp = !!((lparam >> 30) & 1);
    bool isDown = message == WM_KEYDOWN;
    DWORD key = wparam;
    WasKeyPressed[key] = wasUp & isDown;
    WasKeyReleased[key] = !wasUp & !isDown;
    IsKeyHeldDown[key] = isDown;
    return 0;
  }

// .. in your main game loop

// if you need to do action exactly once when key is being pressed down, like throw one grenade
if (WasKeyPressed[VK_A]) throwGrenade();

// if you need to do action continuously while key is kept pressed down, like move forward
if (IsKeyHeldDown[VK_UP]) moveForward();

This is pretty much what Unity offers in their Input.GetKeyDown/GetKeyUp/GetKey methods.

You can see that IsKeyHeldDown[key] will be true regardless how many times more your game loop runs - it will be only reset to false when key is actually released, and not sooner.

This will work fine unless user starts to press buttons very fast. In such case you simply count transition count during WM_KEYUP/DOWN messages and then you'll know now many times key was pressed, which is what Handmade Hero implemented: https://guide.handmadehero.org/code/day017/

Edited by Mārtiņš Možeiko on
This is exactly like my code (except that my code has the windowProc inside the game loop, and I used wasDown rather than wasUp). The problem is because Windows sends messages at a slower rate, the input wouldn't be updated reliably. In your example, WasKeyPressed won't only happen for a single frame, because wasDown won't get updated for at least a couple of frames until another message gets send from Windows. Here's my code:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
bool IsKeyPressed(int key)
{
    return (vkCode == key) && isDown && wasDown;
}

bool IsKeyDown(int key)
{
    return (vkCode == key) && isDown && !wasDown;
}

bool IsKeyUp(int key)
{
    return (vkCode == key) && !isDown && wasDown;
}

while (/* game loop */)
{
    MSG message;
    while (PeekMessage(&message, 0, 0, 0, PM_REMOVE))
    {
        switch (message.message)
        {
            case WM_SYSKEYDOWN:
            case WM_SYSKEYUP:
            case WM_KEYDOWN:
            case WM_KEYUP:
            {
                vkCode = message.wParam;
                wasDown = ((message.lParam & (1 << 30)) != 0);
                isDown = ((message.lParam & (1 << 31)) == 0);
                // Handle wasPressed, isPressed, isReleased
                }
            } break;
            default:
            {
                TranslateMessage(&message);
                DispatchMessage(&message);
            } break;
        }
    }
    // Do other stuff
}


For example, if I press the A key down, here's the output:
A is down
A is down
A is down
// This happens for a couple of frames until Windows sends another message to change the wasDown to true
A is pressed
A is pressed
// This happens until I release the key, then Windows sends a message to change wasDown to true, isDown to false
A is up
A is up
// This happens forever because Windows never sends any other message to change wasDown to false

Edited by longtran2904 on
Windows only posts messages to the message queue when it needs to. It doesn't update at a (fixed or variable) time interval. That means, in the case of key presses, that it will only post a message when a transition happens (the key was pressed or released) or the key has been pressed for more than the "repeat timer" in which case it posts a new key down message without a key up message before ( a "repeat message"). The repeat messages are mainly used to handle text input, where you want to repeat the key at a constant rate while the key is pressed. For example when you keep 'a' pressed in a text editor, it will repeat the 'a' letter at fixed time interval.

I believe the repeat message made you think the windows message update was slower than your frame rate. What is happening is that the repeat timer is ~300 ms (I don't know the actual value, it can be configured in Windows settings) and so if you keep a key pressed, PeekMessage will only have a message every 300ms which is a lot slower than your frame rate (7ms). As far as I know there is no limit at how fast Windows can post messages, but it'll only post messages when necessary.

As mmozeiko said, you need to properly keep track of the state of keys.
- You need a globally accessible state for each key that tracks its "pressed this frame", "released this frame" and "is pressed" state;
- Each frame before processing the messages, you need to clear the "pressed this frame" and "released this frame" state (not the "is pressed" state), because if you just pressed a key, the next frame you'll not get a message so the "pressed this frame" state won't be updated in the message loop (I believe this is your issue);
- In the message loop, you need to check the messages to find the transitions ( "pressed this frame", "released this frame" ) and update the 3 key states.

Edited by Simon Anciaux on Reason: typo
One easy hack that I've just found is assigned wasDown = isDown at the start of every frame and then handle the message. So for the first time that I press a key, wasDown == false, isDown == true, so this is "key down". The next frame, wasDown will be equal to true (because isDown == true) and isDown won't change until I release the key, so this is "key pressed". When I release the key, wasDown == true and isDown == false, so this is "key release". Finally, on the next frame, wasDown will be reset back to false automatically.
That is exactly what you should do. Again - watch Handmade Hero video where this is explained. There are some variations on how to implement, but what you wrote in this "easy hack" is one of ways to do that.