J E L L Y E N T
Windows Timer Resolution: The Colossal Rule Alternate

The habits of the Windows scheduler modified vastly in Windows 10 2004, in a approach that will ruin just a few purposes, and there looks to be buy to had been no announcement, and the documentation has now no longer been up to this level. This isn’t the most needed time this has came about, but this change looks to be like greater than closing time.

The short model is that calls to timeBeginPeriod from one assignment now have an effect on rather a lot of processes less than they extinct to, but there might be serene an invent.

I believe the brand new habits is an enchancment, but it absolutely’s authentic, and it deserves to be documented. Fascinating warning – all I absolutely be elated are the outcomes of experiments I absolutely be elated fling, so I will be succesful to top likely speculate regarding the quirks and targets of this change. If any of my conclusions are monstrous then please let me know and I’ll update this.

Timer interrupts and their raison d’être

A geeky clockFirst, a minute little little bit of running-machine map context. It’s tremendous for a program in grunt to drop asleep after which web up a short time later. This absolutely shouldn’t be performed very usually – threads might maybe presumably serene most incessantly be ready on situations in characteristic of timers – but it absolutely is as soon as critical. And so now we be elated the Windows Sleep characteristic – hump it the desired dimension of your nap in milliseconds and it wakes you up later, like this:

Sleep(1);

It’s payment pausing for a 2nd to buy into tale how here’s performed. Ideally the CPU goes to sleep when Sleep(1) is named, in grunt to lead dart of losing power, so how does the running machine (OS) wake your thread if the CPU is drowsing? The answer is hardware interrupts. The OS purposes a timer chip that then triggers an interrupt that wakes up the CPU and the OS can then agenda your thread.

The WaitForSingleObject and WaitForMultipleObjects functions additionally be elated timeout values and these timeouts are performed the usage of the identical mechanism.

If there are a tall possibility of threads all ready on timers then the OS might maybe presumably program the timer chip with particular person wakeup times for each and each thread, but this tends to consequence in threads waking up at random times and the CPU by no machine attending to be elated a prolonged nap. CPU power effectivity is strongly tied to how prolonged the CPU can dangle asleep (8+ ms is outwardly a appropriate amount), and random wakeups work towards that. If a pair of threads can synchronize or coalesce their timer waits then the machine becomes more power atmosphere qualified.

There are a tall possibility of how to coalesce wakeups but the predominant mechanism extinct by Windows is to be elated an international timer interrupt that ticks at a standard payment. When a thread calls Sleep(n) then the OS will agenda the thread to fling when the most needed timer interrupt fires after the time has elapsed. This means that the thread might maybe presumably pause up waking up a minute bit dumb, but Windows is never any longer a appropriate-time OS and it absolutely can now no longer guarantee a advise wakeup time (there might maybe presumably now no longer be a CPU core accessible at the 2nd anyway) so waking up a minute bit dumb need to be lustrous.

The interval between timer interrupts relies upon on the Windows model and on your hardware but on each and each machine I absolutely be elated extinct now no longer too prolonged contained within the past the default interval has been 15.625 ms (1,000 ms divided by 64). That machine that must you name Sleep(1) at some random time then you definately can seemingly be woken in some unspecified time in the future between 1.0 ms and 16.625 ms in due course, on each and each occasion the next interrupt fires (or the one after that if the next interrupt is magnificent too hasty).

In short, it is noteworthy the persona of timer delays that (except a busy wait is extinct, and please don’t busy wait) the OS can top likely web up threads at a advise time by the usage of timer interrupts, and a most neatly-liked timer interrupt is what Windows uses.

Some purposes (WPF, SQL Server, Quartz, PowerDirector, Chrome, the Waft Runtime, many video games, etc.) web this mountainous variance in wait delays solid to buy care of but luckily there could be a characteristic that lets in them to dangle leer over this. timeBeginPeriod lets a program place an whisper to a smaller timer interrupt interval by passing in a requested timer interrupt interval. There can even be NtSetTimerResolution which lets in atmosphere the interval with sub-millisecond precision but that’s now no longer usually extinct and by no machine critical so I won’t level out it once over again.

About a years of madness

Right here’s the crazy ingredient: timeBeginPeriod will be usually known as by any program and it adjustments the timer interrupt interval, and the timer interrupt is a global to hand helpful resource.

Let’s imagine that Job A is sitting in a loop calling Sleep(1). It shouldn’t be doing this, but it absolutely is, and by default it is waking up each and each 15.625 ms, or 64 times a 2nd. Then Job B comes along and calls timeBeginPeriod(2). This makes the timer interrupt hearth more usually and Job A is waking up 500 times a 2nd as an alternate of 64 times a 2nd. That’s crazy! However that’s how Windows has repeatedly labored.

