diff --git a/pep-0418.txt b/pep-0418.txt index f7ff26f41..79ad7271e 100644 --- a/pep-0418.txt +++ b/pep-0418.txt @@ -13,8 +13,7 @@ Python-Version: 3.3 Abstract ======== -Add time.monotonic(), time.hires() and time.try_monotonic() functions to Python -3.3. +Add time.monotonic() and time.hires() functions to Python 3.3. Rationale @@ -24,33 +23,9 @@ Use cases: * Display the current time to a human (e.g. display a calendar or draw a wall clock): use system clock. time.time() or datetime.datetime.now() - * Implement a timeout: use monotonic clock, or fallback to the clock with - the highest resolution. time.try_monotonic() - * Benchmark and profiling: time.hires(), with a manual fallback to time.time() + * Benchmark, profiling, timeout: time.hires() * Event scheduler: time.monotonic() -time.try_monotonic() tries to use a monotonic clock, but it falls back to a -non-monotonic clock if no monotonic clock is available or if reading a -monotonic clock failed. - -The pybench benchmark tool supports the following clocks: time.clock(), -time.time() and systimes.processtime(). By default, it uses time.clock() on -Windows, and time.time() otherwise. It is possible to choose the clock using -the --timer command line option. - -Which clock? - - * System time: pthread_mutex_timedlock(), pthread_cond_wait() (CLOCK_REALTIME) - * Monotonic: clock_nanosleep() (CLOCK_MONOTONIC) - -Timeouts: - - * threading.Lock.wait() - * select.select() - * time.sleep() - * subprocess.Popen.communicate() - * etc. - Functions ========= @@ -60,7 +35,7 @@ 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 backward and -forward, and is not monotonic. +forward. It is not monotonic. It is available on all platforms and cannot fail. @@ -96,12 +71,12 @@ Pseudo-code [#pseudo]_: :: time.monotonic() ---------------- -Monotonic clock advancing at a monotonic rate relative to real time. It -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. +Clock advancing at a monotonic rate relative to real time. It 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. + +It is not available on all platforms and may raise an OSError. -It is not avaialble on all platforms and raise an OSError on error. The monotonic clock may stop while the system is suspended. Pseudo-code [#pseudo]_: :: @@ -157,53 +132,21 @@ Pseudo-code [#pseudo]_: :: time.hires() ------------ -High-resolution clock. It has an unspecified starting point and may be -adjusted. The clock starting point changes when the system is resumed after -being suspended. +High-resolution clock: use a monotonic clock if available, or fallback to the +system time. + +It is available on all platforms and cannot fail. Pseudo-code [#pseudo]_: :: - if os.name == 'nt': - def hires(): - return _time.QueryPerformanceCounter() - elif hasattr(time, "monotonic"): - hires = time.monotonic - elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_REALTIME"): - def hires(): - return time.clock_gettime(time.CLOCK_REALTIME) - -It is not available on all platforms and may raise an OSError. - - -time.try_monotonic() --------------------- - -This clock advances at a steady rate relative to real time. It may be adjusted. -The reference point of the returned value is undefined so only the difference -of consecutive calls is valid. - -Pseudo-code:: - - def try_monotonic(): - if try_monotonic.use_monotonic: + def hires(): + if hires.use_monotonic: try: return time.monotonic() - except (AttributeError, OSError): - try_monotonic.use_monotonic = False - if try_monotonic.use_hires: - try: - return time.hires() - except (AttributeError, OSError): - try_monotonic.use_hires = False + except OSError: + hires.use_monotonic = False return time.time() - try_monotonic.use_monotonic = True - try_monotonic.use_hires = True - - -If available, a monotonic clock is used. The function falls back to another -clock if the monotonic clock failed or is not available. - -This function cannot fail. + hires.use_monotonic = hasattr(time, 'monotonic') Clocks @@ -212,54 +155,75 @@ Clocks Monotonic --------- - * mach_absolute_time(): Mac OS X provides a monotonic clock: - mach_absolute_time(). mach_timebase_info() provides a fraction to convert it - to a number of nanoseconds. According to the documentation, - mach_timebase_info() is always equals to one and does never fail, even if - the function may fail according to its prototype. - * clock_gettime(CLOCK_MONOTONIC): Clock that cannot be set and represents - monotonic time since some unspecified starting point. - * clock_gettime(CLOCK_MONOTONIC_RAW), since Linux 2.6.28; Linux-specific: - Similar to CLOCK_MONOTONIC, but provides access to a raw hardware-based time - that is not subject to NTP adjustments. - * Windows: GetTickCount(), GetTickCount64(). +mach_absolute_time +^^^^^^^^^^^^^^^^^^ -CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW clocks cannot be set. +Mac OS X provides a monotonic clock: mach_absolute_time(). mach_timebase_info() +provides a fraction to convert the clock value to a number of nanoseconds. + +According to the documentation, mach_timebase_info() is always equals to one +and does never fail, even if the function may fail according to its prototype. + +mach_absolute_time() has a resolution of 1 nanosecond. + +CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW represents monotonic time since some +unspecified starting point. They cannot be set. + +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. On Linux, NTP may adjust CLOCK_MONOTONIC rate, but not jump backward. If available, CLOCK_MONOTONIC_RAW should be used instead of CLOCK_MONOTONIC to -avoid the NTP adjustement. CLOCK_MONOTONIC stops while the machine is -suspended. +avoid the NTP adjustement. -Resolution: +CLOCK_MONOTONIC stops while the machine is suspended. - * mach_absolute_time(): 1 nanosecond - * CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW: be read using clock_getres(). - 1 nanosecond on Linux for example. - * GetTickCount(), GetTickCount64(): 1 millisecond +clock_gettime() fails if the system does not support the specified clock, +whereas the standard C library supports it. For example, CLOCK_MONOTONIC_RAW +requires a kernel version 2.6.28 or later. -May fail? - - * mach_absolute_time() cannot fail. According to the documentation, - mach_timebase_info() does never fail, even if the function has a return - value. - * clock_gettime() can fail if the system does not support the specified clock, - whereas the standard C library supports it. For example, CLOCK_MONOTONIC_RAW - requires a kernel version 2.6.28 or later. - * GetTickCount() and GetTickCount64() cannot fail +clock_getres() gives the clock resolution. It is 1 nanosecond on Linux. .. note:: clock_gettime() requires to link the program with the realtime ("rt") library. -.. note:: - GetTickCount64() was added to Windows Vista and Windows Server 2008. +QueryPerformanceCounter +^^^^^^^^^^^^^^^^^^^^^^^ + +High-resolution performance counter. It is monotonic. +QueryPerformanceFrequency() gives its frequency. + + +On Windows XP, QueryPerformanceFrequency() is the processor frequency and +QueryPerformanceCounter() is the TSC of the current processor. Windows XP +had a bug (see `KB896256 `_): on a +multiprocessor computer, QueryPerformanceCounter() returned a different value +for each processor. + +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. + + +GetTickCount(), GetTickCount64() +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +GetTickCount() and GetTickCount64() are monotonic and cannot fail. + +GetTickCount64() was added to Windows Vista and Windows Server 2008. + +The clock resolution is 1 millisecond. System time ----------- -System time on Windows -^^^^^^^^^^^^^^^^^^^^^^ +Windows: GetSystemTimeAsFileTime +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The system time can be read using GetSystemTimeAsFileTime(), ftime() and time(). @@ -276,12 +240,12 @@ The system time can be set using SetSystemTime(). System time on UNIX ^^^^^^^^^^^^^^^^^^^ -gettimeofday(), ftime(), time() and clock_settime(CLOCK_REALTIME) return the +gettimeofday(), ftime(), time() and clock_gettime(CLOCK_REALTIME) return the system clock. Resolution: - * clock_settime(): clock_getres(CLOCK_REALTIME), 1 nanosecond on Linux + * clock_gettime(): clock_getres(CLOCK_REALTIME), 1 nanosecond on Linux * gettimeofday(): 1 microsecond * ftime(): 1 millisecond * time(): 1 second @@ -299,7 +263,8 @@ Process ^^^^^^^ * Windows: GetProcessTimes() - * clock_gettime(CLOCK_PROCESS_CPUTIME_ID): High-resolution per-process timer from the CPU. + * clock_gettime(CLOCK_PROCESS_CPUTIME_ID): High-resolution per-process timer + from the CPU. * clock(): * Windows: The elapsed wall-clock time since the start of the process @@ -331,28 +296,6 @@ Resolution: See also pthread_getcpuclockid(). -QueryPerformanceCounter ------------------------ - -Windows provides a high-resolution performance counter: -QueryPerformanceCounter(). Its frequency can be retrieved using -QueryPerformanceFrequency(). - -On Windows XP, QueryPerformanceFrequency() is the processor frequency and -QueryPerformanceCounter() is the TSC of the current processor. Windows XP -had a bug (see `KB896256 `_): on a -multiprocessor computer, QueryPerformanceCounter() returned a different value -for each processor. - -QueryPerformanceCounter() is monotonic. - -QueryPerformanceFrequency() fails if the installed hardware does not support a -high-resolution performance counter. - -QueryPerformanceFrequency() should only be called once: the frequency will not -change while the system is running. - - QueryUnbiasedInterruptTime -------------------------- @@ -369,12 +312,12 @@ QueryUnbiasedInterruptTime() was introduced in Windows 7. Alternatives: API design ======================== -One function with a flag: time.try_monotonic(strict=False) +One function with a flag: time.monotonic(strict=False) ---------------------------------------------------------- - * time.try_monotonic(strict=False) falls back to another clock if no monotonic clock + * time.monotonic(strict=False) falls back to another clock if no monotonic clock is not available or does not work, but it does never fail. - * time.try_monotonic(strict=True) raises OSError if monotonic clock fails or + * time.monotonic(strict=True) raises OSError if monotonic clock fails or NotImplementedError if the system does not provide a monotonic clock "A keyword argument that gets passed as a constant in the caller is usually @@ -387,10 +330,10 @@ should be avoided. One function, no flag --------------------- -time.try_monotonic() returns (time: float, is_monotonic: bool). +time.monotonic() returns (time: float, is_monotonic: bool). -An alternative is to use a function attribute: time.try_monotonic.monotonic. The -attribute value would be None before the first call to time.try_monotonic(). +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(). Working around operating system bugs?