8

My system is suffering from a high timer resolution (NtQueryTimerResolution returns 0.5ms).

Maximum timer interval: 15.600 ms
Minimum timer interval: 0.500 ms
Current timer interval: 0.500 ms

Some process must be calling NtSetTimerResolution with a value of 5000 (0.5ms), but how can I determine which one? I saw Intel has a tool called Battery Life Analyzer that shows the current timer resolution per process, but that tool is only available to Intel partners. Is there another tool or a way to see it via WinDbg? Note: It seems to happen at boot time as setting a breakpoint isn't working (the resolution is already high when the debugger starts).

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • 3
    Powercfg.exe /energy will generate a slick report that will finger the evil-doer. Use superuser.com to ask questions like this. – Hans Passant May 05 '14 at 11:57
  • 1
    @HansPassant thanks but it didn't work. The report says `Request Count 1` but doesn't show who requested it. I uploaded the complete report [here](http://rustyx.org/energy-report.html). – rustyx May 05 '14 at 14:02
  • Powercfg.exe /energy isn't doing it, Intel can do it. I'd like to see the API call as well. – Arno May 12 '14 at 18:11
  • Your report shows that it was a driver that changed it. Harder to narrow down, other than by selectively disabling non-standard drivers one by one. You really do need to ask this at superuser.com – Hans Passant May 12 '14 at 18:48
  • if setting a breakpoint at start time does not works, the process should be "System", since you should able to debug the machine before the first process is created. – Gonmator May 16 '14 at 14:57
  • I've pushed this matter by another [question](http://stackoverflow.com/q/23734775/1504523). Maybe the question itself gets you a few more details. – Arno May 19 '14 at 10:15

3 Answers3

4

I found that Windows 7 keeps track of timer resolution per process in the _EPROCESS kernel structure.

With debugging enabled (boot with /debug) it is possible to browse the ExpTimerResolutionListHead list with windbg (run windbg -kl) and extract timer information like this:

lkd> !list "-e -x \"dt nt!_EPROCESS @$extret-@@(#FIELD_OFFSET(nt!_EPROCESS,TimerResolutionLink)) ImageFileName UniqueProcessId SmallestTimerResolution RequestedTimerResolution\" nt!ExpTimerResolutionListHead"

In my case however the process ID was NULL (probably because a driver made the request), and I still couldn't figure out which driver it was.

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • +1 BTW: powercfg -energy does not inject any code, thus it must get the information somehow else. But it also cannot resolve timer settings acquired by a driver. – Arno May 21 '14 at 07:00
  • powercfg -energy also shows the call stack of the call which set process' highest timer resolution. I assume this call stack works also retroactively - for calls that were done before running powercfg -energy. So perhaps kernel has even information for these callstacks too. I only wonder why...? And mainly in this context - where could this information be located? Is it also in the same kernel data structure? One could also wonder why drivers' call stacks are not stored there. Drivers run under the System process if I understand correctly. – Roland Pihlakas Jun 29 '14 at 13:33
  • I did a little Google search. It looks that yes, _EPROCESS contains also diagnostic stacks related to the timer resolution requests: http://msdn.moonsols.com/win7rtm_x86/EPROCESS.html – Roland Pihlakas Dec 19 '14 at 05:09
3

The only way I know and have used so far is injecting into each of running processes and inside that process calling timeEndPeriod for each increased resolution (values 1-15) in a loop over these resolutions and checking whether the timeEndPeriod call for a current resolution returns TIMERR_NOCANDO or TIMERR_NOERROR (note: these return values are NOT correspondingly false and true). And if it returns TIMERR_NOERROR then concluding that the program is using that frequency, and then calling again timeBeginPeriod to restore the original resolution requested by the program.

Unfortunately this method does not detect the 0.5 ms timer resolutions that can be set by undocumented NtSetTimerResolution function.

If you want to continuously monitor the new timer resolutions then hooking calls to undocumented NtSetTimerResolution function in ntdll.dll is the way I use currently (the function's signature can be taken for example from here).

Unfortunately hooking does not detect timer resolutions that were requested before the hook was installed, so you need to combine it with the above timeEndPeriod trick and note also that the 0.5 ms resolution requests before the hooking stay undetected.

And I agree, this method seems cumbersome. Moreover, it is a bit intrusive since it modifies the state of the process, and also assumes that you are able to inject into all processes.

If anybody has better methods, I would be interested knowing about them too.

TLama
  • 75,147
  • 17
  • 214
  • 392
Roland Pihlakas
  • 4,246
  • 2
  • 43
  • 64
  • 1
    I like the inject idea! But firstly, the injected code would only have to check for the "current" resolution and secondly it could also use NtSetTimerResolution to test for STATUS_TIMER_RESOLUTION_NOT_SET. – Arno May 20 '14 at 07:14
  • However, this would cause a small interval while the application loses its desired resolution. Do you think that's the way `powercfg - energy´ is implemented? And: Drivers? System at boot time? Anyway bounty granted, thanks for your effort. I've pulled the attention to this matter again in another question [here](http://stackoverflow.com/q/23734775/1504523). – Arno May 20 '14 at 07:22
  • How can I inject into a process and call timeEndPeriod? I'm having the same problem he is, except it's calling for the timer frequency to be 1.25ms. – Joe Simmons Dec 10 '14 at 20:23
  • @JoeSimmons Hello, about injecting...it is a bit involved topic and there are various ways. Maybe I will post some link to an overview later. But about the second thing You mention: why do You think the timer interval is 1.25ms? I wonder how did You get that info since it contains fractional value and I am not aware of functions returning fractional values for timer resolution except the 0.5ms interval case. In case You obtained this value statistically then well, I suspect the intervals might be like 2-1-1-1 and Arno might know a lot more about the rhythms of Windows timers, check his website – Roland Pihlakas Dec 11 '14 at 02:56
  • @RolandPihlakas Using [TimerResolution](http://www.lucashale.com/timer-resolution/), it shows a Current Resolution of 1.250ms. Windows energy report does not show which process did it. – Joe Simmons Dec 11 '14 at 15:42
  • @JoeSimmons Oh, this program apparently does some statistical approach, I guess. Yes, the actual timer resolutions might be fractional. Somewhere in the web there is a table with typical actual values that should correspond the integer values seen in the API. Usually the actual values are bigger than the API values and multiple API values might have same actual resolution that corresponds to them (for example API 7ms => actual 10.6ms, API 8ms => actual 10.6ms, API 9ms => actual 10.6ms, API 10ms => actual 16.8ms - this is just an example, the numbers might not be same in real life). – Roland Pihlakas Dec 13 '14 at 05:26
  • @RolandPihlakas I'd just like to resolve the issue and have my timer resolution be 15.6ms like my laptop. Any articles on how to do this besides Windows energy report would be nice :) The injection idea seems nice, though. I only have like 30 processes running with all my stuff closed, so trying them all wouldn't be too painful. – Joe Simmons Dec 13 '14 at 07:19
  • @JoeSimmons Oh, I understand now. But why don't You like energy report? It would be useful. Since if the culprit is some service process then the injection procedure is again a bit more complex and on the other hand it would not make sense to implement all the nuances in case You actually don't need it. – Roland Pihlakas Dec 13 '14 at 13:59
  • @RolandPihlakas I like the energy report, but it doesn't show the process that requested that resolution. It's probably a driver. I really want to resolve this so my pc doesn't need to use as much power. I could show you the energy report, if you'd like (we should continue in a PM, if so). – Joe Simmons Dec 15 '14 at 21:24
  • @JoeSimmons I created the chat room here: http://chat.stackoverflow.com/rooms/66951/how-to-tell-which-process-set-the-high-timer-resolution-in-windows Yes, if You can, please send or upload the energy report somehow – Roland Pihlakas Dec 16 '14 at 12:00
3

Input

You can run the following command in a Administrative CMD Prompt:

c:\temp> powercfg -energy duration 5

This will create a report called: C:\temp\energy-report.html

This report will show you which processes have changed the Clock Latency/Resolution on your computer. Normally these are RTC (Real-Time Communication) applications, but as you have noticed can be Chrome and other applications.

Output

An (albeit German) example of the output looks like this. Sorry I don't have access to an English client at the moment.

First Statement in Report: Something has changed

Plattform-Zeitgeberauflösung:Plattform-Zeitgeberauflösung

Die standardmäßige Plattform-Zeitgeberauflösung beträgt 15,6 ms (15625000 ns) und sollte immer dann verwendet werden, wenn sich das System im Leerlauf befindet. Wenn die Zeitgeberauflösung erhöht wird, sind die Technologien zur Prozessorenergieverwaltung möglicherweise nicht wirksam. Die erhöhte Zeitgeberauflösung kann auf eine Multimediawiedergabe oder Grafikanimationen zurückzuführen sein.

Aktuelle Zeitgeberauflösung (100-ns-Einheiten) 10000 <<=== CURRENT SETTING
Maximale Zeitgeberperiode (100-ns-Einheiten) 156250 <<== DEFAULT SETTING

Second Statement in Report: The Culprit

Plattform-Zeitgeberauflösung:Ausstehende Zeitgeberanforderung

Von einem Programm oder Dienst wurde eine Zeitgeberauflösung angefordert, die kleiner als die maximale Zeitgeberauflösung der Plattform ist.

Angeforderter Zeitraum 10000 <<== Requested Clock Latency
ID des anfordernden Prozesses 12592 <<== Process ID of application requesting different Clock Latency
Pfad des anfordernden Prozesses \Device\HarddiskVolume4\Program Files (x86)\C4B\XPhone Connect Client\C4B.XPhone.Commander.exe <<== The culprit

The information can be separated from each other and can contain different modules in between the individual blocks, but you should be able to find the culprit armed with the information provided above.

John K. N.
  • 159
  • 16