Sign in to follow this  
incertia

Does Sleep tend to overwait?

Recommended Posts

I've been the high performance timers (QueryPerformaceCounter) to time program fps. I've let the program take the average of 256 fps samples to produce the final fps. So I test it with Sleep(500), expecting the fps to be around 2, but I've found that the fps steadily decreases until it stabilizes around 1.9961 - 1.9962. Frame time, on the other hand, seems to be increasing by 0.00006 per query. Is this normal and should be disregarded as float inaccuracies?

Share this post


Link to post
Share on other sites
If you sleep 500 and then take something like 1ms to generate the frame, you just spent 501 ms for a frame, and you'll measure about 1.9961 fps. This sounds like expected behavior to me.

Share this post


Link to post
Share on other sites
sleep (on Windows) will sleep for atleast the specified amount of time so in general it will sleep for slightly longer than specified. (Exactly how long it sleeps depend on alot of factors such as other running processes, available cpu cores, scheduler timeslice size, etc), It is a bad idea to use sleep to control the speed an application runs at, only use sleep to reduce cpu usage for mobile devices(when running on battery) or for enviromental reasons.

Share this post


Link to post
Share on other sites
[quote name='alvaro' timestamp='1335711300' post='4935838']
If you sleep 500 and then take something like 1ms to generate the frame, you just spent 501 ms for a frame, and you'll measure about 1.9961 fps. This sounds like expected behavior to me.
[/quote]

Does a simple std::cout really require 1ms to output something? I simply thought that it would take faster. Thanks for the input.

Share this post


Link to post
Share on other sites
[quote name='incertia' timestamp='1335730184' post='4935880']
[quote name='alvaro' timestamp='1335711300' post='4935838']
If you sleep 500 and then take something like 1ms to generate the frame, you just spent 501 ms for a frame, and you'll measure about 1.9961 fps. This sounds like expected behavior to me.
[/quote]

Does a simple std::cout really require 1ms to output something? I simply thought that it would take faster. Thanks for the input.
[/quote]

Oh, I probably misunderstood what you tested. Sorry about that. If all you were doing was printing out a number, it shouldn't take anywhere near 1ms, so the explanation of Sleep waiting for too long seems sound.

Share this post


Link to post
Share on other sites
Yeah lol, this was my test program:

[CODE]
int main(){
timer_init();

while(true){
timer_begin_frame();

cout << get_fps() << endl;

Sleep(500);

timer_end_frame();

timer_calculate();
}

return 0;
}
[/CODE]

begin_frame() and end_frame() grab high resolution tick counts while timer_calculate() subtracts a number and adds.
I'm not too sure how fast timer_calculate() can run, but I don't think this will take anywhere near 1ms.

[CODE]
void __stdcall timer_calculate(){
float fps = static_cast<float>(timer_info.freq.QuadPart) / static_cast<float>(timer_info.time_end.QuadPart - timer_info.time_start.QuadPart);

//Increment current sample and mod if necessary
fps_info.current_sample++;
fps_info.current_sample %= FPS_SAMPLES;

//First run
if(fps_info.first){
for(size_t i = 0; i < FPS_SAMPLES; i++){
fps_info.fps_samples[i] = fps;
}

fps_info.fps = fps;
fps_info.frame_time = 1/fps;
fps_info.fps_sum = static_cast<float>(FPS_SAMPLES) * fps;

fps_info.first = false;

return;
}

//Subtract the previous recorded fps from the sum
fps_info.fps_sum -= fps_info.fps_samples[fps_info.current_sample];

//Add the current sample information to the sample info
fps_info.fps_samples[fps_info.current_sample] = fps;

//Add our data to the sum
fps_info.fps_sum += fps_info.fps_samples[fps_info.current_sample];

//FPS is sum / samples while frame_time = 1/fps
fps_info.fps = fps_info.fps_sum / static_cast<float>(FPS_SAMPLES);
fps_info.frame_time = 1/fps_info.fps;
}
[/CODE]

Share this post


