[Python-checkins] peps: Rewrite the PEP 418

victor.stinner python-checkins at python.org
Wed Apr 4 02:58:04 CEST 2012


http://hg.python.org/peps/rev/5f1708dfd267
changeset:   4199:5f1708dfd267
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Wed Apr 04 02:57:55 2012 +0200
summary:
  Rewrite the PEP 418

 * Rename time.steady() to time.monotonic(), again
 * time.monotonic() does not fallback to the system clock anymore
 * Drop time.perf_counter() function

files:
  pep-0418.txt |  209 ++++++++++++++++----------------------
  1 files changed, 86 insertions(+), 123 deletions(-)


diff --git a/pep-0418.txt b/pep-0418.txt
--- a/pep-0418.txt
+++ b/pep-0418.txt
@@ -1,5 +1,5 @@
 PEP: 418
-Title: Add steady and high-resolution time functions
+Title: Add a monotonic time functions
 Version: $Revision$
 Last-Modified: $Date$
 Author: Victor Stinner <victor.stinner at gmail.com>
@@ -13,8 +13,7 @@
 Abstract
 ========
 
-Add time.steady(), time.perf_counter(), time.get_clock_info(name) functions to
-Python 3.3.
+Add time.monotonic() and time.get_clock_info(name) functions to Python 3.3.
 
 
 Rationale
@@ -25,8 +24,9 @@
 * Display the current time to a human (e.g. display a calendar or draw
   a wall clock): use system clock, i.e. time.time() or
   datetime.datetime.now().
-* Benchmark, profiling: time.perf_counter().
-* Event scheduler, timeout: time.steady().
+* Event scheduler, timeout: time.monotonic().
+* Benchmark, profiling: time.clock() on Windows, time.monotonic(),
+  or fallback to time.time()
 
 
 Functions
@@ -35,8 +35,7 @@
 To fulfill the use cases, the functions' properties are:
 
 * time.time(): system clock, "wall clock".
-* time.perf_counter(): clock with the best accuracy.
-* time.steady(): steady clock, should be monotonic
+* time.monotonic(): monotonic clock
 * time.get_clock_info(name): get information on the specified time function
 
 
@@ -78,129 +77,75 @@
                 return _time.time()
 
 
-time.steady()
--------------
+time.monotonic()
+----------------
 
-Steady clock. Use a monotonic clock, or falls back to the system clock.  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.
-
-Use time.get_clock_info('steady')['is_monotonic'] to check if the clock
-monotonic or not.
+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
 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 steady():
+            def monotonic():
                 return _time.GetTickCount64() * 1e-3
         else:
-            def steady():
+            def monotonic():
                 ticks = _time.GetTickCount()
-                if ticks < steady.last:
+                if ticks < monotonic.last:
                     # Integer overflow detected
-                    steady.delta += 2**32
-                steady.last = ticks
-                return (ticks + steady.delta) * 1e-3
-            steady.last = 0
-            steady.delta = 0
+                    monotonic.delta += 2**32
+                monotonic.last = ticks
+                return (ticks + monotonic.delta) * 1e-3
+            monotonic.last = 0
+            monotonic.delta = 0
 
     elif os.name == 'mac':
-        def steady():
-            if steady.factor is None:
+        def monotonic():
+            if monotonic.factor is None:
                 factor = _time.mach_timebase_info()
-                steady.factor = timebase[0] / timebase[1]
-            return _time.mach_absolute_time() * steady.factor
-        steady.factor = None
+                monotonic.factor = timebase[0] / timebase[1]
+            return _time.mach_absolute_time() * monotonic.factor
+        monotonic.factor = None
 
-    elif os.name.startswith('sunos'):
-        def steady():
-            if steady.use_clock_highres:
+    elif hasattr(time, "clock_gettime"):
+        def monotonic():
+            if monotonic.use_clock_highres:
                 try:
                     time.clock_gettime(time.CLOCK_HIGHRES)
                 except OSError:
