[Python-checkins] bpo-31415: Add _PyTime_GetPerfCounter() and use it for -X importtime (#3936)

Victor Stinner webhook-mailer at python.org
Tue Oct 10 05:51:56 EDT 2017


https://github.com/python/cpython/commit/a997c7b434631f51e00191acea2ba6097691e859
commit: a997c7b434631f51e00191acea2ba6097691e859
branch: master
author: Victor Stinner <victor.stinner at gmail.com>
committer: GitHub <noreply at github.com>
date: 2017年10月10日T02:51:50-07:00
summary:
bpo-31415: Add _PyTime_GetPerfCounter() and use it for -X importtime (#3936)
* Add _PyTime_GetPerfCounter()
* Use _PyTime_GetPerfCounter() for -X importtime
files:
M Include/pytime.h
M Modules/timemodule.c
M Python/import.c
M Python/pytime.c
diff --git a/Include/pytime.h b/Include/pytime.h
index 87ac7fcbbad..95d482fee3b 100644
--- a/Include/pytime.h
+++ b/Include/pytime.h
@@ -192,6 +192,22 @@ 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. */
+PyAPI_FUNC(_PyTime_t) _PyTime_GetPerfCounter(void);
+
+/* Similar to _PyTime_GetPerfCounter(),
+ but get also clock info if info is non-NULL. */
+PyAPI_FUNC(int) _PyTime_GetPerfCounterWithInfo(
+ _PyTime_t *t,
+ _Py_clock_info_t *info);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
index 34e057d9d74..31050fb554b 100644
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -60,6 +60,13 @@ Fractions of a second may be present if the system clock provides them.");
 #endif
 #endif
 
+static PyObject*
+_PyFloat_FromPyTime(_PyTime_t t)
+{
+ double d = _PyTime_AsSecondsDouble(t);
+ return PyFloat_FromDouble(d);
+}
+
 static PyObject *
 floatclock(_Py_clock_info_t *info)
 {
@@ -81,47 +88,19 @@ floatclock(_Py_clock_info_t *info)
 }
 #endif /* HAVE_CLOCK */
 
-#ifdef MS_WINDOWS
-#define WIN32_PERF_COUNTER
-/* Win32 has better clock replacement; we have our own version, due to Mark
- Hammond and Tim Peters */
-static PyObject*
-win_perf_counter(_Py_clock_info_t *info)
-{
- static LONGLONG cpu_frequency = 0;
- static LONGLONG ctrStart;
- LARGE_INTEGER now;
- double diff;
-
- if (cpu_frequency == 0) {
- LARGE_INTEGER freq;
- QueryPerformanceCounter(&now);
- ctrStart = now.QuadPart;
- if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) {
- PyErr_SetFromWindowsErr(0);
- return NULL;
- }
- cpu_frequency = freq.QuadPart;
- }
- QueryPerformanceCounter(&now);
- diff = (double)(now.QuadPart - ctrStart);
- if (info) {
- info->implementation = "QueryPerformanceCounter()";
- info->resolution = 1.0 / (double)cpu_frequency;
- info->monotonic = 1;
- info->adjustable = 0;
- }
- return PyFloat_FromDouble(diff / (double)cpu_frequency);
-}
-#endif /* MS_WINDOWS */
-
-#if defined(WIN32_PERF_COUNTER) || defined(HAVE_CLOCK)
+#if defined(MS_WINDOWS) || defined(HAVE_CLOCK)
 #define PYCLOCK
 static PyObject*
 pyclock(_Py_clock_info_t *info)
 {
-#ifdef WIN32_PERF_COUNTER
- return win_perf_counter(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);
 #else
 return floatclock(info);
 #endif
@@ -939,13 +918,11 @@ static PyObject *
 pymonotonic(_Py_clock_info_t *info)
 {
 _PyTime_t t;
- double d;
 if (_PyTime_GetMonotonicClockWithInfo(&t, info) < 0) {
 assert(info != NULL);
 return NULL;
 }
- d = _PyTime_AsSecondsDouble(t);
- return PyFloat_FromDouble(d);
+ return _PyFloat_FromPyTime(t);
 }
 
 static PyObject *
@@ -962,11 +939,11 @@ Monotonic clock, cannot go backward.");
 static PyObject*
 perf_counter(_Py_clock_info_t *info)
 {
-#ifdef WIN32_PERF_COUNTER
- return win_perf_counter(info);
-#else
- return pymonotonic(info);
-#endif
+ _PyTime_t t;
+ if (_PyTime_GetPerfCounterWithInfo(&t, info) < 0) {
+ return NULL;
+ }
+ return _PyFloat_FromPyTime(t);
 }
 
 static PyObject *
@@ -1448,13 +1425,11 @@ static PyObject*
 floattime(_Py_clock_info_t *info)
 {
 _PyTime_t t;
- double d;
 if (_PyTime_GetSystemClockWithInfo(&t, info) < 0) {
 assert(info != NULL);
 return NULL;
 }
- d = _PyTime_AsSecondsDouble(t);
- return PyFloat_FromDouble(d);
+ return _PyFloat_FromPyTime(t);
 }
 
 
diff --git a/Python/import.c b/Python/import.c
index 7554bf86272..d396b4de793 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -1695,7 +1695,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
 
 if (ximporttime) {
 import_level++;
- t1 = _PyTime_GetMonotonicClock();
+ t1 = _PyTime_GetPerfCounter();
 accumulated = 0;
 }
 
@@ -1711,7 +1711,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
 mod != NULL);
 
 if (ximporttime) {
- _PyTime_t cum = _PyTime_GetMonotonicClock() - t1;
+ _PyTime_t cum = _PyTime_GetPerfCounter() - t1;
 
 import_level--;
 fprintf(stderr, "import time: %9ld | %10ld | %*s%s\n",
diff --git a/Python/pytime.c b/Python/pytime.c
index 8f275d29839..bda6d8bb912 100644
--- a/Python/pytime.c
+++ b/Python/pytime.c
@@ -285,8 +285,8 @@ _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv, int raise)
 #endif
 
 static int
-_PyTime_FromFloatObject(_PyTime_t *t, double value, _PyTime_round_t round,
- long unit_to_ns)
+_PyTime_FromDouble(_PyTime_t *t, double value, _PyTime_round_t round,
+ long unit_to_ns)
 {
 /* volatile avoids optimization changing how numbers are rounded */
 volatile double d;
@@ -315,7 +315,7 @@ _PyTime_FromObject(_PyTime_t *t, PyObject *obj, _PyTime_round_t round,
 PyErr_SetString(PyExc_ValueError, "Invalid value NaN (not a number)");
 return -1;
 }
- return _PyTime_FromFloatObject(t, d, round, unit_to_ns);
+ return _PyTime_FromDouble(t, d, round, unit_to_ns);
 }
 else {
 long long sec;
@@ -779,19 +779,80 @@ _PyTime_GetMonotonicClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
 return pymonotonic(tp, info, 1);
 }
 
+
+#ifdef MS_WINDOWS
 int
-_PyTime_Init(void)
+_PyTime_GetWinPerfCounterWithInfo(_PyTime_t *t, _Py_clock_info_t *info)
+{
+ static LONGLONG cpu_frequency = 0;
+ static LONGLONG ctrStart;
+ LARGE_INTEGER now;
+ double diff;
+
+ if (cpu_frequency == 0) {
+ LARGE_INTEGER freq;
+ QueryPerformanceCounter(&now);
+ ctrStart = now.QuadPart;
+ if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) {
+ PyErr_SetFromWindowsErr(0);
+ return -1;
+ }
+ cpu_frequency = freq.QuadPart;
+ }
+ QueryPerformanceCounter(&now);
+ diff = (double)(now.QuadPart - ctrStart);
+ if (info) {
+ info->implementation = "QueryPerformanceCounter()";
+ info->resolution = 1.0 / (double)cpu_frequency;
+ info->monotonic = 1;
+ info->adjustable = 0;
+ }
+
+ diff = diff / (double)cpu_frequency;
+ return _PyTime_FromDouble(t, diff, _PyTime_ROUND_FLOOR, SEC_TO_NS);
+}
+#endif
+
+
+int
+_PyTime_GetPerfCounterWithInfo(_PyTime_t *t, _Py_clock_info_t *info)
+{
+#ifdef MS_WINDOWS
+ return _PyTime_GetWinPerfCounterWithInfo(t, info);
+#else
+ return _PyTime_GetMonotonicClockWithInfo(t, info);
+#endif
+}
+
+
+_PyTime_t
+_PyTime_GetPerfCounter(void)
 {
 _PyTime_t t;
+ if (_PyTime_GetPerfCounterWithInfo(&t, NULL) < 0) {
+ /* should not happen, _PyTime_Init() checked the clock at startup */
+ Py_UNREACHABLE();
+ }
+ return t;
+}
 
- /* ensure that the system clock works */
- if (_PyTime_GetSystemClockWithInfo(&t, NULL) < 0)
- return -1;
 
- /* ensure that the operating system provides a monotonic clock */
- if (_PyTime_GetMonotonicClockWithInfo(&t, NULL) < 0)
+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. */
+ _PyTime_t t;
+ if (_PyTime_GetSystemClockWithInfo(&t, NULL) < 0) {
 return -1;
-
+ }
+ if (_PyTime_GetMonotonicClockWithInfo(&t, NULL) < 0) {
+ return -1;
+ }
+ if (_PyTime_GetPerfCounterWithInfo(&t, NULL) < 0) {
+ return -1;
+ }
 return 0;
 }
 


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /