python-peps/pep-0418.txt

1202 lines
42 KiB
Plaintext
Raw Normal View History

2012-03-26 19:12:03 -04:00
PEP: 418
Title: Add a monotonic time functions
2012-03-26 19:12:03 -04:00
Version: $Revision$
Last-Modified: $Date$
Author: Victor Stinner <victor.stinner@gmail.com>
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 26-March-2012
Python-Version: 3.3
Abstract
========
Add time.monotonic() and time.get_clock_info(name) functions to Python 3.3.
2012-03-26 19:12:03 -04:00
Rationale
=========
Use cases:
* Display the current time to a human (e.g. display a calendar or draw
2012-03-31 02:53:07 -04:00
a wall clock): use system clock, i.e. time.time() or
datetime.datetime.now().
* Event scheduler, timeout: time.monotonic().
* Benchmark, profiling: time.clock() on Windows, time.monotonic(),
or fallback to time.time()
2012-03-26 19:12:03 -04:00
Functions
=========
2012-03-31 02:53:07 -04:00
To fulfill the use cases, the functions' properties are:
* time.time(): system clock, "wall clock".
* time.monotonic(): monotonic clock
2012-03-31 22:11:08 -04:00
* time.get_clock_info(name): get information on the specified time function
time.time()
-----------
The system time is the "wall clock". It can be set manually by the
system administrator or automatically by a NTP daemon. It can jump
2012-03-31 02:53:07 -04:00
backward and forward. It is not monotonic.
It is available on all platforms and cannot fail.
Pseudo-code [#pseudo]_::
if os.name == "nt":
def time():
return _time.GetSystemTimeAsFileTime()
else:
def time():
if hasattr(time, "clock_gettime"):
try:
# resolution = 1 nanosecond
return time.clock_gettime(time.CLOCK_REALTIME)
except OSError:
# CLOCK_REALTIME is not supported (unlikely)
pass
if hasattr(_time, "gettimeofday"):
try:
# resolution = 1 microsecond
return _time.gettimeofday()
except OSError:
# gettimeofday() should not fail
pass
if hasattr(_time, "ftime"):
# resolution = 1 millisecond
return _time.ftime()
else:
# resolution = 1 second
return _time.time()
time.monotonic()
----------------
Monotonic clock, cannot go backward. Its rate may be adjusted by NTP. The
reference point of the returned value is undefined so only the difference of
consecutive calls is valid.
The elapsed time may or may not include time the system spends in
2012-03-31 02:53:07 -04:00
sleep or hibernation; this depends on the operating system.
Availability: Windows, Mac OS X, Unix.
Pseudo-code [#pseudo]_::
if os.name == 'nt':
# GetTickCount64() requires Windows Vista, Server 2008 or later
if hasattr(time, '_GetTickCount64'):
def monotonic():
return _time.GetTickCount64() * 1e-3
else:
def monotonic():
ticks = _time.GetTickCount()
if ticks < monotonic.last:
# Integer overflow detected
monotonic.delta += 2**32
monotonic.last = ticks
return (ticks + monotonic.delta) * 1e-3
monotonic.last = 0
monotonic.delta = 0
elif os.name == 'mac':
def monotonic():
if monotonic.factor is None:
factor = _time.mach_timebase_info()
monotonic.factor = timebase[0] / timebase[1]
return _time.mach_absolute_time() * monotonic.factor
monotonic.factor = None
elif hasattr(time, "clock_gettime"):
def monotonic():
if monotonic.use_clock_highres:
try:
time.clock_gettime(time.CLOCK_HIGHRES)
except OSError:
monotonic.use_clock_highres = False
return time.clock_gettime(time.CLOCK_MONOTONIC)
monotonic.use_clock_highres = (hasattr(time, 'clock_gettime')
and hasattr(time, 'CLOCK_HIGHRES'))
On Windows, QueryPerformanceCounter() is not used even though it has a better
accuracy than GetTickCount(). It is not reliable and has too many issues.
.. note::
time.monotonic() detects GetTickCount() integer overflow (32 bits, roll-over
after 49.7 days): it increases a delta by 2\ :sup:`32` each time than an
overflow is detected. The delta is stored in the process-local state and so
the value of time.monotonic() may be different in two Python processes
running for more than 49 days.
time.sleep()
------------
Suspend execution for the given number of seconds. The actual suspension time
may be less than that requested because any caught signal will terminate the
time.sleep() following execution of that signal's catching routine. Also, the
suspension time may be longer than requested by an arbitrary amount because of
the scheduling of other activity in the system.
Pseudo-code [#pseudo]_::
try:
import select
except ImportError:
has_select = False
else:
has_select = hasattr(select, "select")
if has_select:
def sleep(seconds):
return select.select([], [], [], seconds)
elif hasattr(_time, "delay"):
def sleep(seconds):
milliseconds = int(seconds * 1000)
_time.delay(milliseconds)
elif os.name == "nt":
def sleep(seconds):
milliseconds = int(seconds * 1000)
win32api.ResetEvent(hInterruptEvent);
win32api.WaitForSingleObject(sleep.sigint_event, milliseconds)
sleep.sigint_event = win32api.CreateEvent(NULL, TRUE, FALSE, FALSE)
# SetEvent(sleep.sigint_event) will be called by the signal handler of SIGINT
elif os.name == "os2":
def sleep(seconds):
milliseconds = int(seconds * 1000)
DosSleep(milliseconds)
else:
def sleep(seconds):
seconds = int(seconds)
_time.sleep(seconds)
2012-03-31 22:11:08 -04:00
time.get_clock_info(name)
-------------------------
Get information on the specified clock. Supported clocks:
2012-03-31 22:11:08 -04:00
* "clock": time.clock()
* "monotonic": time.monotonic()
2012-03-31 22:11:08 -04:00
* "time": time.time()
Return a dictionary with the following keys:
2012-03-31 22:11:08 -04:00
* Mandatory keys:
* "function" (str): name of the underlying operating system function.
Examples: "QueryPerformanceCounter()", "clock_gettime(CLOCK_REALTIME)".
* "resolution" (float): resolution in seconds of the clock
* "is_monotonic" (bool): True if the clock cannot go backward
* Optional keys:
* "accuracy" (float): accuracy in seconds of the clock
* "is_adjusted" (bool): True if the clock can be adjusted (e.g. by a NTP
daemon)
2012-03-31 22:11:08 -04:00
Definitions
===========
Resolution
----------
The resolution is the smallest difference between two timestamps supported by
the format used by the clock. For example, clock_gettime() uses a timespec
structure which has two integer fields, tv_sec and tv_nsec, so the resolution
is 1 nanosecond.
Accuracy
--------
The accuracy is the effective smallest difference of two timestamps of the
clock. It does not reflect the stability the clock rate. For example,
QueryPerformanceCounter() has a good accuracy but is known to not have a steady
rate.
Monotonic
---------
A monotonic clock cannot go backward. It may give the same value for two close
reads depending on the clock resolution.
On Linux, CLOCK_MONOTONIC is a monotonic clock but its rate is adjusted by NTP.
Steady
------
A steady clock is a clock with a stable rate.
2012-04-03 19:49:55 -04:00
The `C++ Timeout Specification
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3128.html>`_ uses the
following definition: "Objects of class steady_clock represent clocks for which
values of time_point advance at a steady rate relative to real time. That is,
the clock may not be adjusted."
Hardware clocks
===============
* HPET: An HPET chip consists of a 64-bit up-counter (main counter)
counting at least at 10 MHz and a set of up to 256 comparators (at
least 3). Each HPET can have up to 32 timers.
* TSC (Time Stamp Counter): Historically, the TSC increased with every internal
processor clock cycle, but now the rate is usually constant (even if the
processor changes frequency) and usually equals the maximum processor
frequency. Multiple cores having different TSC values. Hibernation of system
will reset TSC value. The instructor RDTSC can be used to read this counter.
CPU frequency scaling for power saving.
* ACPI PMTMR (power management timer): ACPI 24-bit timer with a frequency
of 3.5 MHz (3,579,545 Hz). HPET can cause around 3 seconds of drift per day.
* Cyclone: The Cyclone timer uses a 32-bit counter on IBM Extended
X-Architecture (EXA) chipsets which include computers that use the
IBM "Summit" series chipsets (ex: x440). This is available in IA32
and IA64 architectures.
* PIT (programmable interrupt timer): Intel 8253/8254 chipsets with a
configurable frequency in range 18.2 Hz - 1.2 MHz. It is a 16-bit counter.
* RTC (Real-time clock). Most RTCs use a crystal oscillator with a frequency of
32,768 Hz
NTP adjustment
==============
NTP has diffent methods to adjust a clock:
* "slewing": change the clock frequency to be slightly faster or slower
(which is done with adjtime()). Since the slew rate is limited to 0.5 ms/s,
each second of adjustment requires an amortization interval of 2000 s. Thus,
an adjustment of many seconds can take hours or days to amortize.
* "stepping": jump by a large amount in a single discrete step (which is done
with settimeofday())
By default, the time is slewed if the offset is less than 128 ms, or stepped
otherwise.
Slewing is generally desirable (i.e. we should use CLOCK_MONOTONIC, not
CLOCK_MONOTONIC_RAW) if one wishes to measure "real" time (and not a time-like
object like CPU cycles). This is because the clock on the other end of the NTP
connection from you is probably better at keeping time: hopefully that thirty
five thousand dollars of Cesium timekeeping goodness is doing something better
than your PC's $3 quartz crystal, after all.
Get more detail in the `documentation of the NTP daemon
<http://doc.ntp.org/4.1.2/ntpd.htm>`_.
Operating system clocks
=======================
2012-03-26 19:12:03 -04:00
Monotonic clocks
----------------
2012-04-10 18:42:54 -04:00
========================= ========== =============== ============= ===============
Name Resolution Adjusted Include sleep Include suspend
========================= ========== =============== ============= ===============
gethrtime 1 ns No Yes Yes
CLOCK_HIGHRES 1 ns No Yes ?
CLOCK_MONOTONIC 1 ns Slewed on Linux Yes No
CLOCK_MONOTONIC_RAW 1 ns No Yes No
mach_absolute_time() 1 ns No Yes No
2012-04-10 18:42:54 -04:00
QueryPerformanceCounter() \- No Yes ?
GetTickCount[64]() 1 ms No Yes Yes
timeGetTime() 1 ms No Yes ?
========================= ========== =============== ============= ===============
Examples of clock accuracy on x86_64:
========================= ================ ===============
Name Operating system Accuracy
========================= ================ ===============
CLOCK_MONOTONIC_RAW Linux 3.2 1 ns
CLOCK_MONOTONIC Linux 3.2 1 ns
CLOCK_HIGHRES SunOS 5.11 2 ns
CLOCK_MONOTONIC SunOS 5.11 2 ns
QueryPerformanceCounter Windows Seven 10 ns
CLOCK_MONOTONIC FreeBSD 8.2 11 ns
CLOCK_MONOTONIC OpenBSD 5.0 10 ms
GetTickCount Windows Seven 15.6 ms
========================= ================ ===============
For CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW, the accuracy of this table is the
result of clock_getres(). It looks like Linux does not implement
clock_getres() and always return 1 nanosecond.
mach_absolute_time
^^^^^^^^^^^^^^^^^^
Mac OS X provides a monotonic clock: mach_absolute_time(). It is
based on absolute elapsed time delta since system boot. It is not
adjusted and cannot be set.
mach_timebase_info() gives a fraction to convert the clock value to a
number of nanoseconds. According to the documentation (`Technical Q&A
QA1398 <https://developer.apple.com/library/mac/#qa/qa1398/>`_),
2012-03-31 02:53:07 -04:00
mach_timebase_info() is always equal to one and never fails, even
if the function may fail according to its prototype.
2012-03-26 19:12:03 -04:00
2012-03-31 02:53:07 -04:00
mach_absolute_time() stops during a sleep on a PowerPC CPU, but not on
an Intel CPU: `Different behaviour of mach_absolute_time() on i386/ppc
<http://lists.apple.com/archives/PerfOptimization-dev/2006/Jul/msg00024.html>`_.
mach_absolute_time() has a resolution of 1 nanosecond.
CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2012-03-31 02:53:07 -04:00
CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW represent monotonic time since
some unspecified starting point. They cannot be set.
Documentation: refer to the manual page of your operating system.
Examples:
* `FreeBSD clock_gettime() manual page
<http://www.freebsd.org/cgi/man.cgi?query=clock_gettime>`_
* `Linux clock_gettime() manual page
<http://linux.die.net/man/3/clock_gettime>`_
CLOCK_MONOTONIC is available at least on the following operating systems:
* DragonFly BSD, FreeBSD >= 5.0, OpenBSD, NetBSD
* Linux
* Solaris
The following operating systems don't support CLOCK_MONOTONIC:
* GNU/Hurd (see `open issues/ clock_gettime
<http://www.gnu.org/software/hurd/open_issues/clock_gettime.html>`_)
* Mac OS X
* Windows
On Linux, NTP may adjust the CLOCK_MONOTONIC rate (slewed), but it cannot
jump backward.
CLOCK_MONOTONIC_RAW is specific to Linux. It is similar to CLOCK_MONOTONIC, but
provides access to a raw hardware-based time that is not subject to NTP
adjustments. CLOCK_MONOTONIC_RAW requires Linux 2.6.28 or later.
2012-03-26 19:12:03 -04:00
CLOCK_MONOTONIC stops while the machine is suspended.
2012-03-26 19:12:03 -04:00
clock_gettime() fails if the system does not support the specified
2012-03-31 02:53:07 -04:00
clock, even if the standard C library supports it. For example,
CLOCK_MONOTONIC_RAW requires a kernel version 2.6.28 or later.
2012-03-26 19:12:03 -04:00
clock_getres() gives the clock resolution. It is 1 nanosecond on
Linux.
2012-03-26 19:12:03 -04:00
.. note::
2012-03-31 02:53:07 -04:00
clock_gettime() requires to link the program against the rt
(real-time) library.
.. note::
Linux provides also CLOCK_MONOTONIC_COARSE since Linux 2.6.32 which has less
accurate than CLOCK_MONOTONIC but is faster.
2012-03-26 19:12:03 -04:00
Windows: QueryPerformanceCounter
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
High-resolution performance counter. It is monotonic.
QueryPerformanceFrequency() gives its frequency.
2012-03-31 02:53:07 -04:00
It has a much higher resolution, but has lower long term accuracy than
GetTickCount() and timeGetTime() clocks. For example, it will drift
compared to the low precision clocks.
Documentation:
* `MSDN: QueryPerformanceCounter() documentation
<http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904%28v=vs.85%29.aspx>`_
* `MSDN: QueryPerformanceFrequency() documentation
<http://msdn.microsoft.com/en-us/library/windows/desktop/ms644905%28v=vs.85%29.aspx>`_
Hardware clocks used by QueryPerformanceCounter:
* Windows XP: RDTSC instruction of Intel processors, the clock
frequency is the frequency of the processor (between 200 MHz and 3
2012-03-31 02:53:07 -04:00
GHz, usually greater than 1 GHz nowadays).
* Windows 2000: ACPI power management timer, frequency = 3,549,545 Hz.
It can be forced through the "/usepmtimer" flag in boot.ini.
.. * Windows 95/98: 8245 PIT chipset, frequency = 1,193,181 Hz
QueryPerformanceFrequency() should only be called once: the frequency
will not change while the system is running. It fails if the
installed hardware does not support a high-resolution performance
counter.
QueryPerformanceCounter() cannot be adjusted:
`SetSystemTimeAdjustment()
<http://msdn.microsoft.com/en-us/library/windows/desktop/ms724943(v=vs.85).aspx>`_
2012-03-31 02:53:07 -04:00
only adjusts the system time.
Bugs:
* The performance counter value may unexpectedly leap forward because
2012-03-31 02:53:07 -04:00
of a hardware bug, see `KB274323`_.
* On VirtualBox, QueryPerformanceCounter() does not increment the high
part every time the low part overflows, see `Monotonic timers
<http://code-factor.blogspot.fr/2009/11/monotonic-timers.html>`_
(2009).
* VirtualBox had a bug in its HPET virtualized device:
QueryPerformanceCounter() did jump forward by approx. 42 seconds (`issue
#8707 <https://www.virtualbox.org/ticket/8707>`_).
* Windows XP had a bug (see `KB896256`_): on a multiprocessor
computer, QueryPerformanceCounter() returned a different value for
each processor. The bug was fixed in Windows XP SP2.
* Issues with processor with variable frequency: the frequency is changed
depending on the workload to reduce memory consumption.
* Chromium don't use QueryPerformanceCounter() on Athlon X2 CPUs (model 15)
because "QueryPerformanceCounter is unreliable" (see base/time_win.cc in
Chromium source code)
.. _KB896256: http://support.microsoft.com/?id=896256
.. _KB274323: http://support.microsoft.com/?id=274323
Windows: GetTickCount(), GetTickCount64()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
GetTickCount() and GetTickCount64() are monotonic, cannot fail and are
not adjusted by SetSystemTimeAdjustment(). MSDN documentation:
`GetTickCount()
<http://msdn.microsoft.com/en-us/library/windows/desktop/ms724408(v=vs.85).aspx>`_,
`GetTickCount64()
<http://msdn.microsoft.com/en-us/library/windows/desktop/ms724411(v=vs.85).aspx>`_.
2012-03-31 02:53:07 -04:00
The elapsed time retrieved by GetTickCount() or GetTickCount64()
includes time the system spends in sleep or hibernation.
GetTickCount64() was added to Windows Vista and Windows Server 2008.
The clock resolution is 1 millisecond. Its accuracy is usually around
2012-03-31 02:53:07 -04:00
15 ms. It is possible to improve the accuracy using the `undocumented
NtSetTimerResolution() function
<http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Time/NtSetTimerResolution.html>`_.
There are applications using this undocumented function, example:
`Timer Resolution <http://www.lucashale.com/timer-resolution/>`_.
WaitForSingleObject() use the same timer than GetTickCount() with the same
resolution.
GetTickCount() has an accuracy of 55 ms on Windows 9x.
2012-03-26 19:12:03 -04:00
Windows: timeGetTime
^^^^^^^^^^^^^^^^^^^^
The timeGetTime function retrieves the system time, in milliseconds.
2012-03-31 02:53:07 -04:00
The system time is the time elapsed since Windows was started. Read
the `timeGetTime() documentation
<http://msdn.microsoft.com/en-us/library/windows/desktop/dd757629(v=vs.85).aspx>`_.
The return type of timeGetTime() is a 32-bit unsigned integer. As
GetTickCount(), timeGetTime() rolls over after 2^32 milliseconds (49.7
days).
2012-04-10 18:42:54 -04:00
The elapsed time retrieved by timeGetTime() includes time the system spends in
sleep.
The default precision of the timeGetTime function can be five
milliseconds or more, depending on the machine.
timeBeginPeriod() can be used to increase the precision of timeGetTime() up to
1 millisecond, but it negatively affects power consumption. Calling
timeBeginPeriod() also affects the granularity of some other timing calls, such
as CreateWaitableTimer(), WaitForSingleObject() and Sleep().
.. note::
2012-03-31 02:53:07 -04:00
timeGetTime() and timeBeginPeriod() are part the Windows multimedia
2012-03-31 02:53:07 -04:00
library and so require to link the program against winmm or to
dynamically load the library.
Solaris: CLOCK_HIGHRES
^^^^^^^^^^^^^^^^^^^^^^
2012-03-31 02:53:07 -04:00
The Solaris OS has a CLOCK_HIGHRES timer that attempts to use an
optimal hardware source, and may give close to nanosecond resolution.
CLOCK_HIGHRES is the nonadjustable, high-resolution clock. For timers
created with a clockid_t value of CLOCK_HIGHRES, the system will
attempt to use an optimal hardware source.
Solaris: gethrtime
^^^^^^^^^^^^^^^^^^
The gethrtime() function returns the current high-resolution real
time. Time is expressed as nanoseconds since some arbitrary time in
the past; it is not correlated in any way to the time of day, and thus
is not subject to resetting or drifting by way of adjtime() or
settimeofday(). The hires timer is ideally suited to performance
measurement tasks, where cheap, accurate interval timing is required.
The linearity of gethrtime() is not preserved accross cpr
suspend-resume cycle (`Bug 4272663
<http://wesunsolve.net/bugid/id/4272663>`_).
Read the `gethrtime() manual page of Solaris 11
<http://docs.oracle.com/cd/E23824_01/html/821-1465/gethrtime-3c.html#scrolltoc>`_.
On Solaris, gethrtime() is the same as clock_gettime(CLOCK_MONOTONIC).
2012-03-26 19:12:03 -04:00
System time clocks
------------------
========================= ===============
Name Resolution
========================= ===============
CLOCK_REALTIME 1 ns
GetSystemTimeAsFileTime 100 ns
gettimeofday() 1 µs
ftime() 1 ms
time() 1 sec
========================= ===============
Examples of clock accuracy on x86_64:
========================= ================ ===============
Name Operating system Accuracy
========================= ================ ===============
CLOCK_REALTIME Linux 3.2 1 ns
CLOCK_REALTIME FreeBSD 8.2 11 ns
CLOCK_REALTIME SunOS 5.11 10 ms
CLOCK_REALTIME OpenBSD 5.0 10 ms
GetSystemTimeAsFileTime Windows Seven 15.6 ms
========================= ================ ===============
For CLOCK_REALTIME, the accuracy of this table is the result of clock_getres().
It looks like Linux does not implement clock_getres() and always return 1
nanosecond.
.. note::
Linux provides also CLOCK_REALTIME_COARSE since Linux 2.6.32 which has less
accurate than CLOCK_REALTIME but is faster.
Windows: GetSystemTimeAsFileTime
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2012-03-26 19:12:03 -04:00
The system time can be read using GetSystemTimeAsFileTime(), ftime()
and time().
2012-03-26 19:12:03 -04:00
The system time resolution can be read using
GetSystemTimeAdjustment(). The accuracy is usually between 1
2012-03-31 02:53:07 -04:00
millisecond and 15 milliseconds. Resolution:
2012-03-26 19:12:03 -04:00
* GetSystemTimeAsFileTime(): 100 nanoseconds
* ftime(): 1 millisecond
* time(): 1 second
2012-03-26 19:12:03 -04:00
The system time can be set using SetSystemTime().
System time on UNIX
^^^^^^^^^^^^^^^^^^^
gettimeofday(), ftime(), time() and clock_gettime(CLOCK_REALTIME)
return the system clock.
2012-03-26 19:12:03 -04:00
Resolution:
* clock_gettime(): clock_getres(CLOCK_REALTIME)
* gettimeofday(): 1 microsecond
* ftime(): 1 millisecond
* time(): 1 second
2012-03-26 19:12:03 -04:00
The system time can be set using settimeofday() or
clock_settime(CLOCK_REALTIME).
2012-03-26 19:12:03 -04:00
Process time
------------
The process time cannot be set. It is not monotonic: the clocks stop while the
process is idle.
========================= ===============
Name Resolution
========================= ===============
GetProcessTimes() 100 ns
CLOCK_PROCESS_CPUTIME_ID 1 ns
clock() \-
========================= ===============
Examples of clock accuracy on x86_64:
========================= ================ ===============
Name Operating system Accuracy
========================= ================ ===============
CLOCK_PROCESS_CPUTIME_ID Linux 3.2 1 ns
clock() Linux 3.2 1 µs
clock() SunOS 5.11 1 µs
clock() FreeBSD 8.2 7.8 ms
clock() OpenBSD 5.0 10 ms
GetProcessTimes() Windows Seven 15.6 ms
========================= ================ ===============
2012-03-26 19:12:03 -04:00
The accuracy of clock() in this table is the result of 1 / CLOCKS_PER_SEC.
For CLOCK_PROCESS_CPUTIME_ID, the accuracy of this table is the result of
clock_getres(). It looks like Linux does not implement clock_getres() and
always return 1 nanosecond. For GetProcessTimes(), the accuracy is read using
GetSystemTimeAdjustment().
2012-03-26 19:12:03 -04:00
Functions
^^^^^^^^^
2012-03-26 19:12:03 -04:00
* Windows: GetProcessTimes()
* clock_gettime(CLOCK_PROCESS_CPUTIME_ID): High-resolution per-process
timer from the CPU.
* clock():
2012-03-26 19:12:03 -04:00
* Windows: The elapsed wall-clock time since the start of the
2012-03-31 02:53:07 -04:00
process (elapsed time in seconds times CLOCKS_PER_SEC). It can
fail.
* UNIX: returns an approximation of processor time used by the
program.
2012-03-26 19:12:03 -04:00
* times()
* getrusage(): ru_utime and ru_stime fields
2012-03-26 19:12:03 -04:00
Resolution:
* clock() rate is CLOCKS_PER_SEC. It was called CLK_TCK in Microsoft
C before 6.0.
* The clock resolution can be read using clock_getres().
2012-03-31 02:53:07 -04:00
* GetProcessTimes(): call GetSystemTimeAdjustment().
2012-03-26 19:12:03 -04:00
Thread time
-----------
The thread time cannot be set. It is not monotonic: the clocks stop while the
thread is idle.
========================= ===============
Name Resolution
========================= ===============
GetThreadTimes() 100 ns
CLOCK_THREAD_CPUTIME_ID 1 ns
========================= ===============
Examples of clock accuracy on x86_64:
========================= ================ ===============
Name Operating system Accuracy
========================= ================ ===============
CLOCK_THREAD_CPUTIME_ID Linux 3.2 1 ns
CLOCK_THREAD_CPUTIME_ID FreeBSD 8.2 1 µs
GetThreadTimes() Windows Seven 15.6 ms
========================= ================ ===============
For CLOCK_THREAD_CPUTIME_ID, the accuracy of this table is the result of
clock_getres(). It looks like Linux does not implement clock_getres() and
always return 1 nanosecond. For GetThreadTimes(), the accuracy is read using
GetSystemTimeAdjustment().
Functions
^^^^^^^^^
2012-03-26 19:12:03 -04:00
* Windows: GetThreadTimes()
* clock_gettime(CLOCK_THREAD_CPUTIME_ID): Thread-specific CPU-time
clock.
2012-03-26 19:12:03 -04:00
Resolution:
* CLOCK_THREAD_CPUTIME_ID: call clock_getres().
* GetThreadTimes(): call GetSystemTimeAdjustment()
2012-03-26 19:12:03 -04:00
See also pthread_getcpuclockid().
Windows: QueryUnbiasedInterruptTime
-----------------------------------
2012-03-26 19:12:03 -04:00
Gets the current unbiased interrupt time from the biased interrupt
time and the current sleep bias amount. This time is not affected by
power management sleep transitions.
2012-03-26 19:12:03 -04:00
The elapsed time retrieved by the QueryUnbiasedInterruptTime function
includes only time that the system spends in the working state.
QueryUnbiasedInterruptTime() is not monotonic.
2012-03-26 19:12:03 -04:00
QueryUnbiasedInterruptTime() was introduced in Windows 7.
2012-03-31 02:53:07 -04:00
Linux timers
------------
There were 4 implementations of the time in the Linux kernel: UTIME
2012-03-31 02:53:07 -04:00
(1996), timer wheel (1997), HRT (2001) and hrtimers (2007). The
latter is the result of the "high-res-timers" project started by
George Anzinger in 2001, with contributions by Thomas Gleixner and
Douglas Niehaus. hrtimers implementation was merged into Linux
2.6.21, released in 2007.
hrtimers supports various clock sources. It sets a priority to each
source to decide which one will be used.
* TSC (Time Stamp Counter): Internal processor clock incremented at
each processor cycle. Its frequency is the processor frequency and
so usually higher than 1 GHz. Its priority is 300 by default, but
falls to 0 if the processor frequency changes and the counter
becomes unstable.
* HPET: An HPET chip consists of a 64-bit up-counter (main counter)
counting at least at 10 MHz and a set of up to 256 comparators (at
least 3). Each HPET can have up to 32 timers.
* PIT (programmable interrupt timer): Intel 8253/8254 chipsets with a
configurable frequency in range 18.2 Hz - 1.2 MHz. Linux uses the
frequency 1,193,181.8 Hz. It is a 16-bit counter.
* PMTMR (power management timer): ACPI 24-bit timer with a frequency
of 3.5 MHz (3,579,545 Hz). Its priority is 200 by default, but
changes to 110 if the chipset is broken and need a software
workaround. HPET can cause around 3 seconds of drift per day.
* Cyclone: The Cyclone timer uses a 32-bit counter on IBM Extended
X-Architecture (EXA) chipsets which include computers that use the
IBM "Summit" series chipsets (ex: x440). This is available in IA32
and IA64 architectures.
High-resolution timers are not supported on all hardware
architectures. They are at least provided on x86/x86_64, ARM and
PowerPC.
The list of available clock sources can be read in
/sys/devices/system/clocksource/clocksource0/available_clocksource.
It is possible to force a clocksource at runtime by writing its name
into /sys/devices/system/clocksource/clocksource0/current_clocksource.
/proc/timer_list contains the list of all hardware timers.
Read also the `time(7) manual page
<http://www.kernel.org/doc/man-pages/online/pages/man7/time.7.html>`_:
"overview of time and timers".
FreeBSD timers
--------------
The sysctl program can be used to change the timecounter. For example::
# sysctl kern.timecounter.hardware="ACPI-fast"
kern.timecounter.hardware: HPET -> ACPI-fast
Sleep, suspend and monotonic time
=================================
Linux
-----
2012-04-10 18:42:54 -04:00
sleep() is not affected by system clock update.
On Linux, CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW includes time the system
spends in sleep; but it does not include time spent in hibernation (ACPI S3
mode). If the system clock jumps backward, CLOCK_MONOTONIC and
CLOCK_MONOTONIC_RAW are not affected.
Linux 2.6.39 and glibc 2.14 introduces a new clock: CLOCK_BOOTTIME.
CLOCK_BOOTTIME is idential to CLOCK_MONOTONIC, except it also includes any time
spent in suspend. Read also `Waking systems from suspend
<http://lwn.net/Articles/429925/>`_ (March, 2011).
2012-04-10 18:42:54 -04:00
Other operating systems
-----------------------
On Windows, GetTickCount() and GetTickCount64() include time the system
spends in sleep; sleep() is not affected by system clock update.
On FreeBSD 8, CLOCK_MONOTONIC include time the system spends in sleep; sleep()
is not affected by system clock update.
On OpenIndiana, CLOCK_MONOTONIC include time the system spends in sleep;
sleep() is not affected by system clock update.
On Mac OS X, mach_absolute_time() include time the system spends in sleep;
sleep() is not affected by system clock update. Sleep is interrupted during
suspend.
2012-03-26 19:12:03 -04:00
Sleeping
========
Sleep can be interrupted by a signal: the function fails with EINTR.
======================== ==========
Name Resolution
======================== ==========
nanosleep() 1 ns
clock_nanosleep() 1 ns
usleep() 1 µs
delay() 1 µs
sleep() 1 sec
======================== ==========
Other functions:
======================== ==========
Name Resolution
======================== ==========
sigtimedwait() 1 ns
pthread_cond_timedwait() 1 ns
sem_timedwait() 1 ns
select() 1 µs
epoll() 1 ms
poll() 1 ms
WaitForSingleObject() 1 ms
======================== ==========
Classic functions
-----------------
* sleep(seconds)
* usleep(microseconds)
* nanosleep(nanoseconds, remaining)
`Linux manpage
<http://www.kernel.org/doc/man-pages/online/pages/man2/nanosleep.2.html>`_
* delay(milliseconds)
clock_nanosleep
---------------
clock_nanosleep(clock_id, flags, nanoseconds, remaining):
`Linux manpage
<http://www.kernel.org/doc/man-pages/online/pages/man2/clock_nanosleep.2.html>`_.
If flags is TIMER_ABSTIME, then request is interpreted as an absolute
time as measured by the clock, clock_id. If request is less than or
equal to the current value of the clock, then clock_nanosleep() returns
immediately without suspending the calling thread.
POSIX.1 specifies that changing the value of the CLOCK_REALTIME clock via
clock_settime(2) shall have no effect on a thread that is blocked on a relative
clock_nanosleep().
select()
--------
select(nfds, readfds, writefds, exceptfs, timeout).
Since Linux 2.6.28, select() uses high-resolution timers to handle the timeout.
A process has a "slack" attribute to configure the accuracy of the timeout, the
default slack is 50 microseconds. Before Linux 2.6.28, timeouts for select()
were handled by the main timing subsystem at a jiffy-level resolution. Read
also `High- (but not too high-) resolution timeouts
<http://lwn.net/Articles/296578/>`_ and `Timer slack
<http://lwn.net/Articles/369549/>`_.
Other functions
---------------
* poll(), epoll()
* sigtimedwait(). POSIX: "If the Monotonic Clock option is supported, the
CLOCK_MONOTONIC clock shall be used to measure the time interval specified
by the timeout argument."
* pthread_cond_timedwait(), pthread_condattr_setclock(). "The default value of
the clock attribute shall refer to the system clock."
* sem_timedwait(): "If the Timers option is supported, the timeout shall be
based on the CLOCK_REALTIME clock. If the Timers option is not supported,
the timeout shall be based on the system clock as returned by the time()
function. The resolution of the timeout shall be the resolution of the clock
on which it is based."
* WaitForSingleObject(): use the same timer than GetTickCount() with the same
resolution.
Alternatives: API design
========================
2012-03-26 19:12:03 -04:00
Other names for time.monotonic()
--------------------------------
* time.counter()
* time.seconds()
* time.steady()
* time.timeout_clock()
* time.wallclock(): it is not the system time aka the "wall clock", but
a monotonic clock with an unspecified starting point
The name "time.try_monotonic()" was also proposed when time.monotonic() was
falling back to the system clock when no monotonic clock was available.
2012-04-03 19:00:46 -04:00
Only expose operating system clocks
-----------------------------------
To not have to define high-level clocks, which is a difficult task, a simpler
approach is to only expose operating system clocks. time.clock_gettime() and
related clock identifiers were already added to Python 3.3 for example.
Fallback to system clock
------------------------
If no monotonic clock is available, time.monotonic() falls back to the system
clock.
2012-04-03 19:00:46 -04:00
Issues:
2012-04-03 19:00:46 -04:00
* It is hard to define correctly such function in the documentation: is it
monotonic? is it steady? is it adjusted?
* Some user want to decide what to do when no monotonic clock is available:
use another clock, display an error, or do something else
2012-04-03 19:00:46 -04:00
One function choosing the clock from a list of constrains
---------------------------------------------------------
2012-04-03 19:49:55 -04:00
``time.get_clock(*flags)`` with the following flags:
2012-04-03 19:00:46 -04:00
* time.MONOTONIC: clock cannot go backard
* time.STEADY: clock rate is steady and the clock is not adjusted
* time.HIGHRES: clock with the highest resolutions
time.get_clock() returns None if the clock is found and so calls can be chained
using the or operator. Example::
get_time = time.get_clock(time.MONOTONIC) or time.get_clock(time.STEADY) or time.time()
t = get_time()
2012-04-03 19:00:46 -04:00
Example of flags of system clocks:
* QueryPerformanceCounter: MONOTONIC | HIGHRES
* GetTickCount: MONOTONIC | STEADY
* CLOCK_MONOTONIC: MONOTONIC | STEADY (or only MONOTONIC on Linux)
* CLOCK_MONOTONIC_RAW: MONOTONIC | STEADY
* gettimeofday(): (no flag)
2012-04-03 19:00:46 -04:00
One function with a flag: time.monotonic(fallback=True)
-------------------------------------------------------
* time.monotonic(fallback=True) falls back to the system clock if no monotonic
clock is available or if the monotonic clock failed.
* time.monotonic(fallback=False) raises OSError if monotonic clock fails and
NotImplementedError if the system does not provide a monotonic clock
"A keyword argument that gets passed as a constant in the caller is usually
poor API."
Raising NotImplementedError for a function is something uncommon in Python and
should be avoided.
2012-03-26 19:12:03 -04:00
One function, no flag
---------------------
time.monotonic() returns (time: float, is_monotonic: bool).
2012-03-26 19:12:03 -04:00
An alternative is to use a function attribute:
time.monotonic.is_monotonic. The attribute value would be None before
the first call to time.monotonic().
2012-03-26 19:12:03 -04:00
Working around operating system bugs?
=====================================
2012-03-26 19:12:03 -04:00
Should Python ensure manually that a monotonic clock is truly
monotonic by computing the maximum with the clock value and the
previous value?
2012-03-26 19:12:03 -04:00
Since it's relatively straightforward to cache the last value returned
using a static variable, it might be interesting to use this to make
sure that the values returned are indeed monotonic.
* Virtual machines provide less reliable clocks.
* QueryPerformanceCounter() has known bugs (only one is not fixed yet)
2012-03-31 02:53:07 -04:00
Python may only work around a specific known operating system bug:
`KB274323`_ contains a code example to workaround the bug (use
GetTickCount() to detect QueryPerformanceCounter() leap).
2012-03-26 19:12:03 -04:00
Issues of a hacked monotonic function:
* if the clock is accidentally set forward by an hour and then back
again, you wouldn't have a useful clock for an hour
* the cache is not shared between processes so different processes wouldn't
see the same clock value
2012-03-26 19:12:03 -04:00
Deferred API: time.perf_counter()
=================================
Performance counter used for benchmarking and profiling. The reference point of
the returned value is undefined so only the difference of consecutive calls is
valid and is number of seconds.
Pseudo-code::
def perf_counter():
if perf_counter.use_performance_counter:
if perf_counter.cpu_frequency is None:
try:
perf_counter.cpu_frequency = float(_time.QueryPerformanceFrequency())
except OSError:
# QueryPerformanceFrequency() fails if the installed
# hardware does not support a high-resolution performance
# counter
perf_counter.use_performance_counter = False
else:
return _time.QueryPerformanceCounter() / perf_counter.cpu_frequency
else:
return _time.QueryPerformanceCounter() / perf_counter.cpu_frequency
if perf_counter.use_monotonic:
# Monotonic clock is preferred over system clock
try:
return time.monotonic()
except OSError:
perf_counter.use_monotonic = False
return time.time()
perf_counter.use_performance_counter = (os.name == 'nt')
if perf_counter.use_performance_counter:
perf_counter.cpu_frequency = None
perf_counter.use_monotonic = hasattr(time, 'monotonic')
Other names proposed for time.perf_counter():
* time.hires()
* time.highres()
* time.timer()
Python source code includes a portable library to get the process time (CPU
time): `Tools/pybench/systimes.py
<http://hg.python.org/cpython/file/tip/Tools/pybench/systimes.py>`_.
Footnotes
=========
.. [#pseudo] "_time" is an hypothetical module only used for the example.
The time module is implemented in C and so there is no need for
such module.
2012-03-26 19:12:03 -04:00
Links
=====
Related Python issues:
* `Issue #12822: NewGIL should use CLOCK_MONOTONIC if possible.
<http://bugs.python.org/issue12822>`_
* `Issue #14222: Use time.steady() to implement timeout
<http://bugs.python.org/issue14222>`_
* `Issue #14397: Use GetTickCount/GetTickCount64 instead of
QueryPerformanceCounter for monotonic clock
<http://bugs.python.org/issue14397>`_
* `Issue #14428: Implementation of the PEP 418
<http://bugs.python.org/issue14428>`_
Libraries exposing monotonic clocks:
* `Java: System.nanoTime
<http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#nanoTime()>`_
* `Qt library: QElapsedTimer
<http://qt-project.org/doc/qt-4.8/qelapsedtimer.html>`_
* `glib library: g_get_monotonic_time ()
<http://developer.gnome.org/glib/2.30/glib-Date-and-Time-Functions.html#g-get-monotonic-time>`_
uses GetTickCount64()/GetTickCount() on Windows,
clock_gettime(CLOCK_MONOTONIC) on UNIX or falls back to the system
clock
* `python-monotonic-time
<http://code.google.com/p/python-monotonic-time/>`_ (`github
<https://github.com/gavinbeatty/python-monotonic-time>`_)
* `Monoclock.nano_count()
<https://github.com/ludios/Monoclock>`_ uses clock_gettime(CLOCK_MONOTONIC)
and returns a number of nanoseconds
* `monotonic_clock <https://github.com/ThomasHabets/monotonic_clock>`_
* `Perl: Time::HiRes <http://perldoc.perl.org/Time/HiRes.html>`_
exposes clock_gettime(CLOCK_MONOTONIC)
* `Ruby: AbsoluteTime.now
<https://github.com/bwbuchanan/absolute_time/>`_: use
clock_gettime(CLOCK_MONOTONIC), mach_absolute_time() or
gettimeofday(). "AbsoluteTime.monotonic?" method indicates if
AbsoluteTime.now is monotonic or not.
* `libpthread
<http://code.google.com/p/libpthread/>`_: POSIX thread library for Windows
(`clock.c <http://code.google.com/p/libpthread/source/browse/src/clock.c>`_)
* `Boost.Chrono
<http://www.boost.org/doc/libs/1_49_0/doc/html/chrono.html>`_ uses:
* system_clock:
* mac = gettimeofday()
* posix = clock_gettime(CLOCK_REALTIME)
* win = GetSystemTimeAsFileTime()
* steady_clock:
* mac = mach_absolute_time()
* posix = clock_gettime(CLOCK_MONOTONIC)
* win = QueryPerformanceCounter()
* high_resolution_clock:
* steady_clock, if available system_clock, otherwise
Time:
* `hrtimers - subsystem for high-resolution kernel timers
<http://www.kernel.org/doc/Documentation/timers/hrtimers.txt>`_
* `C++ Timeout Specification
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3128.html>`_
* `Windows: Game Timing and Multicore Processors
<http://msdn.microsoft.com/en-us/library/ee417693.aspx>`_
* `Implement a Continuously Updating, High-Resolution Time Provider
for Windows
<http://msdn.microsoft.com/en-us/magazine/cc163996.aspx>`_
* `clockspeed <http://cr.yp.to/clockspeed.html>`_ uses a hardware tick
counter to compensate for a persistently fast or slow system clock
* `Retrieving system time
<http://en.wikipedia.org/wiki/System_time#Retrieving_system_time>`_
lists hardware clocks and time functions with their resolution and
epoch or range
* On Windows, the JavaScript runtime of Firefox interpolates
GetSystemTimeAsFileTime() with QueryPerformanceCounter() to get an
higher resolution. See the `Bug 363258 - bad millisecond resolution
for (new Date).getTime() / Date.now() on Windows
<https://bugzilla.mozilla.org/show_bug.cgi?id=363258>`_.
* `When microseconds matter
<http://www.ibm.com/developerworks/library/i-seconds/>`_: How the
IBM High Resolution Time Stamp Facility accurately measures itty
bits of time
* `Win32 Performance Measurement Options
<http://drdobbs.com/windows/184416651>`_ by Matthew Wilson, May 01, 2003
Copyright
=========
This document has been placed in the public domain.
2012-03-26 19:12:03 -04:00
..
Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
coding: utf-8
End: