Author: Mark Young <marky1...@gmail.com> Branch: py3k Changeset: r85801:6cec221f8473 Date: 2016-07-07 21:53 -0400 http://bitbucket.org/pypy/pypy/changeset/6cec221f8473/
Log: Hopefully final tweaks to match all fallback scenarios with cpython for time.get_clock_info . 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 @@ -36,9 +36,9 @@ if name == "time": time.time(info) - elif name == "monotonic": + elif name == "monotonic" and hasattr(time, "monotonic"): time.monotonic(info) - elif name == "clock": + elif name == "clock" and hasattr(time, "clock"): time.clock(info) elif name == "perf_counter": time.perf_counter(info) 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 @@ -161,6 +161,7 @@ has_gettimeofday = platform.Has('gettimeofday') has_clock_gettime = platform.Has('clock_gettime') CLOCK_PROF = platform.DefinedConstantInteger('CLOCK_PROF') + HAVE_CLOCK = platform.DefinedConstantInteger("HAVE_CLOCK") CLOCK_CONSTANTS = ['CLOCK_HIGHRES', 'CLOCK_MONOTONIC', 'CLOCK_MONOTONIC_RAW', 'CLOCK_PROCESS_CPUTIME_ID', 'CLOCK_REALTIME', @@ -227,6 +228,11 @@ CLOCKS_PER_SEC = cConfig.CLOCKS_PER_SEC HAS_CLOCK_GETTIME = cConfig.has_clock_gettime +HAS_CLOCK_HIGHRES = cConfig.CLOCK_HIGHRES is not None +HAS_CLOCK_MONOTONIC = cConfig.CLOCK_MONOTONIC is not None +HAS_CLOCK = _WIN or cConfig.HAVE_CLOCK +HAS_MONOTONIC = (_WIN or _MACOSX or + (HAS_CLOCK_GETTIME and (HAS_CLOCK_HIGHRES or HAS_CLOCK_MONOTONIC))) clock_t = cConfig.clock_t tm = cConfig.tm glob_buf = lltype.malloc(tm, flavor='raw', zero=True, immortal=True) @@ -827,102 +833,135 @@ lltype.free(outbuf, flavor='raw') i += i +if HAS_MONOTONIC: + if _WIN: + _GetTickCount = rwin32.winexternal('GetTickCount', [], rwin32.DWORD) + def monotonic(space, w_info=None): + result = 0 + HAS_GETTICKCOUNT64 = time_state.check_GetTickCount64() + if HAS_GETTICKCOUNT64: + result = time_state.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: + implementation = "GetTickCount64()" + else: + implementation = "GetTickCount()" + resolution = 1e-7 + with lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as time_adjustment, \ + lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as time_increment, \ + lltype.scoped_alloc(rwin32.LPBOOL.TO, 1) 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[0] + _setinfo(space, w_info, implementation, resolution, True, False) + return space.wrap(result) + + elif _MACOSX: + c_mach_timebase_info = external('mach_timebase_info', + [lltype.Ptr(cConfig.TIMEBASE_INFO)], + lltype.Void) + c_mach_absolute_time = external('mach_absolute_time', [], rffi.ULONGLONG) + + timebase_info = lltype.malloc(cConfig.TIMEBASE_INFO, flavor='raw', + zero=True, immortal=True) + + 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: + res = (numer / denom) * 1e-9 + _setinfo(space, w_info, "mach_absolute_time()", res, True, False) + secs = nanosecs / 10**9 + rest = nanosecs % 10**9 + return space.wrap(float(secs) + float(rest) * 1e-9) + + else: + assert _POSIX + def monotonic(space, w_info=None): + if cConfig.CLOCK_HIGHRES is not None: + clk_id = cConfig.CLOCK_HIGHRES + implementation = "clock_gettime(CLOCK_HIGHRES)" + else: + clk_id = cConfig.CLOCK_MONOTONIC + implementation = "clock_gettime(CLOCK_MONOTONIC)" + w_result = clock_gettime(space, clk_id) + if w_info is not None: + with lltype.scoped_alloc(TIMESPEC) as tsres: + ret = c_clock_getres(clk_id, tsres) + if ret == 0: + res = _timespec_to_seconds(tsres) + else: + res = 1e-9 + _setinfo(space, w_info, implementation, res, True, False) + return w_result if _WIN: - _GetTickCount = rwin32.winexternal('GetTickCount', [], rwin32.DWORD) - def monotonic(space, w_info=None): - result = 0 - HAS_GETTICKCOUNT64 = time_state.check_GetTickCount64() - if HAS_GETTICKCOUNT64: - result = time_state.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 + # hacking to avoid LARGE_INTEGER which is a union... + QueryPerformanceCounter = external( + 'QueryPerformanceCounter', [rffi.CArrayPtr(lltype.SignedLongLong)], + lltype.Void, releasegil=False) + QueryPerformanceFrequency = external( + 'QueryPerformanceFrequency', [rffi.CArrayPtr(lltype.SignedLongLong)], + rffi.INT, releasegil=False) + class State(object): + divisor = 0.0 + counter_start = 0 + state = State() + def win_perf_counter(space, w_info=None): + with lltype.scoped_alloc(rffi.CArray(rffi.lltype.SignedLongLong), 1) as a: + failed = False + if state.divisor == 0.0: + QueryPerformanceCounter(a) + state.counter_start = a[0] + failed = QueryPerformanceFrequency(a) + state.divisor = float(a[0]) + if not failed and state.divisor != 0.0: + QueryPerformanceCounter(a) + diff = a[0] - state.counter_start + resolution = 1 / state.divisor + _setinfo(space, w_info, "QueryPerformanceCounter()", resolution, + True, False) + return space.wrap(float(diff) / state.divisor) + else: + raise ValueError("Failed to generate the result.") - if w_info is not None: - if HAS_GETTICKCOUNT64: - implementation = "GetTickCount64()" - else: - implementation = "GetTickCount()" - resolution = 1e-7 - with lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as time_adjustment, \ - lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as time_increment, \ - lltype.scoped_alloc(rwin32.LPBOOL.TO, 1) 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[0] - _setinfo(space, w_info, implementation, resolution, True, False) - return space.wrap(result) - -elif _MACOSX: - c_mach_timebase_info = external('mach_timebase_info', - [lltype.Ptr(cConfig.TIMEBASE_INFO)], - lltype.Void) - c_mach_absolute_time = external('mach_absolute_time', [], rffi.ULONGLONG) - - timebase_info = lltype.malloc(cConfig.TIMEBASE_INFO, flavor='raw', - zero=True, immortal=True) - - 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: - # Do I need to convert to float indside the division? - # Looking at the C, I would say yes, but nanosecs - # doesn't... - res = (numer / denom) * 1e-9 - _setinfo(space, w_info, "mach_absolute_time()", res, True, False) - secs = nanosecs / 10**9 - rest = nanosecs % 10**9 - return space.wrap(float(secs) + float(rest) * 1e-9) - -else: - assert _POSIX - def monotonic(space, w_info=None): - if cConfig.CLOCK_HIGHRES is not None: - clk_id = cConfig.CLOCK_HIGHRES - implementation = "clock_gettime(CLOCK_HIGHRES)" - else: - clk_id = cConfig.CLOCK_MONOTONIC - implementation = "clock_gettime(CLOCK_MONOTONIC)" - w_result = clock_gettime(space, clk_id) - if w_info is not None: - with lltype.scoped_alloc(TIMESPEC) as tsres: - ret = c_clock_getres(clk_id, tsres) - if ret == 0: - res = _timespec_to_seconds(tsres) - else: - res = 1e-9 - _setinfo(space, w_info, implementation, res, True, False) - return w_result - -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 - - # TODO: Figure out how to get at the internals of this - return space.wrap(win_perf_counter()) + try: + return win_perf_counter(space, w_info=w_info) + except ValueError: + if HAS_MONOTONIC: + try: + return monotonic(space, w_info=w_info) + except Exception: + pass + return time(space, w_info=w_info) else: def perf_counter(space, w_info=None): - return monotonic(space, w_info=w_info) + if HAS_MONOTONIC: + try: + return monotonic(space, w_info=w_info) + except Exception: + pass + return time(space, w_info=w_info) if _WIN: # untested so far @@ -993,33 +1032,29 @@ return space.wrap(cpu_time / rposix.CLOCK_TICKS_PER_SECOND) return clock(space) -if _WIN: +if HAS_CLOCK: + _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.""" - return space.wrap(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 oefmt(space.w_RuntimeError, - "the processor time used is not available or its value" - "cannot be represented") - if w_info is not None: - _setinfo(space, w_info, - "clock()", 1.0 / CLOCKS_PER_SEC, True, False) - return space.wrap((1.0 * value) / CLOCKS_PER_SEC) + if _WIN: + try: + return win_perf_counter(space, w_info=w_info)) + except ValueError: + pass + value = _clock() + # Is this casting correct? + if value == rffi.cast(clock_t, -1): + raise oefmt(space.w_RuntimeError, + "the processor time used is not available or its value" + "cannot be represented") + if w_info is not None: + _setinfo(space, w_info, + "clock()", 1.0 / CLOCKS_PER_SEC, True, False) + return space.wrap((1.0 * value) / CLOCKS_PER_SEC) def _setinfo(space, w_info, impl, res, mono, adj): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit