[pypy-commit] pypy py3k-clock_get_info: Commit what I have so far so I can test on windows. Everything added might not work properly. (Tests certainly don't pass)

marky1991 pypy.commits at gmail.com
Fri May 27 21:19:43 EDT 2016


Author: Mark Young <marky1991 at gmail.com>
Branch: py3k-clock_get_info
Changeset: r84755:855624d777e9
Date: 2016-05-17 00:07 -0400
http://bitbucket.org/pypy/pypy/changeset/855624d777e9/

Log:	Commit what I have so far so I can test on windows. Everything added
	might not work properly. (Tests certainly don't pass)

diff --git a/lib-python/conftest.py b/lib-python/conftest.py
--- a/lib-python/conftest.py
+++ b/lib-python/conftest.py
@@ -417,7 +417,7 @@
     RegrTest('test_threading.py', usemodules="thread", core=True),
     RegrTest('test_threading_local.py', usemodules="thread", core=True),
     RegrTest('test_threadsignals.py', usemodules="thread"),
-    RegrTest('test_time.py', core=True),
+    RegrTest('test_time.py', core=True, usemodules="struct"),
     RegrTest('test_timeit.py'),
     RegrTest('test_timeout.py'),
     RegrTest('test_tk.py'),
diff --git a/pypy/module/time/__init__.py b/pypy/module/time/__init__.py
--- a/pypy/module/time/__init__.py
+++ b/pypy/module/time/__init__.py
@@ -40,6 +40,7 @@
         'struct_time': 'app_time.struct_time',
         '__doc__': 'app_time.__doc__',
         'strptime': 'app_time.strptime',
+        'get_clock_info': 'app_time.get_clock_info'
     }
 
     def startup(self, space):
diff --git a/pypy/module/time/app_time.py b/pypy/module/time/app_time.py
--- a/pypy/module/time/app_time.py
+++ b/pypy/module/time/app_time.py
@@ -1,7 +1,8 @@
 # NOT_RPYTHON
 
 from _structseq import structseqtype, structseqfield
-
+from types import SimpleNamespace
+import time
 class struct_time(metaclass=structseqtype):
     __module__ = 'time'
     name = 'time.struct_time'
@@ -26,6 +27,28 @@
     import _strptime     # from the CPython standard library
     return _strptime._strptime_time(string, format)
 
+def get_clock_info(name):
+    info = SimpleNamespace()
+    info.implementation = ""
+    info.monotonic = 0
+    info.adjustable = 0
+    info.resolution = 1.0
+    print(id(info), "id in app")
+
+    if name == "time":
+        time.time(info)
+    elif name == "monotonic":
+        time.monotonic(info)
+    elif name == "clock":
+        time.clock(info)
+    elif name == "perf_counter":
+        time.perf_counter(info)
+    elif name == "process_time":
+        time.process_time(info)
+    else:
+        raise ValueError("unknown clock")
+    return info
+
 __doc__ = """This module provides various functions to manipulate time values.
 
 There are two standard representations of time.  One is the number
diff --git a/pypy/module/time/interp_time.py b/pypy/module/time/interp_time.py
--- a/pypy/module/time/interp_time.py
+++ b/pypy/module/time/interp_time.py
@@ -103,6 +103,14 @@
         def get_interrupt_event(self):
             return globalState.interrupt_event
 
+    # Can I just use one of the state classes above?
+    # I don't really get why an instance is better than a plain module
+    # attr, but following advice from armin
+    class TimeState(object):
+        def __init__(self):
+            self.n_overflow = 0
+            self.last_ticks = 0
+    time_state = TimeState()
 
 _includes = ["time.h"]
 if _POSIX:
@@ -118,6 +126,7 @@
     clock_t = platform.SimpleType("clock_t", rffi.ULONG)
     has_gettimeofday = platform.Has('gettimeofday')
     has_clock_gettime = platform.Has('clock_gettime')
+    has_gettickcount64 = platform.Has("GetTickCount64")
     CLOCK_PROF = platform.DefinedConstantInteger('CLOCK_PROF')
 
 CLOCK_CONSTANTS = ['CLOCK_HIGHRES', 'CLOCK_MONOTONIC', 'CLOCK_MONOTONIC_RAW',
@@ -185,6 +194,7 @@
 
 CLOCKS_PER_SEC = cConfig.CLOCKS_PER_SEC
 HAS_CLOCK_GETTIME = cConfig.has_clock_gettime
+HAS_GETTICKCOUNT64 = cConfig.has_gettickcount64
 clock_t = cConfig.clock_t
 tm = cConfig.tm
 glob_buf = lltype.malloc(tm, flavor='raw', zero=True, immortal=True)
@@ -503,18 +513,19 @@
 
     Return the current time in seconds since the Epoch.
     Fractions of a second may be present if the system clock provides them."""
-
     secs = pytime.time()
     return space.wrap(secs)
 
-def clock(space):
-    """clock() -> floating point number
-
-    Return the CPU time or real time since the start of the process or since
-    the first call to clock().  This has as much precision as the system
-    records."""
-
-    return space.wrap(pytime.clock())
+# TODO: Remember what this is for...
+def get_time_time_clock_info(space, w_info):
+    # Can't piggy back on time.time because time.time delegates to the 
+    # host python's time.time (so we can't see the internals)
+    if HAS_CLOCK_GETTIME:
+        try:
+            res = clock_getres(space, cConfig.CLOCK_REALTIME)
+        except OperationError:
+            res = 1e-9
+    #else: ???
 
 def ctime(space, w_seconds=None):
     """ctime([seconds]) -> string
@@ -717,9 +728,51 @@
 if _WIN:
     # untested so far
     _GetTickCount64 = rwin32.winexternal('GetTickCount64', [], rffi.ULONGLONG)
+    _GetTickCount = rwin32.winexternal('GetTickCount', [], rwin32.DWORD)
+    LPDWORD = rwin32.LPDWORD
+    _GetSystemTimeAdjustment = rwin32.winexternal(
+                                            'GetSystemTimeAdjustment',
+                                            [LPDWORD, LPDWORD, rffi.INTP], 
+                                            rffi.INT)
 
-    def monotonic(space):
-        return space.wrap(_GetTickCount64() * 1e-3)
+    def monotonic(space, w_info=None):
+        result = 0
+        if HAS_GETTICKCOUNT64:
+            result = _GetTickCount64() * 1e-3
+        else:
+            ticks = _GetTickCount()
+            if ticks < time_state.last_ticks:
+                time_state.n_overflow += 1
+            time_state.last_ticks = ticks
+            result = math.ldexp(time_state.n_overflow, 32)
+            result = result + ticks
+            result = result * 1e-3
+            
+        if w_info is not None:
+            if HAS_GETTICKCOUNT64:
+                space.setattr(w_info, space.wrap("implementation"),
+                              space.wrap("GetTickCount64()"))
+            else:
+                space.setattr(w_info, space.wrap("implementation"),
+                              space.wrap("GetTickCount()"))
+            resolution = 1e-7
+            with lltype.scoped_alloc(rwin32.LPDWORD) as time_adjustment, \
+                 lltype.scoped_alloc(rwin32.LPDWORD) as time_increment, \
+                 lltype.scoped_alloc(rwin32.FILETIME) as is_time_adjustment_disabled:
+                ok = _GetSystemTimeAdjustment(time_adjustment,
+                                              time_increment,
+                                              is_time_adjustment_disabled)
+                if not ok:
+                    # Is this right? Cargo culting...
+                    raise wrap_windowserror(space,
+                        rwin32.lastSavedWindowsError("GetSystemTimeAdjustment"))
+                resolution = resolution * time_increment
+                
+            space.setattr(w_info, space.wrap("monotonic"), space.w_True)
+            space.setattr(w_info, space.wrap("adjustable"), space.w_False)
+            space.setattr(w_info, space.wrap("resolution"),
+                          space.wrap(resolution))
+        return space.wrap(result)
 
 elif _MACOSX:
     c_mach_timebase_info = external('mach_timebase_info',
@@ -730,13 +783,23 @@
     timebase_info = lltype.malloc(cConfig.TIMEBASE_INFO, flavor='raw',
                                   zero=True, immortal=True)
 
-    def monotonic(space):
+    def monotonic(space, w_info=None):
         if rffi.getintfield(timebase_info, 'c_denom') == 0:
             c_mach_timebase_info(timebase_info)
         time = rffi.cast(lltype.Signed, c_mach_absolute_time())
         numer = rffi.getintfield(timebase_info, 'c_numer')
         denom = rffi.getintfield(timebase_info, 'c_denom')
         nanosecs = time * numer / denom
+        if w_info is not None:
+            space.setattr(w_info, space.wrap("monotonic"), space.w_True)
+            space.setattr(w_info, space.wrap("implementation"),
+                          space.wrap("mach_absolute_time()"))
+            space.setattr(w_info, space.wrap("adjustable"), space.w_False)
+            space.setattr(w_info, space.wrap("resolution"),
+                          #Do I need to convert to float indside the division?
+                          # Looking at the C, I would say yes, but nanosecs
+                          # doesn't...
+                          space.wrap((numer / denom) * 1e-9))
         secs = nanosecs / 10**9
         rest = nanosecs % 10**9
         return space.wrap(float(secs) + float(rest) * 1e-9)
@@ -744,21 +807,49 @@
 else:
     assert _POSIX
     if cConfig.CLOCK_HIGHRES is not None:
-        def monotonic(space):
+        def monotonic(space, w_info=None):
+            if w_info is not None:
+                space.setattr(w_info, space.wrap("monotonic"), space.w_True)
+                space.setattr(w_info, space.wrap("implementation"),
+                              space.wrap("clock_gettime(CLOCK_HIGHRES)"))
+                space.setattr(w_info, space.wrap("adjustable"), space.w_False)
+                try:
+                    space.setattr(w_info, space.wrap("resolution"),
+                                  space.wrap(clock_getres(space, cConfig.CLOCK_HIGHRES)))
+                except OSError:
+                    space.setattr(w_info, space.wrap("resolution"),
+                                  space.wrap(1e-9))
+                
             return clock_gettime(space, cConfig.CLOCK_HIGHRES)
     else:
-        def monotonic(space):
+        def monotonic(space, w_info=None):
+            if w_info is not None:
+                space.setattr(w_info, space.wrap("monotonic"), space.w_True)
+                space.setattr(w_info, space.wrap("implementation"),
+                              space.wrap("clock_gettime(CLOCK_MONOTONIC)"))
+                space.setattr(w_info, space.wrap("adjustable"), space.w_False)
+                try:
+                    space.setattr(w_info, space.wrap("resolution"),
+                                  space.wrap(clock_getres(space, cConfig.CLOCK_MONOTONIC)))
+                except OSError:
+                    space.setattr(w_info, space.wrap("resolution"),
+                                  space.wrap(1e-9))
+
             return clock_gettime(space, cConfig.CLOCK_MONOTONIC)
 
+if _WIN:
+    def perf_counter(space, w_info=None):
+        # What if the windows perf counter fails?
+        # Cpython falls back to monotonic and then clock
+        # Shouldn't we?
+        # TODO: Discuss on irc
 
-if _WIN:
-    def perf_counter(space):
+        # TODO: Figure out how to get at the internals of this
         return space.wrap(win_perf_counter())
 
 else:
-    def perf_counter(space):
-        return monotonic(space)
-
+    def perf_counter(space, w_info=None):
+        return monotonic(space, w_info=w_info)
 
 if _WIN:
     # untested so far
@@ -810,3 +901,54 @@
                     cpu_time = float(tms.c_tms_utime + tms.c_tms_stime)
                     return space.wrap(cpu_time / rposix.CLOCK_TICKS_PER_SECOND)
         return clock(space)
+
+if _WIN:
+    def clock(space, w_info=None):
+        """clock() -> floating point number
+
+        Return the CPU time or real time since the start of the process or since
+        the first call to clock().  This has as much precision as the system
+        records."""
+        return space.wrap(win_perf_counter(space, w_info=w_info))
+
+else:
+    _clock = external('clock', [], clock_t)
+    def clock(space, w_info=None):
+        """clock() -> floating point number
+
+        Return the CPU time or real time since the start of the process or since
+        the first call to clock().  This has as much precision as the system
+        records."""
+        value = _clock()
+        #Is this casting correct?
+        if value == rffi.cast(clock_t, -1):
+            raise RunTimeError("the processor time used is not available "
+                               "or its value cannot be represented")
+
+        print(w_info, "INFO")
+        if w_info is not None:
+            space.setattr(w_info, space.wrap("implementation"),
+                          space.wrap("clock()"))
+            space.setattr(w_info, space.wrap("resolution"),
+                          space.wrap(1.0 / CLOCKS_PER_SEC))
+            space.setattr(w_info, space.wrap("monotonic"),
+                          space.w_True)
+            space.setattr(w_info, space.wrap("adjustable"),
+                          space.w_False)
+        return space.wrap((1.0 * value) / CLOCKS_PER_SEC)
+
+
+def get_clock_info_dict(space, name):
+    if name == "time":
+        return 5#floattime(info)
+    elif name == "monotonic":
+        return monotonic(info)
+    elif name == "clock":
+        return clock(info)
+    elif name == "perf_counter":
+        return perf_counter(info)
+    elif name == "process_time":
+        return 5#process_time(info)
+    else:
+        raise ValueError("unknown clock")
+
diff --git a/pypy/module/time/test/test_time.py b/pypy/module/time/test/test_time.py
--- a/pypy/module/time/test/test_time.py
+++ b/pypy/module/time/test/test_time.py
@@ -379,3 +379,21 @@
         t2 = time.process_time()
         # process_time() should not include time spent during sleep
         assert (t2 - t1) < 0.05
+
+    def test_get_clock_info_monotonic(self):
+        import time
+        clock_info = time.get_clock_info("monotonic")
+        assert clock_info.monotonic
+        assert not clock_info.adjustable
+        # Not really sure what to test about this
+        # At least this tests that the attr exists...
+        assert clock_info.resolution > 0
+
+    def test_get_clock_info_clock(self):
+        import time
+        clock_info = time.get_clock_info("clock")
+        assert clock_info.monotonic
+        assert not clock_info.adjustable
+        # Not really sure what to test about this
+        # At least this tests that the attr exists...
+        assert clock_info.resolution > 0


More information about the pypy-commit mailing list