QueryPerformanceCounter Win32 timer slower than normal

Started by
18 comments, last by tonemgub 10 years, 5 months ago

Hello, windows high res timer QueryPerformanceCounter always seems to act quirky whenever I use it.

I remember to set the thread affinity to cpu 0, and the timer runs perfectly at 1 second per frame, but I want it to run at 60 fps, I tried dividing the timer frequency by 60, but it still runs too slow, and even dividing it by 10000 keeps it slower than 60 fps. I do not know what I am doing wrong.

Here is my code:


while(destroyed != 2)
	{
		QueryPerformanceCounter(&gameTimer->currentTime);
		if(PeekMessage(&msg, 0, NULL, NULL, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		if(gameTimer->deltaTime >= 1.0f / 60.0f)
		{
			for(int i = 0; i < gameObjectList.size(); i++)
			{
				gameObjectList[i]->Update();
			}
			graphicsEngine->Render();
			gameTimer->deltaTime = 0.0f;
		}
		Sleep(1);
		QueryPerformanceCounter(&gameTimer->lastTime);
		gameTimer->CalculateDelta();
	}

This is how I'm calculating delta:


deltaTime += ((float)lastTime.QuadPart - (float)currentTime.QuadPart) / frequency.QuadPart;

View my game dev blog here!

Advertisement

How fast does it render when you are not limiting the FPS?

You should use vsync to limit your FPS to 60, otherwise you'll probably see screen tearing.

EDIT: some users have noted that the approach I suggested previously is not optimal. On further reflection I agree and have retracted it (I have left the explanation of why the OP's code is not behaving as expected).

---

Your problem is that Sleep(1). That's defeating the whole point of using an accurate timer, because Sleep() is less accurate than QPC. So by using it you have lowered the accuracy of your game loop to the accuracy of the Sleep() function, which is equivalent to not having QPC at all.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”


And for people complaining that "it takes all the CPU", relax - first, the CPU is there to be used, and secondly, the CPU is not doing very much work at all when just waiting for the delta time to elapse to draw the next frame (so it won't overheat or anything - it's not as if it were running Linpack in the meantime)

Actually, the CPU is not 'just waiting'. It runs instructions, and so it works, and consumes cycles and power (a lot - it doesn't have any cache misses to stall on).

Now imagine every application on the system running busy-wait loops - the CPU will be fully utilized all the time, causing performance degradation of the entire system.


And for people complaining that "it takes all the CPU", relax - first, the CPU is there to be used, and secondly, the CPU is not doing very much work at all when just waiting for the delta time to elapse to draw the next frame (so it won't overheat or anything - it's not as if it were running Linpack in the meantime)

Actually, the CPU is not 'just waiting'. It runs instructions, and so it works, and consumes cycles and power (a lot - it doesn't have any cache misses to stall on).

Now imagine every application on the system running busy-wait loops - the CPU will be fully utilized all the time, causing performance degradation of the entire system.

Then perhaps a WaitableTimer would do the trick, by getting the operating system to wake up the thread at regular (but not necessarily accurate enough) intervals. But then again, Windows is not a real-time operating system, and does not give particularly strong guarantees regarding when it decides to schedule threads for execution.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

vsync is the simplest solution to limit the FPS to 60.

And for people complaining that "it takes all the CPU", relax - first, the CPU is there to be used, and secondly, the CPU is not doing very much work at all when just waiting for the delta time to elapse to draw the next frame (so it won't overheat or anything - it's not as if it were running Linpack in the meantime). Context switches are expensive, let the operating system handle these details for you and write code without worrying about them - it knows what it's doing better than you do. If you really cannot deal with this, then you can always try and change the timer resolution with timeBeginPeriod(), to, for instance, 1 ms, and then use Sleep(), which will give some better results, but be warned that this may still cause your framerate to jitter to up to +- 1 ms if your thread happens to be sleeping as you cross the 16.67ms threshold.

Actually, if you have a busy wait loop running like that, it actually will run the processor ragged, and if they're on a laptop it's going to be eating their battery to its fullest. If they're committed to a tight loop, however, you don't need to call Sleep every frame. Every 10-15 frames should be enough to give the CPU a breather, maybe even more, and over such a period of time, the time eaten by sleep will be barely noticeable.

However I really don't think I'd advise a loop like that. I second the notion that limiting your main rendering framerate should be handled by vsync because there is almost no reason to do it yourself and lots of reasons why you wouldn't want to do it yourself.


Windows is not a real-time operating system, and does not give particularly strong guarantees regarding when it decides to schedule threads for execution

http://msdn.microsoft.com/en-us/library/windows/desktop/ms685096%28v=vs.85%29.aspx

IMO, It's not that Windows doesn't make guarantees... It does make quite a lot of them, actually, but it cannot guarantee what the hardware does. Most laptops and tablet PCs have hardware power-saving features that can't be controlled by the OS, to save power - this is also why it appears as though the OS "knows what it's doing better than you" - the hardware does that, not the OS.

This is interesting: http://msdn.microsoft.com/en-us/library/windows/desktop/ms684247%28v=vs.85%29.aspx

Hello, windows high res timer QueryPerformanceCounter always seems to act quirky whenever I use it.

You use it in a quirky way.
First-off you are always dropping some time with your current implementation, and I don’t mean the intentional way.

You should never call QueryPerformanceCounter() more than once per loop. If you need to know the “last time”, make a copy of the current time before updating it.

	while(destroyed != 2)
	{
		gameTimer->lastTime = gameTimer->currentTime;
		QueryPerformanceCounter(&gameTimer->currentTime);
		if(PeekMessage(&msg, 0, NULL, NULL, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		if(gameTimer->deltaTime >= 1.0f / 60.0f)
		{
			for(int i = 0; i < gameObjectList.size(); i++)
			{
				gameObjectList[i]->Update();
			}
			graphicsEngine->Render();
			gameTimer->deltaTime = 0.0f;
		}
		Sleep(1);
		gameTimer->CalculateDelta();
	}
Second-off you are converting the values to “float” while still in expanded form, meaning you are converting values such as 351,357,654,184 etc., which you should know better than to do. (Also, use static_cast for sake’s Pete.)
deltaTime += static_cast<float>(currentTime.QuadPart - lastTime.QuadPart) / frequency.QuadPart;
Third-off, don’t accumulate time as a float. Accumulate time in unsigned long long integers (I’m looking at gameTimer->deltaTime).


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

In addition to what Bacterius and L. Spiro already said, the time taken by TranslateMessage+DispatchMessage is not deterministic -- wait, that's a wrong wording. It is deterministic, but it is neither obvious, nor constant. Not only your window proc, but also the default window proc may take vastly different amounts of time to process messages, and new messages may be generated (as a consequence of messages being received) that you even don't yet know about. In an extreme case, these two harmless lines of code could take 20 times longer than they usually do.

Most likely this will not be the cause of your problem, but still it is unwise to wrap a high resolution timer around such a thing (and around Sleep on top of that) and expect something meaningful to happen.

About Sleep, this is a valid objection. There is nothing less likely to break your timings (or your frame rate, for that matter) than calling Sleep. On the other hand, it is also a valid cause not to let the CPU busy wait all the time because of power consumption. However, this is not the case where it matters most anyway, and where it matters less you might even want that exact thing to happen.

One usually wants to save power on mobile devices where busy waiting will drain your batteries much faster (assuming you're not plugged in). However, on those devices, vertical sync is usually forced on by the drivers, so there is some built-in rate limit anyway. The game renders, so inevitably, it will be throttled. Of course, in between it will still run busy. But, even on a mobile device this may be a benefit.

On desktop computers, being busy is more often a benefit rather than a disadvantage, even if it burns a little more power. Unluckily, operating systems apply the power saving craze just as often when it doesn't make sense as when it makes sense. If you search the web for "game stuttering", you'll come up with "fix" instructions like these (which will more likely than not cause unwary users to break something!) for that exact reason.

When a CPU is not utilized, the OS will usually reduce its frequency or even "park" a core alltogether, even if you're on a desktop computer with a thick plug in the wall. This is OK when you're half-asleep in front of Microsoft Word at your boring office job. It is, however, not a big win while a game is running. Not at all. Effectively, the CPU runs at one half or one third of its speed when the only thing you really need is... speed.

This power saving craze is so extreme that for example on my ASUS notebook, I cannot even get the CPU to run at maximum clock speed. I paid for a CPU that can do 2GHz, but it will never run any higher than 1.7GHz, even if I start a program that has 2 threads busy running. On "idle" (i.e. if no program is busy spinning and you don't press a key for about 2 seconds), it runs with 0,58GHz using a single core. The result is that when you start your web browser or mail program, it takes literally seconds before it's ready (happens "instantly" on desktop). Because hey, we must save power. They don't account for the fact that if everything takes longer, this consumes power too, and your life time.

Power throttling is exactly the kind of thing that you normally don't want to happen in a game. Insofar, while the argument against busy waiting is valid, it is not valid without restrictions. In any case, however, there exist better options (Bacterius mentioned waitable timers, to name an example) than Sleep to prevent busy waiting.

Unluckily I can't remember the URL now, but there was a funny (well, funny if it doesn't happen to you) site a while ago about a guy who spent big $$$ to buy a faster server, only to discover that the stupefied power throttling made his new server run at less than 50% of its speed because he was only using two out of four cores (those 100% loaded, though), effectively being slower than the old one.

This topic is closed to new replies.

Advertisement