From cba9a0c6def70549046f1afa6a80e38fe706520e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 12 Oct 2017 08:51:56 -0700 Subject: [PATCH] bpo-31773: time.perf_counter() uses again double (GH-3964) time.clock() and time.perf_counter() now use again C double internally. Remove also _PyTime_GetWinPerfCounterWithInfo(): use _PyTime_GetPerfCounterDoubleWithInfo() instead on Windows. --- Include/pytime.h | 23 ++++++++++++----------- Modules/timemodule.c | 28 +++++++++++----------------- Python/import.c | 12 ++++++------ Python/pytime.c | 36 +++++++++++++++++++++--------------- 4 files changed, 50 insertions(+), 49 deletions(-) diff --git a/Include/pytime.h b/Include/pytime.h index 95d482fee3b2d1..fd95045519d62b 100644 --- a/Include/pytime.h +++ b/Include/pytime.h @@ -192,20 +192,21 @@ PyAPI_FUNC(int) _PyTime_localtime(time_t t, struct tm *tm); Return 0 on success, raise an exception and return -1 on error. */ PyAPI_FUNC(int) _PyTime_gmtime(time_t t, struct tm *tm); -#ifdef MS_WINDOWS -PyAPI_FUNC(int) _PyTime_GetWinPerfCounterWithInfo( - _PyTime_t *t, - _Py_clock_info_t *info); -#endif +/* Get the performance counter: clock with the highest available resolution to + measure a short duration. + + The function cannot fail. _PyTime_Init() ensures that the system clock + works. */ +PyAPI_FUNC(double) _PyTime_GetPerfCounterDouble(void); /* Get the performance counter: clock with the highest available resolution to - measure a short duration. */ -PyAPI_FUNC(_PyTime_t) _PyTime_GetPerfCounter(void); + measure a short duration. -/* Similar to _PyTime_GetPerfCounter(), - but get also clock info if info is non-NULL. */ -PyAPI_FUNC(int) _PyTime_GetPerfCounterWithInfo( - _PyTime_t *t, + Fill info (if set) with information of the function used to get the time. + + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) _PyTime_GetPerfCounterDoubleWithInfo( + double *t, _Py_clock_info_t *info); #ifdef __cplusplus diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 2c0a8d61edac43..3cb1b4ec0b6d11 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -88,19 +88,23 @@ floatclock(_Py_clock_info_t *info) } #endif /* HAVE_CLOCK */ +static PyObject* +perf_counter(_Py_clock_info_t *info) +{ + double t; + if (_PyTime_GetPerfCounterDoubleWithInfo(&t, info) < 0) { + return NULL; + } + return PyFloat_FromDouble(t); +} + #if defined(MS_WINDOWS) || defined(HAVE_CLOCK) #define PYCLOCK static PyObject* pyclock(_Py_clock_info_t *info) { #ifdef MS_WINDOWS - /* Win32 has better clock replacement; we have our own version, due to Mark - Hammond and Tim Peters */ - _PyTime_t t; - if (_PyTime_GetWinPerfCounterWithInfo(&t, info) < 0) { - return NULL; - } - return _PyFloat_FromPyTime(t); + return perf_counter(info); #else return floatclock(info); #endif @@ -936,16 +940,6 @@ PyDoc_STRVAR(monotonic_doc, \n\ Monotonic clock, cannot go backward."); -static PyObject* -perf_counter(_Py_clock_info_t *info) -{ - _PyTime_t t; - if (_PyTime_GetPerfCounterWithInfo(&t, info) < 0) { - return NULL; - } - return _PyFloat_FromPyTime(t); -} - static PyObject * time_perf_counter(PyObject *self, PyObject *unused) { diff --git a/Python/import.c b/Python/import.c index d396b4de7934dc..76aa912dc863c8 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1669,10 +1669,10 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, else { static int ximporttime = 0; static int import_level; - static _PyTime_t accumulated; + static double accumulated; _Py_IDENTIFIER(importtime); - _PyTime_t t1 = 0, accumulated_copy = accumulated; + double t1 = 0, accumulated_copy = accumulated; Py_XDECREF(mod); @@ -1695,7 +1695,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, if (ximporttime) { import_level++; - t1 = _PyTime_GetPerfCounter(); + t1 = _PyTime_GetPerfCounterDouble(); accumulated = 0; } @@ -1711,12 +1711,12 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, mod != NULL); if (ximporttime) { - _PyTime_t cum = _PyTime_GetPerfCounter() - t1; + double cum = _PyTime_GetPerfCounterDouble() - t1; import_level--; fprintf(stderr, "import time: %9ld | %10ld | %*s%s\n", - (long)_PyTime_AsMicroseconds(cum - accumulated, _PyTime_ROUND_CEILING), - (long)_PyTime_AsMicroseconds(cum, _PyTime_ROUND_CEILING), + (long)ceil((cum - accumulated) * 1e6), + (long)ceil(cum * 1e6), import_level*2, "", PyUnicode_AsUTF8(abs_name)); accumulated = accumulated_copy + cum; diff --git a/Python/pytime.c b/Python/pytime.c index dbf1dda4a0e75d..7fd2a90f3bd4ac 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -801,8 +801,8 @@ _PyTime_GetMonotonicClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) #ifdef MS_WINDOWS -int -_PyTime_GetWinPerfCounterWithInfo(_PyTime_t *t, _Py_clock_info_t *info) +static int +win_perf_counter(double *tp, _Py_clock_info_t *info) { static LONGLONG cpu_frequency = 0; static LONGLONG ctrStart; @@ -829,28 +829,33 @@ _PyTime_GetWinPerfCounterWithInfo(_PyTime_t *t, _Py_clock_info_t *info) } diff = diff / (double)cpu_frequency; - return _PyTime_FromDouble(t, diff, _PyTime_ROUND_FLOOR, SEC_TO_NS); + *tp = diff; + return 0; } #endif int -_PyTime_GetPerfCounterWithInfo(_PyTime_t *t, _Py_clock_info_t *info) +_PyTime_GetPerfCounterDoubleWithInfo(double *d, _Py_clock_info_t *info) { #ifdef MS_WINDOWS - return _PyTime_GetWinPerfCounterWithInfo(t, info); + return win_perf_counter(d, info); #else - return _PyTime_GetMonotonicClockWithInfo(t, info); + _PyTime_t t; + if (_PyTime_GetMonotonicClockWithInfo(&t, info) < 0) { + return -1; + } + *d = _PyTime_AsSecondsDouble(t); + return 0; #endif } -_PyTime_t -_PyTime_GetPerfCounter(void) +double +_PyTime_GetPerfCounterDouble(void) { - _PyTime_t t; - if (_PyTime_GetPerfCounterWithInfo(&t, NULL) < 0) { - /* should not happen, _PyTime_Init() checked the clock at startup */ + double t; + if (_PyTime_GetPerfCounterDoubleWithInfo(&t, NULL)) { Py_UNREACHABLE(); } return t; @@ -860,17 +865,18 @@ _PyTime_GetPerfCounter(void) int _PyTime_Init(void) { - /* check that the 3 most important clocks are working properly - to not have to check for exceptions at runtime. If a clock works once, - it cannot fail in next calls. */ + /* check that time.time(), time.monotonic() and time.perf_counter() clocks + are working properly to not have to check for exceptions at runtime. If + a clock works once, it cannot fail in next calls. */ _PyTime_t t; + double d; if (_PyTime_GetSystemClockWithInfo(&t, NULL) < 0) { return -1; } if (_PyTime_GetMonotonicClockWithInfo(&t, NULL) < 0) { return -1; } - if (_PyTime_GetPerfCounterWithInfo(&t, NULL) < 0) { + if (_PyTime_GetPerfCounterDoubleWithInfo(&d, NULL) < 0) { return -1; } return 0;