From: Christian Herdtweck Date: Wed, 6 Dec 2017 12:16:01 +0000 (+0100) Subject: Use a monotonic wall clock for performance tests also in py2 X-Git-Tag: v1.2~6 X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=627834fdf5db84b5bd32f9acc197e3d5922d4ff0;p=pyi2ncommon Use a monotonic wall clock for performance tests also in py2 This fixes the problem enountered sometimes in unittest test_log_read. The clock was not precise enough (10ms beat) --- diff --git a/src/test_helpers.py b/src/test_helpers.py index ec6e82f..18a233c 100644 --- a/src/test_helpers.py +++ b/src/test_helpers.py @@ -35,7 +35,7 @@ import time from datetime import datetime as dt from itertools import tee from warnings import warn -from sys import stderr, version_info, exit as sys_exit +from sys import stderr, platform, version_info, exit as sys_exit from os import getpid, kill, _exit as brutal_exit_function_DO_NOT_USE import signal @@ -439,13 +439,16 @@ def watch_disc_fill(paths=None, interval=0.1): def get_perf_counter(): - """ returns time.perf_counter or time.clock depending on python version + """ return the best monotonic clock for performance measure - before py 3.3: return function :py:function:`time.clock` + returned clocks are monotonic and measure "absoulte"/wall-clock time + differences (as opposed to time processor spends on the particular python + code, so sleep(1) should result in a perf counter diff of 1). + + before py 3.3: return monotonic clock from linux system after that: returns function :py:function:`time.perf_counter` - .. warn:: these will behave differently, so do not make assumption on change - or time during sleep or what 0 value means + .. warn:: absolute values mean nothing, only differences between calls! For simple single-command use cases: use ipython's %timeit magic command. @@ -460,8 +463,43 @@ def get_perf_counter(): """ if version_info.major == 2: - return time.clock + if platform.startswith('linux'): + return monotonic_clock_py2() + else: + return time.time elif version_info.major == 3 and version_info.minor < 3: return time.clock else: return time.perf_counter + + +def monotonic_clock_py2(): + """ get a monotonic clock in py2 using ctypes and clock_gettime + + copied from: + https://stackoverflow.com/questions/1205722/ + how-do-i-get-monotonic-time-durations-in-python + """ + + import ctypes + from os import strerror + CLOCK_MONOTONIC_RAW = 4 # see + + class timespec(ctypes.Structure): + _fields_ = [ + ('tv_sec', ctypes.c_long), + ('tv_nsec', ctypes.c_long) + ] + + librt = ctypes.CDLL('librt.so.1', use_errno=True) + clock_gettime = librt.clock_gettime + clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)] + + def monotonic_time(): + t = timespec() + if clock_gettime(CLOCK_MONOTONIC_RAW , ctypes.pointer(t)) != 0: + errno_ = ctypes.get_errno() + raise OSError(errno_, strerror(errno_)) + return t.tv_sec + t.tv_nsec * 1e-9 + + return monotonic_time