[Python-Dev] Use QueryPerformanceCounter() for time.monotonic() and/or time.highres()? (original) (raw)

Guido van Rossum guido at python.org
Fri Mar 30 23:35:29 CEST 2012


On Fri, Mar 30, 2012 at 1:52 PM, Guido van Rossum <guido at python.org> wrote:

On Fri, Mar 30, 2012 at 1:21 PM, Victor Stinner <victor.stinner at gmail.com> wrote:

Windows provides two main monotonic clocks: QueryPerformanceCounter() and GetTickCount(). QueryPerformanceCounter() has a good accuracy (0.3 ns - 5 ns) but has various issues and is know to not have a steady rate. GetTickCount() has a worse accuracy (1 ms - 15 ms) but is more stable and behave better on system suspend/resume.

The glib library prefers GetTickCount() over QueryPerformanceCounter() for its ggetmonotonictime() because "The QPC timer has too many issues to be used as is." Ihttp://mail.gnome.org/archives/commits-list/2011-November/msg04589.html The Qt library tries QueryPerformanceCounter() but may fallback to GetTickCount() if it is not available. python-monotonic-time only uses GetTickCount() or GetTickCount64(). It is important to decide which clock is used for the Python time.monotonic() because it may change the design of the PEP 418. If we use GetTickCount() for time.monotonic(), we should use QueryPerformanceCounter() for time.highres(). But in this case, it means that time.highres() is not a simple "try monotonic or falls back to system time", but may use a different clock with an higher resolution. So we might add a third function for the "try monotonic or falls back to system time" requirement. Python implements time.clock() using QueryPerformanceCounter() on Windows. Oh dear. I really want to say that 15 ms is good enough. Some possible exceptions I can think of: - Profiling. But this really wants to measure CPU time anyways, and it already uses a variety of hacks and heuristics to pick the best timer, so I don't really care. - Certain algorithms for thread (or even process?) communication might benefit from being able to set very short timeouts. But it seems you can just specify a timeout when waiting for a lock and it will be taken care of. So probably a non-use-case. So I think I still prefer GetTickCount*() over QueryPerformanceCounter(). And this is another reason why I don't like highres as a name -- as I said, I really prefer to have just two new functions, one that's a decent OS-provided timer that isn't affected by wall clock adjustments, if there is one, and the other strictly an alias for that one with a fallback to time.time() if there isn't one. Having two different OS-provided timers with different pros and cons will just make it too hard for users to decide, and hence we'll see a higher rate of using the wrong timer. (In fact, this even argues against having both the timer with fallback and the timer without fallback. So maybe we should just have a single timer function, with fallback, and a separate mechanism to inquire its properties.)

And disagreeing with myself, I just found myself using a tool for RPC analytics that displays times in msec, and the times are often between 1 and 20 msec. Here a 15 msec timer would be horrible, and I see no alternative but to use QPC()... (Well, if the tool ran on Windows, which it doesn't. :-)

Can we tell what the accuracy of GetTickCount*() is when we first request the time, and decode then?

Can you go into more detail about QPC()'s issues? What is unsteady about its rate?

-- --Guido van Rossum (python.org/~guido)



More information about the Python-Dev mailing list