[Python-checkins] peps: PEP 418

victor.stinner python-checkins at python.org
Sun Apr 15 17:06:45 CEST 2012


http://hg.python.org/peps/rev/f2bb3f74298a
changeset:   4252:f2bb3f74298a
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Sun Apr 15 17:06:07 2012 +0200
summary:
  PEP 418

 * time.perf_counter() is not necessary monotonic; format code
 * Replace system clock by system time to reuse the expression of the glossary
 * If CLOCK_HIGHRES is available, time.monotonic() only uses it and does not
   fallback to CLOCK_MONOTONIC because CLOCK_MONOTONIC may not be available
   at the same time
 * Rewrite time.perf_counter(), time.process_time() and time.time() doc
 * Reorder "fallback to system time" alternatives

files:
  pep-0418.txt |  307 ++++++++++++++++++++------------------
  1 files changed, 160 insertions(+), 147 deletions(-)


diff --git a/pep-0418.txt b/pep-0418.txt
--- a/pep-0418.txt
+++ b/pep-0418.txt
@@ -21,19 +21,20 @@
 Rationale
 =========
 
-If a program uses the system clock to schedule events or to implement
+If a program uses the system time to schedule events or to implement
 a timeout, it will not run events at the right moment or stop the
-timeout too early or too late when the system clock is set manually or
+timeout too early or too late when the system time is set manually or
 adjusted automatically by NTP.  A monotonic clock should be used
-instead to not be affected by system clock updates.
+instead to not be affected by system time updates:
+``time.monotonic()``.
 
 To measure the performance of a function, ``time.clock()`` can be used
 but it is very different on Windows and on Unix.  On Windows,
 ``time.clock()`` includes time elapsed during sleep, whereas it does
 not on Unix.  ``time.clock()`` precision is very good on Windows, but
-very bad on Unix.  The new ``time.perf_counter()`` function can be
+very bad on Unix.  The new ``time.perf_counter()`` function should be
 used instead to always get the most precise performance counter with a
-portable behaviour.
+portable behaviour (ex: include time spend during sleep).
 
 To measure CPU time, Python does not provide directly a portable
 function.  ``time.clock()`` can be used on Unix, but it has a bad
@@ -60,18 +61,18 @@
 
 Users of new functions:
 
- * time.monotonic(): concurrent.futures, multiprocessing, queue, subprocess,
-   telnet and threading modules to implement timeout
- * time.perf_counter(): trace and timeit modules, pybench program
- * time.process_time(): profile module
- * time.get_clock_info(): pybench program to display information about the
-   timer like the precision or the resolution
+* time.monotonic(): concurrent.futures, multiprocessing, queue, subprocess,
+  telnet and threading modules to implement timeout
+* time.perf_counter(): trace and timeit modules, pybench program
+* time.process_time(): profile module
+* time.get_clock_info(): pybench program to display information about the
+  timer like the precision or the resolution
 
-The ``time.clock()`` function is deprecated by this PEP because it is not
+The ``time.clock()`` function is deprecated because it is not
 portable: it behaves differently depending on the operating system.
-``time.perf_counter()`` or ``time.process_time()`` should be used instead,
-depending on your requirements. ``time.clock()`` is marked as deprecated but
-is not planned for removal.
+``time.perf_counter()`` or ``time.process_time()`` should be used
+instead, depending on your requirements. ``time.clock()`` is marked as
+deprecated but is not planned for removal.
 
 
 Python functions
@@ -83,47 +84,51 @@
 time.get_clock_info(name)
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Get information on the specified clock.  Supported clocks:
+Get information on the specified clock.  Supported clock names:
 
-* "clock": time.clock()
-* "monotonic": time.monotonic()
-* "perf_counter": time.perf_counter()
-* "process_time": time.process_time()
-* "time": time.time()
+* ``"clock"``: ``time.clock()``
+* ``"monotonic"``: ``time.monotonic()``
+* ``"perf_counter"``: ``time.perf_counter()``
+* ``"process_time"``: ``time.process_time()``
+* ``"time"``: ``time.time()``
 
 Return a dictionary with the following keys:
 
 * Mandatory keys:
 
