[Python-checkins] peps: PEP 418: Add fallback=True argument to time.monotonic()

victor.stinner python-checkins at python.org
Sat Mar 31 01:21:28 CEST 2012


http://hg.python.org/peps/rev/9e1dfb3d8c50
changeset:   4176:9e1dfb3d8c50
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Sat Mar 31 00:50:05 2012 +0200
summary:
  PEP 418: Add fallback=True argument to time.monotonic()

 * time.monotonic() doesn't use QPC anymore
 * Rewrite also time.monotonic() and time.highres() definitions.

files:
  pep-0418.txt |  88 ++++++++++++++++++++++++---------------
  1 files changed, 53 insertions(+), 35 deletions(-)


diff --git a/pep-0418.txt b/pep-0418.txt
--- a/pep-0418.txt
+++ b/pep-0418.txt
@@ -13,7 +13,7 @@
 Abstract
 ========
 
-Add time.monotonic() and time.highres() functions to Python 3.3.
+Add time.monotonic(fallback=True) and time.highres() functions to Python 3.3.
 
 
 Rationale
@@ -24,12 +24,19 @@
  * 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()
  * Benchmark, profiling, timeout: time.highres()
- * Event scheduler: time.monotonic()
+ * Event scheduler: time.monotonic(), or time.monotonic(fallback=False)
 
 
 Functions
 =========
 
+ * time.time(): system clock, "wall clock"
+ * time.highres(): clock with the best accuracy
+ * time.monotonic(fallback=True): monotonic clock. If no monotonic clock is
+   available, falls back to system clock by default, or raises an OSError if
+   *fallback* is False. time.monotonic(fallback=True) cannot go backward.
+
+
 time.time()
 -----------
 
@@ -68,12 +75,12 @@
                 return _time.time()
 
 
-time.monotonic()
-----------------
+time.monotonic(fallback=True)
+-----------------------------
 
-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 that cannot go backward, its rate is as steady as possible. 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
 available on GNU/Hurd for example.
@@ -85,34 +92,21 @@
     if os.name == 'nt':
         # GetTickCount64() requires Windows Vista, Server 2008 or later
         if hasattr(time, '_GetTickCount64'):
-            _get_tick_count = _time.GetTickCount64
+            def monotonic(fallback=True):
+                return _time.GetTickCount64()
         else:
-            def _get_tick_count():
+            def monotonic(fallback=True):
                 ticks = _time.GetTickCount()
-                if ticks < _get_tick_count.last:
+                if ticks < monotonic.last:
                     # Integer overflow detected
-                    _get_tick_count.delta += 2**32
-                _get_tick_count.last = ticks
-                return ticks + _get_tick_count.delta
-            _get_tick_count.last = 0
-            _get_tick_count.delta = 0
-
-        def monotonic():
-            if monotonic.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
-                    monotonic.use_performance_counter = False
-            # Fallback to GetTickCount/GetTickCount64 which has
-            # a lower resolution
-            return _get_tick_count()
-        monotonic.use_performance_counter = True
+                    monotonic.delta += 2**32
+                monotonic.last = ticks
+                return ticks + monotonic.delta
+            monotonic.last = 0
+            monotonic.delta = 0
 
     elif os.name == 'mac':
-        def monotonic():
+        def monotonic(fallback=True):
             if monotonic.factor is None:
                 factor = _time.mach_timebase_info()
                 monotonic.factor = timebase[0] / timebase[1]
@@ -120,31 +114,45 @@
         monotonic.factor = None
 
     elif os.name.startswith('sunos'):
-        def monotonic():
+        def monotonic(fallback=True):
             if monotonic.use_clock_highres:
                 try:
                     time.clock_gettime(time.CLOCK_HIGHRES)
                 except OSError:
                     monotonic.use_clock_highres = False
-            return time.gethrtime()
+            if monotonic.use_gethrtime:
+                try:
+                    return time.gethrtime()
+                except OSError:
+                    if not fallback:
+                        raise
+                    monotonic.use_gethrtime = False
+            return time.time()
         monotonic.use_clock_highres = (hasattr(time, 'clock_gettime')
                                        and hasattr(time, 'CLOCK_HIGHRES'))
+        monotonic.use_gethrtime = True
 
     elif hasattr(time, "clock_gettime"):
-        def monotonic():
+        def monotonic(fallback=True):
             while monotonic.clocks:
                 try:
                     clk_id = monotonic.clocks[0]
                     return time.clock_gettime(clk_id)
                 except OSError:
                     # CLOCK_MONOTONIC_RAW requires a Linux kernel >= 2.6.28
+                    if len(monotonic.clocks) == 1 and not fallback:
+                        raise
                     del monotonic.clocks[0]
-            return time.clock_gettime(time.CLOCK_MONOTONIC)
+            return time.time()
         monotonic.clocks = []
         if hasattr(time, 'CLOCK_MONOTONIC_RAW'):
             monotonic.clocks.append(time.CLOCK_MONOTONIC_RAW)
         if hasattr(time, 'CLOCK_HIGHRES'):
             monotonic.clocks.append(time.CLOCK_HIGHRES)
+        monotonic.clocks.append(time.CLOCK_MONOTONIC)
+
+On Windows, QueryPerformanceCounter() is not used even if it has a better
+resolution than GetTickCount(). It is not reliable and has too much issues.
 
 .. note::
 
@@ -157,20 +165,29 @@
 time.highres()
 --------------
 
-High-resolution clock: use a monotonic clock if available, or fallback to the
-system time.
+Clock with the best available resolution.
 
 It is available on all platforms and cannot fail.
 
 Pseudo-code::
 
     def highres():
+        if monotonic.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
+                monotonic.use_performance_counter = False
         if highres.use_monotonic:
+            # Monotonic clock is preferred over system clock
             try:
                 return time.monotonic()
             except OSError:
                 highres.use_monotonic = False
         return time.time()
+    highres.use_performance_counter = (os.name == 'nt')
     highres.use_monotonic = hasattr(time, 'monotonic')
 
 

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


More information about the Python-checkins mailing list