[C++] Win32 Sleep(1) different on multi-core system

Started by
14 comments, last by Evil Steve 16 years, 8 months ago
Am I the only one that is experiencing problems with the Win32 function Sleep()? On my Pentium 4HT cpu, it does what is expected, it throttles the CPU down to less than 1% when very little is drawn. My framerates are about 400fps. On my Core2 Q6600, it throttles the CPU down to 1% AND my FPS is at 65. Also, if I stick 4 Sleep(1) next to each other, it brings it down to 17fps. On my P4 four sleeps in a row of 1ms will do nothing of that sort. Has anyone experienced similar situation? If so, what can I do?
Advertisement
It does exactly what it says on the box. It sleeps at least one millisecond when called with 1 as parameter.

Nothing more should be expected from it, and if you rely on behavior beyond that, you're asking for trouble.
Nowhere in the documentation does it say "Lowers CPU usage to less than 1%"


Now, you haven't actually said what you're trying to achieve by calling it, or why the result you're getting isn't satisfactory, which makes it hard to help.

If you simply want to ensure that other applications get the CPU time they need, you.... basically don't need to do anything. Calling Sleep is not necessary, unless you're running on Windows 3.1.

If you want to constrain the CPU usage to an absolute minimum, you might want to call it with a different value than 1. If you simply want your app to get CPU time frequently, but at the same time yielding the CPU again as soon as possible, you might want to call it with 0 as argument.
Yes, I guess it does by definition. But this is the first time that I noticed that it stopped for longer than around 1ms. Someone else has clued me in on the fact that depending on the system, not OS, it will sleep different amount of time. But there is a fix.

// Beginning of program
timeBeingPeriod(1);

// Where you need it
Sleep(1);

// Right before the program exits.
timeEndPeriod(1);

I was informed that this basically sets the granularity of 1ms and Sleep(1) will do what I want accross different systems.

And yes, I am trying to have a window (not full screen) based game not use up 100% of the CPU time. Calling Sleep(0) still works my CPU up a sweat of around 40%, Sleep(1) drops it to 1%. The game is a casual game and I don't want customer's CPU fan spinning up while they are on the welcome screen. :)
What I'm betting is happening is that when you sleep, the thread is getting loaded on the other core a lot of the time. This leads to unhappy memory effects.
Quote:And yes, I am trying to have a window (not full screen) based game not use up 100% of the CPU time. Calling Sleep(0) still works my CPU up a sweat of around 40%, Sleep(1) drops it to 1%. The game is a casual game and I don't want customer's CPU fan spinning up while they are on the welcome screen. :)


Then go with timer-based updates, or with multiple v-sync multiplier.

Relying on timers and sleep is generally not recommended due to various issues. For example, what happens on CPUs that vary clock rate?

Setting the timeBeginPeriod(1) is generally bad, since it messes with system clock.

And if this is casual game, then try running it on a bit less bleeding edge hardware. Like *a lot* less bleeding edge.
Antheus,

"Then go with timer-based updates, or with multiple v-sync multiplier."

How would I do this in C++ windowed and fullscreen mode?
It depends a bit on the API and approach you choose.

One way is to spin on QueryPerformanceCounter. Not perfect, you'd probably need to SetThreadAffinity for timer thread to only run in one thread. If x miliseconds elapsed (timer would likely have much higher resolution than that of sleep), call render, otherwise Sleep(0).

The other way is to simply specify VSync by setting D3DPRESENT to D3DPRESENT_INTERVAL_ONE or higher. This will block your rendering in call to Present(). If you don't specify D3DPRESENT_DONOTWAIT, this should give your application accurate idle time.

The second option would be better. By default, your applicaiton ships with vsync enabled. If vsync is disabled, then it only pauses with Sleep(0) between calls to render. This would give the users option of either running nicely, or getting highest frame-rate.

Unless you really need to render more than 30 or 60 times per second, there's no need to allow disabling of vsync.
Either use SetTimer and process WM_TIMER messages or use CreateWaitableTimer to create a waitable timer and use WaitForSingleObject / MsgWaitForMultipleObjects(Ex).

Edit: Or use the multimedia timer (timeBeginPerion / timeSetEvent) for better precision.

Spinning on a polled timer with a Sleep (.) is not a particularly good way of doing it as your application will be consuming CPU (a small amount, granted, but it won't allow the OS to power down at all). Sleep also suspends the message processing loop (GetMessage et al) so it's a double whammy.

Skizz
Thanks guys. I will try out few things. I never intended to disable vsync, but in windowed mode, you can't enable it so you need to limit it somehow.
Quote:Original post by azherdev
Calling Sleep(0) still works my CPU up a sweat of around 40%, Sleep(1) drops it to 1%.
That's because they do different things. Sleep(0) causes the thread to give up the rest of it's timeslice, it doesn't actually put the thread to sleep. Sleep(1) will sleep for at least 1 millisecond, and probably ~20ms. So you have a 20ms wait v.s. a fraction of a millisecond wait.

This topic is closed to new replies.

Advertisement