At this level if Job C received here along and usually known as timeBeginPeriod(4) this wouldn’t change the relaxation – Job A would proceed to web up 500 times a 2nd. It’s now no longer closing-name-gadgets-the-tips, it’s lowest-place an whisper to-gadgets-the-tips.

To be more particular, no enviornment serene running program has specified the smallest timer interrupt duration in an prominent name to timeBeginPeriod will get to characteristic the worldwide timer interrupt interval. If that program exits or calls timeEndPeriod then the brand new minimum takes over. If a single program usually known as timeBeginPeriod(1) then that is the timer interrupt interval on your total machine. If one program usually known as timeBeginPeriod(1) and one other program then usually known as timeBeginPeriod(4) then the one ms timer interrupt interval will be the rules of the land.

powercfg /energy /duration 5This matters because a high timer interrupt frequency – and the linked high-frequency of thread scheduling – can ruin critical power, as mentioned here.

One case where timer-surely based entirely mostly scheduling is critical is when imposing a web browser. The JavaScript veteran has a characteristic usually known as setTimeout which asks the browser to name a JavaScript characteristic some replace of milliseconds later. Chromium uses timers (mostly WaitForSingleObject with timeouts in characteristic of Sleep) to place in force this and rather a lot of functionality. This usually requires raising the timer interrupt frequency. To be succesful to lower the battery-life implications of this Chromium has been modified now no longer too prolonged contained within the past in grunt that it doesn’t elevate the timer interrupt frequency above 125 Hz (8 ms interval) when running on battery.

timeGetTime

timeGetTime (now no longer to be stressed with GetTickCount) is a characteristic that returns the most smartly-cherished time, as up to this level by the timer interrupt. CPUs be elated historically now no longer been appropriate at conserving final time (their clocks deliberately fluctuate to take care of up far from being FM transmitters, and for diverse reasons) in grunt that they commonly depend on separate clock chips to dangle final time. Finding out from these clock chips is costly so Windows maintains a 64-bit counter of the time, in milliseconds, as up to this level by the timer interrupt. This timer is saved in shared reminiscence so any assignment can cheaply learn the most smartly-cherished time from there, with out having to take care of to the timer chip. timeGetTime calls ReadInterruptTick which at its core staunch reads this 64-bit counter. Straightforward!

Since this counter is up to this level by the timer interrupt we will have the option to video reward it and web the timer interrupt frequency.

The new undocumented actuality

With the Windows 10 2004 (April 2020 liberate) some of this quietly modified, but in a surely sophisticated approach. I first heard about this thru experiences that timeBeginPeriod didn’t work anymore. The very fact modified into once over again sophisticated than this.

Somewhat of experimentation gave sophisticated outcomes. After I ran a program that customarily known as timeBeginPeriod(2) then clockres confirmed that the timer interval modified into as soon as 2.0 ms, but a separate buy a see at program with a Sleep(1) loop modified into as soon as top likely waking up about 64 times a 2nd as an alternate of the five hundred times a 2nd that it could maybe maybe most likely be elated woken up under dilapidated adaptations of Windows.

It’s time to form science

I then wrote a pair of purposes which printed what modified into as soon as occurring. One program (change_interval.cpp) staunch sits in a loop calling timeBeginPeriod with intervals starting from 1 to fifteen ms. It holds each and each timer interval place an whisper to for four seconds, after which works to the next one, wrapping spherical when it is performed. It’s fifteen traces of code. Straightforward.

The rather a lot of program (measure_interval.cpp) runs some assessments to evaluate how mountainous its habits is altered by the habits of change_interval.cpp. It does this by gathering three objects of recordsdata.

  1. It asks the OS what the most smartly-cherished global timer resolution is, the usage of NtQueryTimerResolution.
  2. It measures the precision of timeGetTime by calling it in a loop except its return payment adjustments. When it adjustments then the amount it modified by is its precision.
  3. It measures the lengthen of Sleep(1) by calling it in a loop for a 2nd and counting what possibility of calls it would construct. The neatly-liked lengthen is staunch the reciprocal of the unreal of iterations.

@FelixPetriconi ran the assessments for me on Windows 10 1909 and I ran the assessments on Windows 10 2004. The outcomes (cleaned up to salvage away randomness) are proven here:

Desk of timeGetTime precision and Sleep(1) delays

What this implies is that timeBeginPeriod serene gadgets the worldwide timer interrupt interval, on all adaptations of Window. We are in a characteristic to direct from the outcomes of timeGetTime() that the interrupt fires on now no longer no longer up to 1 CPU core at that payment, and the time is up to this level. Unusual additionally that the two.0 on row one for 1909 modified into as soon as 2.0 on Windows XP, then 1.0 on Windows 7/8, and is outwardly relief to 2.0? I guess?

