summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorInada Naoki <songofacandy@gmail.com>2019-04-11 10:11:46 (GMT)
committerGitHub <noreply@github.com>2019-04-11 10:11:46 (GMT)
commit536a35b3f14888999f1ffa5be7239d0c26b73d7a (patch)
tree108c9ac0b94843733069be5c2fe6c48524708dcc
parentb3c92c6ae923ffb2b9ac5f80b28ecd689de48662 (diff)
downloadcpython-536a35b3f14888999f1ffa5be7239d0c26b73d7a.zip
cpython-536a35b3f14888999f1ffa5be7239d0c26b73d7a.tar.gz
cpython-536a35b3f14888999f1ffa5be7239d0c26b73d7a.tar.bz2
bpo-36575: lsprof: Use _PyTime_GetPerfCounter() (GH-8378)
-rw-r--r--Misc/NEWS.d/next/Library/2019-04-09-22-40-52.bpo-36575.Vg_p92.rst4
-rw-r--r--Modules/_lsprof.c122
2 files changed, 40 insertions, 86 deletions
diff --git a/Misc/NEWS.d/next/Library/2019-04-09-22-40-52.bpo-36575.Vg_p92.rst b/Misc/NEWS.d/next/Library/2019-04-09-22-40-52.bpo-36575.Vg_p92.rst
new file mode 100644
index 0000000..3e305f1
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-04-09-22-40-52.bpo-36575.Vg_p92.rst
@@ -0,0 +1,4 @@
+The ``_lsprof`` module now uses internal timer same to ``time.perf_counter()`` by default.
+``gettimeofday(2)`` was used on Unix. New timer has better resolution on most Unix
+platforms and timings are no longer impacted by system clock updates since ``perf_counter()``
+is monotonic. Patch by Inada Naoki.
diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c
index 4508f5e..c4e0f52 100644
--- a/Modules/_lsprof.c
+++ b/Modules/_lsprof.c
@@ -2,62 +2,6 @@
#include "frameobject.h"
#include "rotatingtree.h"
-/*** Selection of a high-precision timer ***/
-
-#ifdef MS_WINDOWS
-
-#include <windows.h>
-
-static long long
-hpTimer(void)
-{
- LARGE_INTEGER li;
- QueryPerformanceCounter(&li);
- return li.QuadPart;
-}
-
-static double
-hpTimerUnit(void)
-{
- LARGE_INTEGER li;
- if (QueryPerformanceFrequency(&li))
- return 1.0 / li.QuadPart;
- else
- return 0.000001; /* unlikely */
-}
-
-#else /* !MS_WINDOWS */
-
-#ifndef HAVE_GETTIMEOFDAY
-#error "This module requires gettimeofday() on non-Windows platforms!"
-#endif
-
-#include <sys/resource.h>
-#include <sys/times.h>
-
-static long long
-hpTimer(void)
-{
- struct timeval tv;
- long long ret;
-#ifdef GETTIMEOFDAY_NO_TZ
- gettimeofday(&tv);
-#else
- gettimeofday(&tv, (struct timezone *)NULL);
-#endif
- ret = tv.tv_sec;
- ret = ret * 1000000 + tv.tv_usec;
- return ret;
-}
-
-static double
-hpTimerUnit(void)
-{
- return 0.000001;
-}
-
-#endif /* MS_WINDOWS */
-
/************************************************************/
/* Written by Brett Rosen and Ted Czotter */
@@ -66,8 +10,8 @@ struct _ProfilerEntry;
/* represents a function called from another function */
typedef struct _ProfilerSubEntry {
rotating_node_t header;
- long long tt;
- long long it;
+ _PyTime_t tt;
+ _PyTime_t it;
long callcount;
long recursivecallcount;
long recursionLevel;
@@ -77,8 +21,8 @@ typedef struct _ProfilerSubEntry {
typedef struct _ProfilerEntry {
rotating_node_t header;
PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */
- long long tt; /* total time in this entry */
- long long it; /* inline time in this entry (not in subcalls) */
+ _PyTime_t tt; /* total time in this entry */
+ _PyTime_t it; /* inline time in this entry (not in subcalls) */
long callcount; /* how many times this was called */
long recursivecallcount; /* how many times called recursively */
long recursionLevel;
@@ -86,8 +30,8 @@ typedef struct _ProfilerEntry {
} ProfilerEntry;
typedef struct _ProfilerContext {
- long long t0;
- long long subt;
+ _PyTime_t t0;
+ _PyTime_t subt;
struct _ProfilerContext *previous;
ProfilerEntry *ctxEntry;
} ProfilerContext;
@@ -114,41 +58,46 @@ static PyTypeObject PyProfiler_Type;
/*** External Timers ***/
-#define DOUBLE_TIMER_PRECISION 4294967296.0
-static PyObject *empty_tuple;
-
-static long long CallExternalTimer(ProfilerObject *pObj)
+static _PyTime_t CallExternalTimer(ProfilerObject *pObj)
{
- long long result;
- PyObject *o = PyObject_Call(pObj->externalTimer, empty_tuple, NULL);
+ PyObject *o = _PyObject_CallNoArg(pObj->externalTimer);
if (o == NULL) {
PyErr_WriteUnraisable(pObj->externalTimer);
return 0;
}
+
+ _PyTime_t result;
+ int err;
if (pObj->externalTimerUnit > 0.0) {
/* interpret the result as an integer that will be scaled
in profiler_getstats() */
- result = PyLong_AsLongLong(o);
+ err = _PyTime_FromNanosecondsObject(&result, o);
}
else {
/* interpret the result as a double measured in seconds.
- As the profiler works with long long internally
+ As the profiler works with _PyTime_t internally
we convert it to a large integer */
- double val = PyFloat_AsDouble(o);
- /* error handling delayed to the code below */
- result = (long long) (val * DOUBLE_TIMER_PRECISION);
+ err = _PyTime_FromSecondsObject(&result, o, _PyTime_ROUND_FLOOR);
}
Py_DECREF(o);
- if (PyErr_Occurred()) {
+ if (err < 0) {
PyErr_WriteUnraisable(pObj->externalTimer);
return 0;
}
return result;
}
-#define CALL_TIMER(pObj) ((pObj)->externalTimer ? \
- CallExternalTimer(pObj) : \
- hpTimer())
+static inline _PyTime_t
+call_timer(ProfilerObject *pObj)
+{
+ if (pObj->externalTimer != NULL) {
+ return CallExternalTimer(pObj);
+ }
+ else {
+ return _PyTime_GetPerfCounter();
+ }
+}
+
/*** ProfilerObject ***/
@@ -332,14 +281,14 @@ initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
if (subentry)
++subentry->recursionLevel;
}
- self->t0 = CALL_TIMER(pObj);
+ self->t0 = call_timer(pObj);
}
static void
Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
{
- long long tt = CALL_TIMER(pObj) - self->t0;
- long long it = tt - self->subt;
+ _PyTime_t tt = call_timer(pObj) - self->t0;
+ _PyTime_t it = tt - self->subt;
if (self->previous)
self->previous->subt += tt;
pObj->currentProfilerContext = self->previous;
@@ -631,12 +580,14 @@ profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
statscollector_t collect;
if (pending_exception(pObj))
return NULL;
- if (!pObj->externalTimer)
- collect.factor = hpTimerUnit();
- else if (pObj->externalTimerUnit > 0.0)
+ if (!pObj->externalTimer || pObj->externalTimerUnit == 0.0) {
+ _PyTime_t onesec = _PyTime_FromSeconds(1);
+ collect.factor = (double)1 / onesec;
+ }
+ else {
collect.factor = pObj->externalTimerUnit;
- else
- collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
+ }
+
collect.list = PyList_New(0);
if (collect.list == NULL)
return NULL;
@@ -882,7 +833,6 @@ PyInit__lsprof(void)
(PyObject*) &StatsEntryType);
PyModule_AddObject(module, "profiler_subentry",
(PyObject*) &StatsSubEntryType);
- empty_tuple = PyTuple_New(0);
initialized = 1;
return module;
}