Link to post
Share on other sites
To make it short: there simply is no way to wait for any exact amount of time. There are a ton of processes running and a scheduler juggling them all. When you suspend your process with sleep all you can do is "nicely ask" to be resumed in at least x ms. Even if you waste resources by busy waiting the scheduler can suspend you at any time and you won't get to run again in time.

Always keep in mind that your program isn't the only thing going on and that with all the background processes, services and what-not there are way more things wanting to run every once in a while than you got cores in your CPU.

Share this post


Link to post
Share on other sites
This is so obvious, yet I see so many threads about this subject with no clear answers.

Just put all your events into a [url="http://www.cplusplus.com/reference/stl/priority_queue/"]std::priority_queue[/url] and sleep only if there is more than one timeslice between now and the next event. Otherwise just keep spinning until the time the event occurs. Edited by Mihai Moldovan

Share this post


Link to post
Share on other sites
I'm afraid you don't understand the point of my test. I was simply using a set of functions I wrote and a simple Sleep(500) test to see if I would get reasonably near 2fps. The fact that I was actually waiting 1ms too long made me question whether Sleep tends to over wait or if I have code that is not functioning at top performance.

Share this post


Link to post
Share on other sites
[quote name='incertia' timestamp='1335830326' post='4936238']
I'm afraid you don't understand the point of my test. I was simply using a set of functions I wrote and a simple Sleep(500) test to see if I would get reasonably near 2fps. The fact that I was actually waiting 1ms too long made me question whether Sleep tends to over wait or if I have code that is not functioning at top performance.
[/quote]

I was trying to explain the more general application of event queues aka reactor pattern.

Share this post


Link to post
Share on other sites
[quote name='incertia' timestamp='1335830326' post='4936238']
I'm afraid you don't understand the point of my test. I was simply using a set of functions I wrote and a simple Sleep(500) test to see if I would get reasonably near 2fps. The fact that I was actually waiting 1ms too long made me question whether Sleep tends to over wait or if I have code that is not functioning at top performance.
[/quote]

FPS = 1000 / (sleep_time_in_ms + x).

x = time needed to update fps, to render frame, anything really

sleep_time_in_ms is guaranteed to be 500ms or more.

As such, using method above, it's impossible to get 2.000000 fps, unless x is exactly 0 (cycles, nanoseconds, ...).

Any routine which switches threads, such as sleep, will be accurate up to 20 ms, or whatever the time slice quantum is. Expected times for such approach are 1.92 - 1.99fps.

The lower the sleep time, the larger the range. For sleep time, such as 30ms, fps will vary between 33 and 20.

If you run multiple applications that put more load on CPU, you'll notice the time starts varying, since scheduler cannot find a time slice for your app quickly enough. Edited by Antheus

Share this post


Link to post
Share on other sites
Antheus explained it, but I wanted to try to explain it with a different approach.

It basically boils down to this.
Sleep() waits for [i]no less than[/i] the given time. In other words, it [i]always[/i] sleeps more than you want. That is why I am such an antagonist against using it for game loops or anything that relies on timing.

You may as well assume it is possible for Sleep() to wait 5 seconds longer than you specify, because at least then you will follow safe coding practices.

Between the hardware and the operating system, Sleep() gives you 1 and only 1 guarantee: Nothing will happen for at least the time you specify.
The hardware schedules triggers on a regularly scheduled basis. A basis that does not give a damn about the number of milliseconds you sent to your last Sleep() call. If it wants to wait 5 more milliseconds, it will.
Then the operating system, which has the task of scheduling threads, needs to decide which threads are the most starved for attention. Some threads have been put on hold so, well, it’s super-nifty that your little timer went off, but this thread has been waiting for a long time and needs to run for a while.


Timers basically give you 1 and only 1 guarantee: Whatever delay you specify, it will always be longer than that before the timer triggers.
Never use timers for time-sensitive execution.
Does Sleep() sometimes overwait? No. It [b]always[/b] overwaits. No exceptions.


L. Spiro

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this