Then once over again the scheduler habits adjustments dramatically in Windows 10 2004. Beforehand the lengthen for Sleep(1) in any assignment modified into as soon as simply such because the timer interrupt interval (with an exception for timeBeginPeriod(1)), giving a graph like this:

Sleep(1) delays on Windows 10 1909 vs. Global interrupt interval

In Windows 10 2004 the mapping between timeBeginPeriod and the sleep lengthen in a single other assignment (one which didn’t name timeBeginPeriod) is extraordinary:

Sleep(1) delays on Windows 10 2004 vs. Global interrupt interval

The particular shape of the left facet of the graph is unclear but it absolutely indubitably slopes contained within the execrable approach from sooner than!

Why?

Implications

As modified into as soon as identified contained within the reddit/hacker-recordsdata discussion, the left half of of the graph looks to be an strive to simulate the “veteran” lengthen as carefully as that you just magnificent can also presumably mediate given the accessible precision of the worldwide timer interrupt. That is, with a 6 millisecond interrupt interval they lengthen for ~12 ms (two cycles) and with a 7 millisecond interrupt interval they lengthen for ~14 ms (two cycles). Then once over again, measuring of the very very top delays finds that in point of fact messier than that. With the timer interrupt place to 7 ms a Sleep(1) lengthen of 14 ms is never any longer even the most veteran consequence:

image

Some readers will be tempted in payment this on random noise on the machine, but when the timer interrupt frequency is at 9 ms and above there might be zero noise, in grunt that can now no longer be the explanation. Strive the up to this level code your self. The timer interrupt intervals from 4 ms to eight ms seem like in particular perplexing. Doubtlessly the interval measurements need to be performed with QueryPerformanceCounter since the most smartly-cherished code is plagued by altering scheduling tips and altering timer precision, which is messy.

Right here is all very authentic, and I don’t designate the explanation, or the implementation. Perhaps it’s a worm, but I doubt it. I believe that there might be sophisticated backwards compatibility common sense gradual this. However, the most highly atmosphere real approach to take care of up far from compatibility problems is to legend your adjustments, preferably upfront, and this looks to be buy to had been slipped in with out any particular person being notified.

Most purposes will be unaffected. If a assignment wants a sooner timer interrupt then it could maybe maybe most likely be calling timeBeginPeriod itself. That mentioned, here are the troubles that this could presumably place off:

  • A program might maybe presumably by likelihood consume that Sleep(1) and timeGetTime be elated the identical resolutions, and that assumption is damaged now. However, such an assumption looks to be like now no longer going.
  • A program might maybe presumably depend on a like a flash timer resolution and fail to characteristic an whisper to it. There had been a pair of claims that some video games be elated this field and there could be a tool usually known as Windows Machine Timer Machine and one other usually known as TimerResolution 1.2 that “repair” these video games by raising the timer interrupt frequency. These fixes presumably won’t work anymore, or now no longer no longer prior to now no longer as effectively. Perhaps this could presumably energy these video games to form a official repair, but except then this change is a backwards compatibility field.
  • A multi-assignment program will be elated its master dangle leer over program elevate the timer interrupt frequency after which place an whisper to that this could have an effect on the scheduling of its teen processes. This extinct to be a cheap map replace, and now it doesn’t work. Right here is how I modified into as soon as alerted to this field. The product in question now calls timeBeginPeriod in all of their processes in grunt that they are lustrous, thanks for asking, but their utility modified into as soon as misbehaving for a total lot of months with out a explanation.

Sacrifice

The change_interval.cpp buy a see at program top likely works if nothing has requested the next timer interrupt frequency. Since each and each Chrome and Visual Studio be elated a habits of doing this I wanted to form most of my experimentation with out a web entry to to the on-line whereas writing code in notepad. Somebody suggested Emacs but wading into that debate is more than I’m prepared to form.

I’d steal to listen in on more about this from Microsoft, along side any corrections to my diagnosis. Discussions:

Read More

Related Post

5 Commentaires

Leave a Comment

Recent Posts

An oil tanker with 60M gallons of oil aboard is all thru the meantime sinking [video]
Amazon’s $23M book about flies (2011)
Google Coral Dev Board mini SBC is now on hand for $100
Glow: Markdown reader for the terminal with a TUI and encrypted cloud stash
The manner you would possibly well abolish your occupation, one entirely extremely contented one year at a time

Recent Posts

An oil tanker with 60M gallons of oil aboard is all thru the meantime sinking [video]
Amazon’s $23M book about flies (2011)
Google Coral Dev Board mini SBC is now on hand for $100
Glow: Markdown reader for the terminal with a TUI and encrypted cloud stash
The manner you would possibly well abolish your occupation, one entirely extremely contented one year at a time
fr_FRFrench
en_USEnglish fr_FRFrench