Compartilhar via


Know Thy Tick

When I read something like “the clock interval… for most x86 multiprocessors is about 15 milliseconds” I’m compelled to determine the value of my clock, or “tick”, interval. Fortunately, the book I read this quote in, Windows Internals Fourth Edition provides a reference for helping me with my affliction.

The author, Mark Russinovich, of the aforementioned book has graciously made the utility ClockRes available on his web site. Running this utility, I was able to determine that the clock interval on my x86 multiprocessor PC is 15.625000 ms. Interesting, but my curious mind wants to know more.

Even more graciously, Mark has made the source code for ClockRes available. The function used in ClockRes to determine the tick interval is GetSystemTimeAdjustment . This function serves two purposes:

1) provide information about how and if the system periodically adjusts the time-of-day clock and

2) provide the interval between two successive system clock interrupts (i.e. the tick interval). Actually, the second purpose is really part of the first, but from my driven perspective, it’s the primary purpose of this function.

Armed with this information, I can start to connect a few dots without inflicting too much cerebral pain. Specifically, it explains why the return value from API function GetSystemTimeAsFileTime doesn’t update as frequently as one might expect. Given that the return value has a resolution of 100-nanoseconds, one might think that this function would provide a nifty high resolution timer. But, no, its system time and system time is only updated at the rate of the tick interval. And, to connect the dots, the tick interval is the value returned by function GetSystemTimeAdjustment.

Of course the real reason why the tick interval is important is that it affects thread scheduling. The Windows scheduler gives each thread a “quantum” of time to execute before allowing another task, at the same priority level, to run. The quantum that the scheduler assigns to a thread is a multiple of the tick interval. The specific quantum value chosen for a specific thread is bit beyond where I want to go with this article.

For now, let’s just examine the default quantum value for a foreground thread in XPe. In this case the Windows scheduler assigns a quantum of 18 or 6 tick intervals (Yes, to convert quantum to tick intervals, one must divide by 3. I could throw in a gratuitous comment about obfuscation here, but the reason for the multiple is to allow the scheduler the ability to “charge” a thread for doing an operation which causes it to suspend.) This means that on my PC, a foreground thread is allowed to hog the processor for about 94 milliseconds before another task of the same priority level is given a chance.

For some applications, one might want to be able to change the quantum setting. Fortunately, within limitations, one can. However, I’ll need to take this subject on in my next blog as this is a lengthy subject all on its own.

- Jim

Comments

  • Anonymous
    March 01, 2006
    Hi Jim,
    Thanks for the blog.
    >For some applications, one might want to be able to change
    >the quantum setting.
    >Fortunately, within limitations, one can.

    I was trying to make system clock interval smaller and SetSystemTimeAdjustment() obviously (dah!) did not help much.
    Any hints on how to change it?

    >However, I’ll need to take this subject on in my next blog
    >as this is a lengthy subject all on its own.
    Looking forward.
    Alexei

  • Anonymous
    March 01, 2006
    Just for notification
  • Anonymous
    March 01, 2006
    Hi Alexei,

    Unfortunately, the system clock interval, or tick, is set by the HAL and can't be changed. Most single processor boards have a clock interval of about 10 milliseconds.

    You can, however, change the thread quantum; I've submitted a blog article on this subject which should be posted shortly. If you don't want to wait, I suggest you checkout the Quantum section of Chapter 6 of Mark Russinovich's Windows Internals Fourth Edition.

    I hope this helps.

    Jim
  • Anonymous
    March 01, 2006
    Thanks Jim,
    I am reading it right now :-(
    Alexei
  • Anonymous
    March 08, 2006
    The comment has been removed
  • Anonymous
    March 09, 2006
    Hi Lucas,
    Thanks for the post and app.
    I did run your application on Win2K.
    Numbers were:
    Minimum Resolution   15.625
    Maximum Resolution   1.000 (?)
    Current Resolution     15.625

    I have looked at your article again and decided to start Multimedia Player.

    Run you app again.
    Minimum Resolution   15.625
    Maximum Resolution   1.000 (?)
    Current Resolution     0.977

    So, the question still remains:
    What is Minimum Resolution and how to change it.

    Thanks,
    Alexei

  • Anonymous
    March 09, 2006
    Ok,
    My laizy. Spent more time writing the post than a test.
    BTW: Lucas thanks for the hint.

    This does it:

    #include "mmsystem.h"
    BOOL SetRes()
    {
      #define TARGET_RESOLUTION 1  // 1-millisecond target resolution

      TIMECAPS tc;
      UINT     wTimerRes;

      if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)
      {
          // Error
         return FALSE;
      }

      wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
      MMRESULT res = timeBeginPeriod(wTimerRes);
     
      return (TIMERR_NOERROR == res);
    }

    Hope this helps someone!
    Alexei
  • Anonymous
    March 09, 2006
    Sorry about the Min and Max names... I guess it should be maximum precision :)

    If you don't want to have to use the winmm.lib and you have access to the DDK you can use ntdll.lib and call the undocumented functions:

    NtSetTimerResolution(
     IN ULONG                DesiredResolution,
     IN BOOLEAN              SetResolution,
     OUT PULONG              CurrentResolution );

    NtQueryTimerResolution(
     OUT PULONG              MinimumResolution,
     OUT PULONG              MaximumResolution,
     OUT PULONG              CurrentResolution );

    Lucas
  • Anonymous
    March 09, 2006
    Thanks much for pointing me at original nt calls, that's much better.
    I usually use LoadLibrary to load ntdll.

    Regards,
    Alexei