-                    steady.use_clock_highres = False
-            if steady.use_gethrtime:
-                try:
-                    return time.gethrtime()
-                except OSError:
-                    steady.use_gethrtime = False
-            return time.time()
-        steady.use_clock_highres = (hasattr(time, 'clock_gettime')
+                    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'))
-        steady.use_gethrtime = True
 
-    elif hasattr(time, "clock_gettime"):
-        def steady():
-            while steady.clocks:
-                try:
-                    clk_id = steady.clocks[0]
-                    return time.clock_gettime(clk_id)
-                except OSError:
-                    del steady.clocks[0]
-            return time.time()
-        steady.clocks = []
-        if hasattr(time, 'CLOCK_HIGHRES'):
-            steady.clocks.append(time.CLOCK_HIGHRES)
-        steady.clocks.append(time.CLOCK_MONOTONIC)
 
-    else:
-        def steady():
-            return time.time()
-
-On Windows, QueryPerformanceCounter() is not used even though it has a
-better resolution than GetTickCount().  It is not reliable and has too
-many issues.
+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.steady() 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.steady() may be
-   different in two Python processes.
+   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.perf_counter()
--------------------
-
-Clock with the best available resolution.
-
-It is available on all platforms and cannot fail.
-
-Pseudo-code::
-
-    def perf_counter():
-        if perf_counter.use_performance_counter:
-            try:
-                return _time.QueryPerformanceCounter()
-            except OSError:
-                # QueryPerformanceFrequency() may fail, if the installed
-                # hardware does not support a high-resolution performance
-                # counter for example
-                perf_counter.use_performance_counter = False
-        if perf_counter.use_steady:
-            # Monotonic clock is preferred over system clock
-            try:
-                return time.steady()
-            except OSError:
-                perf_counter.use_steady = False
-        return time.time()
-    perf_counter.use_performance_counter = (os.name == 'nt')
-    perf_counter.use_steady = hasattr(time, 'steady')
-
 time.get_clock_info(name)
 -------------------------
 
 Get information on the specified clock. Supported clocks:
 
  * "clock": time.clock()
- * "perf_counter": time.perf_counter()
- * "steady": time.steady()
+ * "monotonic": time.monotonic()
  * "time": time.time()
 
 Return a dictionary with the following keys:
@@ -264,8 +209,8 @@
   32,768 Hz
 
 
-NTP adjusted
-============
+NTP adjustment
+==============
 
 NTP has diffent methods to adjust a clock:
 
@@ -655,10 +600,6 @@
 always return 1 nanosecond. For GetProcessTimes(), the accuracy is read using
 GetSystemTimeAdjustment().
 
-Python source code includes a portable library to get the process time:
-`Tools/pybench/systimes.py
-<http://hg.python.org/cpython/file/tip/Tools/pybench/systimes.py>`_.
-
 
 Functions
 ^^^^^^^^^
@@ -793,27 +734,17 @@
 Alternatives: API design
 ========================
 
-Other names for new functions
------------------------------
+Other names for time.monotonic()
+--------------------------------
 
-time.perf_counter():
-
-* time.highres()
-* time.hires(): "hires" can be read as "to hire" as in "he hires a car
-  to go on holiday", rather than a "HIgh-RESolution clock".
-* time.timer(): "it would be too easy to confuse with (or misspell as)
-  time.time()"
-
-time.steady():
-
-* time.monotonic(): QueryPerformanceCounter() is monotonic but it is not used
-  by time.steady() because it is not steady, and it is surprising to have to
-  check for time.get_clock_info('monotonic')['is_monotonic'].
-* time.try_monotonic(): it is a clear and obvious solution for the
-  use-case of "I prefer the monotonic clock, if it is available,
-  otherwise I'll take my chances with a best-effect clock."
+* time.steady()
 * time.wallclock(): it is not the system time aka the "wall clock", but
   a monotonic clock with an unspecified starting point
+* time.seconds()
+* time.counter()
+
+The name "time.try_monotonic()" was also proposed when time.monotonic() was
+falling back to the system clock when no monotonic clock was available.
 
 
 Only expose operating system clocks
@@ -824,14 +755,18 @@
 related clock identifiers were already added to Python 3.3 for example.
 
 
-Don't fallback on system clock
-------------------------------
+Fallback to system clock
+------------------------
 
-time.monotonic() is always a monotonic clock and is only available if the
-operating system provides a monotonic clock.
+If no monotonic clock is available, time.monotonic() falls back to the system
+clock.
 
-time.perf_counter() is only available if the operating system provides a clock
-with a high resolution (e.g. at least a microsecond or better).
+Issues:
+
+ * 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
 
 
 One function choosing the clock from a list of constrains
@@ -846,7 +781,8 @@
 time.get_clock() returns None if the clock is found and so calls can be chained
 using the or operator. Example::
 
- func = time.get_clock(time.MONOTONIC) or time.get_clock(time.STEADY) or time.time()
+ get_time = time.get_clock(time.MONOTONIC) or time.get_clock(time.STEADY) or time.time()
+ t = get_time()
 
 Example of flags of system clocks:
 
@@ -854,7 +790,7 @@
  * GetTickCount: MONOTONIC | STEADY
  * CLOCK_MONOTONIC: MONOTONIC | STEADY (or only MONOTONIC on Linux)
  * CLOCK_MONOTONIC_RAW: MONOTONIC | STEADY
- * gettimeofday(): (none)
+ * gettimeofday(): (no flag)
 
 
 One function with a flag: time.monotonic(fallback=True)
@@ -908,6 +844,29 @@
    see the same clock value
 
 
+Deferred API: time.perf_counter()
+=================================
+
+Python does not provide a portable "performance counter" clock for benchmarking
+or profiling. Each tool has to implement its own heuristic to decide which
+clock is the best depending on the OS and on which counters are available.
+
+A previous version of the PEP proposed a time.perf_counter() function using
+QueryPerformanceCounter() on Windows, time.monotonic(), or falls back to the
+system time. This function was not well defined and the idea is deferred.
+
+Proposed names for such function:
+
+ * time.hires()
+ * time.highres()
+ * time.perf_counter()
+ * time.timer()
+
+Python source code includes a portable library to get the process time:
+`Tools/pybench/systimes.py
+<http://hg.python.org/cpython/file/tip/Tools/pybench/systimes.py>`_.
+
+
 Footnotes
 =========
 

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


More information about the Python-checkins mailing list