-  * "implementation" (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
+  * ``"implementation"`` (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:
 
-  * "precision" (float): precision in seconds of the clock
-  * "is_adjusted" (bool): True if the clock can be adjusted (e.g. by a
-    NTP daemon)
+  * ``"precision"`` (float): precision in seconds of the clock
+    reported by the operating system.
+  * ``"is_adjusted"`` (bool): True if the clock is adjusted (e.g. by a
+    NTP daemon).
 
 
 time.monotonic()
 ^^^^^^^^^^^^^^^^
 
-Monotonic clock, cannot go backward.  It is not affected by system clock
-updates.  The reference point of the returned value is undefined, so that only
-the difference between the results of consecutive calls is valid.
+Monotonic clock, i.e. cannot go backward.  It is not affected by system
+clock updates.  The reference point of the returned value is
+undefined, so that only the difference between the results of
+consecutive calls is valid and is a number of seconds.
 
-On Windows older than Vista, ``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. On more recent
-versions of Windows and on other operating systems, ``time.monotonic()`` is
+On Windows versions older than Vista, ``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. On more recent versions of
+Windows and on other operating systems, ``time.monotonic()`` is
 system-wide.
 
-Availability: Windows, Mac OS X, Unix, Solaris. Not available on GNU/Hurd.
+Availability: Windows, Mac OS X, Unix, Solaris. Not available on
+GNU/Hurd.
 
 Pseudo-code [#pseudo]_::
 
@@ -151,16 +156,13 @@
             return _time.mach_absolute_time() * monotonic.factor
         monotonic.factor = None
 
-    elif hasattr(time, "clock_gettime"):
+    elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_HIGHRES"):
         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_HIGHRES)
+
+    elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_MONOTONIC"):
+        def monotonic():
             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
@@ -171,29 +173,30 @@
 time.perf_counter()
 ^^^^^^^^^^^^^^^^^^^
 
-Performance counter used for benchmarking.  It is monotonic, i.e. cannot go
-backward.  It does include time elapsed during sleep and is system-wide.  The
-reference point of the returned value is undefined, so that only the difference
-between the results of consecutive calls is valid and is number of seconds.
+Performance counter with the highest available precision to measure a
+duration.  It does include time elapsed during sleep and is
+system-wide.  The reference point of the returned value is undefined,
+so that only the difference between the results of consecutive calls
+is valid and is a number of seconds.
 
 Pseudo-code::
 
     def perf_counter():
         if perf_counter.use_performance_counter:
-            if perf_counter.perf_frequency is None:
+            if perf_counter.performance_frequency is None:
                 try:
-                    perf_counter.perf_frequency = float(_time.QueryPerformanceFrequency())
+                    perf_counter.performance_frequency = _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.perf_frequency
+                    return _time.QueryPerformanceCounter() / perf_counter.performance_frequency
             else:
-                return _time.QueryPerformanceCounter() / perf_counter.perf_frequency
+                return _time.QueryPerformanceCounter() / perf_counter.performance_frequency
         if perf_counter.use_monotonic:
-            # Monotonic clock is preferred over system clock
+            # The monotonic clock is preferred over the system time
             try:
                 return time.monotonic()
             except OSError:
@@ -201,17 +204,20 @@
         return time.time()
     perf_counter.use_performance_counter = (os.name == 'nt')
     if perf_counter.use_performance_counter:
-        perf_counter.perf_frequency = None
+        perf_counter.performance_frequency = None
     perf_counter.use_monotonic = hasattr(time, 'monotonic')
 
 
 time.process_time()
 ^^^^^^^^^^^^^^^^^^^
 
-Process time used for profiling: sum of the kernel and user-space CPU time.  It
-does not include time elapsed during sleep. It is process-wide by definition.
-The reference point of the returned value is undefined, so that only the
-difference between the results of consecutive calls is valid.
+Sum of the system and user CPU time of the current process. It does
+not include time elapsed during sleep. It is process-wide by
+definition.  The reference point of the returned value is undefined,
+so that only the difference between the results of consecutive calls
+is valid.
+
+It is available on all platforms.
 
 Pseudo-code [#pseudo]_::
 
@@ -262,9 +268,9 @@
 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.  It is system-wide but not monotonic.
+The system time which is usually the civil time. It is system-wide by
+definition. It can be set manually by the system administrator or
+automatically by a NTP daemon.
 
 It is available on all platforms and cannot fail.
 
@@ -347,10 +353,11 @@
 ^^^^^^^^^^^^
 
 On Unix, return the current processor time as a floating point number
-expressed in seconds. It is process-wide by definition. The precision, and in
-fact the very definition of the meaning of "processor time", depends on that of
-the C function of the same name, but in any case, this is the function to use
-for benchmarking Python or timing algorithms.
+expressed in seconds. It is process-wide by definition. The precision,
+and in fact the very definition of the meaning of "processor time",
+depends on that of the C function of the same name, but in any case,
+this is the function to use for benchmarking Python or timing
+algorithms.
 
 On Windows, this function returns wall-clock seconds elapsed since the
 first call to this function, as a floating point number, based on the
@@ -385,35 +392,33 @@
 Alternatives: API design
 ========================
 
-Other names for new functions
------------------------------
-
-time.monotonic():
+Other names for time.monotonic()
+--------------------------------
 
 * time.counter()
 * time.metronomic()
 * time.seconds()
-* time.steady()
+* time.steady(): "steady" is ambiguous: it means different things to
+  different people. For example, on Linux, CLOCK_MONOTONIC is
+  adjusted. If we uses the real time as the reference clock, we may
+  say that CLOCK_MONOTONIC is steady.  But CLOCK_MONOTONIC gets
+  suspended on system suspend, whereas real time includes any time
+  spent in suspend.
 * time.timeout_clock()
-* time.wallclock(): it is not the system time aka the "wall clock",
-  but a monotonic clock with an unspecified starting point
+* time.wallclock(): time.monotonic() is not the system time aka the
+  "wall clock", but a monotonic clock with an unspecified starting
+  point.
 
-"steady" is ambiguous: it means different things to different people. For
-example, on Linux, CLOCK_MONOTONIC is adjusted. If we uses the real time as the
-reference clock, we may say that CLOCK_MONOTONIC is steady.  But
-CLOCK_MONOTONIC gets suspended on system suspend, whereas real time includes
-any time spent in suspend.
+The name "time.try_monotonic()" was also proposed for an older
+proposition of time.monotonic() which was falling back to the system
+time when no monotonic clock was available.
 
-The name "time.try_monotonic()" was also proposed when
-time.monotonic() was falling back to the system clock when no
-monotonic clock was available.
+Other names for time.perf_counter()
+-----------------------------------
 
-time.perf_counter():
-
- * time.hires()
- * time.highres()
- * time.timer()
-
+* time.hires()
+* time.highres()
+* time.timer()
 
 Only expose operating system clocks
 -----------------------------------
@@ -424,20 +429,48 @@
 to Python 3.3 for example.
 
 
-Fallback to system clock
-------------------------
+time.monotonic(): Fallback to system time
+-----------------------------------------
 
 If no monotonic clock is available, time.monotonic() falls back to the
-system clock.
+system time.
 
 Issues:
 
 * It is hard to define correctly such function in the documentation:
-  is it monotonic? is it steady? is it adjusted?
+  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?
 
+Different APIs were proposed to define such function.
+
+One function with a flag: time.monotonic(fallback=True)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* time.monotonic(fallback=True) falls back to the system time 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.
+
+
+One time.monotonic() function, no flag
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+time.monotonic() returns (time: float, is_monotonic: bool).
+
+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().
+
+
 
 Choosing the clock from a list of constraints
 ---------------------------------------------
@@ -503,32 +536,6 @@
 Example partial implementation:
 `clockutils.py <http://hg.python.org/peps/file/tip/pep-0418/clockutils.py>`_.
 
-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.
-
-
-One function, no flag
----------------------
-
-time.monotonic() returns (time: float, is_monotonic: bool).
-
-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?
 -------------------------------------
 
@@ -1127,8 +1134,8 @@
 On Solaris, gethrtime() is the same as clock_gettime(CLOCK_MONOTONIC).
 
 
-System clocks
--------------
+System Time
+-----------
 
 ========================= ===============  =============  ===============
 Name                      Resolution       Include sleep  Include suspend
@@ -1159,7 +1166,7 @@
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 The system time can be read using GetSystemTimeAsFileTime(), ftime() and
-time(). The precision of the system clock can be read using
+time(). The precision of the system time can be read using
 GetSystemTimeAdjustment().
 
 Read the `GetSystemTimeAsFileTime() documentation
@@ -1171,7 +1178,7 @@
 ^^^^^^^^^^^^^^^^^^^
 
 gettimeofday(), ftime(), time() and clock_gettime(CLOCK_REALTIME) return
-the system clock. The precision of CLOCK_REALTIME can be read using
+the system time. The precision of CLOCK_REALTIME can be read using
 clock_getres().
 
 The system time can be set using settimeofday() or
@@ -1224,8 +1231,9 @@
 Functions
 ^^^^^^^^^
 
-* Windows: GetProcessTimes(). The precision can be read using
-  GetSystemTimeAdjustment().
+* Windows: `GetProcessTimes()
+  <http://msdn.microsoft.com/en-us/library/windows/desktop/ms683223(v=vs.85).aspx>`_.
+  The precision can be read using GetSystemTimeAdjustment().
 * clock_gettime(CLOCK_PROCESS_CPUTIME_ID): High-resolution per-process
   timer from the CPU. The precision can be read using clock_getres().
 * clock(). The precision is 1 / CLOCKS_PER_SEC.
@@ -1280,9 +1288,9 @@
 Functions
 ^^^^^^^^^
 
-* Windows: GetThreadTimes(). The precision can be read using
-  GetSystemTimeAdjustment(). `MSDN documentation of GetThreadTimes()
+* Windows: `GetThreadTimes()
   <http://msdn.microsoft.com/en-us/library/windows/desktop/ms683237(v=vs.85).aspx>`_.
+  The precision can be read using GetSystemTimeAdjustment().
 * clock_gettime(CLOCK_THREAD_CPUTIME_ID): Thread-specific CPU-time
   clock. The precision can be read using of clock_getres().
 
@@ -1312,11 +1320,11 @@
 Sleep
 -----
 
-Suspend execution of the process for the given number of seconds.  Sleep is not
-affected by system clock update. Sleep is paused during system suspend. For
-example, if a process sleeps for 60 seconds and the system is suspended for 30
-seconds in the middle of the sleep, the sleep duration is 90 seconds in the
-real time.
+Suspend execution of the process for the given number of seconds.
+Sleep is not affected by system time updates. Sleep is paused during
+system suspend. For example, if a process sleeps for 60 seconds and
+the system is suspended for 30 seconds in the middle of the sleep, the
+sleep duration is 90 seconds in the real time.
 
 Sleep can be interrupted by a signal: the function fails with EINTR.
 
@@ -1348,12 +1356,12 @@
 Functions
 ^^^^^^^^^
 
- * sleep(seconds)
- * usleep(microseconds)
- * nanosleep(nanoseconds, remaining):
-   `Linux manpage of nanosleep()
-   <http://www.kernel.org/doc/man-pages/online/pages/man2/nanosleep.2.html>`_
- * delay(milliseconds)
+* sleep(seconds)
+* usleep(microseconds)
+* nanosleep(nanoseconds, remaining):
+  `Linux manpage of nanosleep()
+  <http://www.kernel.org/doc/man-pages/online/pages/man2/nanosleep.2.html>`_
+* delay(milliseconds)
 
 
 clock_nanosleep
@@ -1390,19 +1398,19 @@
 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 precision of the timeout
-   shall be the precision of the clock on which it is based."
- * WaitForSingleObject(): use the same timer than GetTickCount() with
-   the same precision.
+* 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 time."
+* 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 time as
+  returned by the time() function.  The precision of the timeout
+  shall be the precision of the clock on which it is based."
+* WaitForSingleObject(): use the same timer than GetTickCount() with
+  the same precision.
 
 
 System Standby
@@ -1506,7 +1514,7 @@
   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
+  counter to compensate for a persistently fast or slow system time
 * `Retrieving system time
   <http://en.wikipedia.org/wiki/System_time#Retrieving_system_time>`_
   lists hardware clocks and time functions with their resolution and

-- 
Repository URL: http://hg.python.org/peps


More information about the Python-checkins mailing list