Why is Win32 Sleep still such garbage?

Started by
34 comments, last by cache_hit 14 years, 2 months ago
Quote:Original post by Washu
Sleep has never been, and never was designed to be, an accurate method of pausing a thread or process. You have told the system that you wish to nap for AT LEAST n milliseconds.
Quoted for truth.

Having said that, Sleep works perfectly well with timeBeginPeriod(1) on my system (I've tried that a while ago because I wondered myself how well it works). Doing 10.000 Sleep(1) takes little over 10 seconds (4-6 ms more), which I guess is pretty much as good as you can get. To me, it's good enough, anyway.

Quote:As a side note - if you Sleep(0), you essentially give up your spot in the OS timehsare for threads for the current thread, but do not specify a wait time.
SwitchToThread is the preferred method here, as it has a much better behaviour. It will run the first ready thread that is scheduled for the same core if there is one, and do nothing otherwise (i.e. the next thread starts with warm caches, and the original thread will still be on the same core unless an urgent reason comes up to move it).

Sleep(0) on the other hand just gives up the time slice and keeps the thread ready, but does not provide any other guarantees. It might run any time later, and in theory on any core that happens to be free at that time.
Advertisement
Quote:Original post by Washu
Sleep has never been, and never was designed to be, an accurate method of pausing a thread or process. You have told the system that you wish to nap for AT LEAST n milliseconds. If you need accurate timing then use an accurate timing method (such as thread timers) and not a documented innacurate method.


Thread timers use a thread-pool correct? I recall them reentrantly calling the code if it was late.
Is there any other method?
I suppose you could have that code just set an event for the actual work thread... hum, how reliable are they?
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
So I tried it...
Thread timers are even worse than sleep!
(Right now we burn up a core spinning hard on QueryPerformanceCounter...)


Here are the numbers trying for a 1000ms timer:
0.001	1.008	1.0072.022	1.0143.036	1.0144.050	1.0145.064	1.0146.078	1.0147.092	1.0148.106	1.0149.120	1.01410.134	1.014

My nekkid eye is about that good.

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Runtime.InteropServices;namespace TestTimers{   class Program   {      [DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]      private static extern uint TimeBeginPeriod(uint uMilliseconds);      [DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]      private static extern uint TimeEndPeriod(uint uMilliseconds);      static System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();      static System.Threading.AutoResetEvent signal = new System.Threading.AutoResetEvent(false);      static void Main(string[] args)      {         TimeBeginPeriod(1);         try         {            stopWatch.Start();            using (System.Threading.Timer timer = new System.Threading.Timer(Program.TimerCheck, null, 0, 1000))            {               System.Threading.Thread.Sleep(10200);            }         }         finally         {            TimeEndPeriod(1);         }      }      static void TimerCheck(object state)      {         decimal time_sec = (decimal)stopWatch.ElapsedTicks / (decimal)System.Diagnostics.Stopwatch.Frequency;         Console.WriteLine(time_sec.ToString());      }   }}

Anything I'm doing wrong?

My gripe with Sleep and all the other various Windows timing mechanisms is that while they certainly could have gotten much better over the years they have actually gotten worse... and that just doesn't make sense.
A ten year old Pentium II running Windows 2000 hits the times better than a i5 running Windows 7.
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Quote:Original post by Shannon Barber
[...]A ten year old Pentium II running Windows 2000 hits the times better than a i5 running Windows 7.
No, it doesn't. If, when given a delay of "at least 1ms", you delay 1ms or more, you're hitting the delay perfectly. Thus, if a pentium 2 delays 1.0001ms when given "at least 1ms" and a modern core i7 delays 37 minutes when given "at least 1ms", both machine are functioning perfectly to the specification.

If you want to specify a delay of something other than "at least X", you'll have to use a different mechanism that works how you desire. The most accurate such mechanism would be a real-time OS on purpose-designed hardware, but you can do much better on an average PC running windows. Jan Wassenburg has written several articles on the topic of timing that can be found here on gamedev and elsewhere.
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
Because people can't wrap their tiny brains around the idea that altering priority levels doesn't make for good multhtreaded code. MS takes that to the extreme until now you simply can't ever really have priority set in a sane manner or anything you do will work like you'd obviously expect it to.

It makes some sense to have signalled threads get more priority, but it takes away your ability to see just what the f is ever going on, and to have some miniscule hope that some multithreaded stuff on.

I guess it's just typical microsoft destructive 'helping'.

This is my thread. There are many threads like it, but this one is mine.

Quote:Original post by Extrarius
Quote:Original post by Shannon Barber
[...]A ten year old Pentium II running Windows 2000 hits the times better than a i5 running Windows 7.
No, it doesn't. If, when given a delay of "at least 1ms", you delay 1ms or more, you're hitting the delay perfectly. Thus, if a pentium 2 delays 1.0001ms when given "at least 1ms" and a modern core i7 delays 37 minutes when given "at least 1ms", both machine are functioning perfectly to the specification.

If you want to specify a delay of something other than "at least X", you'll have to use a different mechanism that works how you desire. The most accurate such mechanism would be a real-time OS on purpose-designed hardware, but you can do much better on an average PC running windows. Jan Wassenburg has written several articles on the topic of timing that can be found here on gamedev and elsewhere.


It's always real-time and always a question of performance.
If you called Sleep(10) in your app and it slept for two minutes every time no one would accept that "it works to spec".
I have a computer that is 40x more powerful yet is 90% less precise.

Quote:Jan Wassenberg
I've previously written an article about timing, but unfortunately the situation has gotten even worse since then. RDTSC is more broken than before and QPC now uses it instead of only marginally broken alternatives, so that leaves WinXP users on dual-core systems with a total lack of a decent timer.

So we rely on QPC to make the best decision for the hardware and blow a core just to figure out "time to make the donuts".


More to the "meat" of the matter though, there is a new feature in Vista and 7 called "Timer Coalescing" designed for minimum power consumption that will intentionally delayed timers by up to a default of 32ms to make many things happen at once to maximize time spent in low-power idle.
Presumably this is why .NET based timer code is off by 14ms (because it is using the default of +32ms).
When I have a chance I'll try using the newer API SetWaitableTimerEx and see how low I can set the coalesce parameter.
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
What do you mean by QPC "is burning up a core"?

I have a similar problem: I want to have a timer that sleeps for one second, and until that, the program sleeps (So the CPU won't burn on 100%). But I want to do it precisely: it's a time display in a minesweeper game, that is event based (windows message event), so it only does stuff, when it gets win message (okay, it's obvious, I'm over-explaining it, because I don't know the terms).

So how could I achieve this?
Edit:Maybe with sleep() combined with QPC to correct the error of sleep... Nope.
How precise is the SetTimer, WM_TIMER stuff? This seems better

I've looked at Jan Wassenburg's article, maybe I'll just leave it as imprecise as it is.

[Edited by - szecs on February 15, 2010 2:56:31 PM]
Quote:
If you called Sleep(10) in your app and it slept for two minutes every time no one would accept that "it works to spec".

Sure they would! If I'm running a really low priority service, and I need to do stuff, then go idle. Sleep(10) could take minutes if there is a high priority task eating up 100% of the CPU. I already said i'm low priority, and I said I don't want to work more than once every 10ms. So the wait time is "to spec" because the user sees that their high priority task(like video encoding or something) isn't being interupted by all the hundreds of random threads on the machine. Waiting on a device is even better. My service will go to sleep till some random time in the future when there is data for me.

Windows only guarantees that I will eventually get time, and will eventually get my data if it exists. It isn't a realtime OS, so it doesn't guarantee it will do any of that in a timely manner.

Quote:
I have a computer that is 40x more powerful yet is 90% less precise.

Your computer is also 40x a powerful, but running 600x as many random tasks. Look back to dos, what did it have running? nothing. command.com that was it, and it was waiting for you to type things. You run another app? yeah it got 100% of the cpu to itself so it could be 100% accurate. You have to remember you are sharing the computer. If you don't have a a very good computer(like my old dual core), try running a high-def 1920x1200 movie and doing anything else. The movie player will be high priority, and everything else takes a back seat. Opening something like firefox(usually a sec or less) can take 15sec to a min, but your video keeps playing along nicely.

Quote:
I have a similar problem: I want to have a timer that sleeps for one second, and until that, the program sleeps (So the CPU won't burn on 100%). But I want to do it precisely: it's a time display in a minesweeper game,

A second is a long time. You can use QPC to get a better guess at the time spent between your 1second event timers, but a person is going to have a hard time noticing a 15-30ms delay in a 1sec timer when they are focusing on clicking on mines.

Quote:
14ms

IIRC the default timeslice in windows XP/Vista is 15ms. That might also explain that number.

Quote:A second is a long time. You can use QPC to get a better guess at the time spent between your 1second event timers, but a person is going to have a hard time noticing a 15-30ms delay in a 1sec timer when they are focusing on clicking on mines.
I want to add best times listing feature, so precision is essential :P
Quote:Original post by szecs
Quote:A second is a long time. You can use QPC to get a better guess at the time spent between your 1second event timers, but a person is going to have a hard time noticing a 15-30ms delay in a 1sec timer when they are focusing on clicking on mines.
I want to add best times listing feature
Don't use the accumulated event timer callbacks to determine the overall time - accumulation always magnifies errors, so in this case your error will increase every second.

Instead, take a begin and end time and subtract, so that you only have the error inherent in two samples.
Quote:so precision is essential :P
How precise, exactly? I can't detect a difference in my winning click of less than about 1/4 second, so it doesn't seem reasonable to apply greater precision to the best times list.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

This topic is closed to new replies.

Advertisement