mirror of https://github.com/python/cpython
gh-111482: Use Argument Clinic for clock_gettime() (#111641)
Use Argument Clinic for time.clock_gettime() and time.clock_gettime_ns() functions. Benchmark on time.clock_gettime_ns(): import time import pyperf runner = pyperf.Runner() runner.timeit( 'clock_gettime_ns(CLOCK_MONOTONIC_COARSE)', setup='import time; clock_gettime_ns=time.clock_gettime_ns; CLOCK_MONOTONIC_COARSE=6', stmt='clock_gettime_ns(CLOCK_MONOTONIC_COARSE)') Result on Linux with CPU isolation: Mean +- std dev: [ref] 134 ns +- 1 ns -> [change] 55.7 ns +- 1.4 ns: 2.41x faster
This commit is contained in:
parent
6a0d7b43df
commit
4fe22c7377
|
@ -0,0 +1,3 @@
|
||||||
|
:mod:`time`: Make :func:`time.clock_gettime()` and
|
||||||
|
:func:`time.clock_gettime_ns()` functions up to 2x faster by faster calling
|
||||||
|
convention. Patch by Victor Stinner.
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*[clinic input]
|
||||||
|
preserve
|
||||||
|
[clinic start generated code]*/
|
||||||
|
|
||||||
|
#if defined(HAVE_CLOCK_GETTIME)
|
||||||
|
|
||||||
|
PyDoc_STRVAR(time_clock_gettime__doc__,
|
||||||
|
"clock_gettime($module, clk_id, /)\n"
|
||||||
|
"--\n"
|
||||||
|
"\n"
|
||||||
|
"Return the time of the specified clock clk_id as a float.");
|
||||||
|
|
||||||
|
#define TIME_CLOCK_GETTIME_METHODDEF \
|
||||||
|
{"clock_gettime", (PyCFunction)time_clock_gettime, METH_O, time_clock_gettime__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
time_clock_gettime_impl(PyObject *module, clockid_t clk_id);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
time_clock_gettime(PyObject *module, PyObject *arg)
|
||||||
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
clockid_t clk_id;
|
||||||
|
|
||||||
|
if (!time_clockid_converter(arg, &clk_id)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
return_value = time_clock_gettime_impl(module, clk_id);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* defined(HAVE_CLOCK_GETTIME) */
|
||||||
|
|
||||||
|
#if defined(HAVE_CLOCK_GETTIME)
|
||||||
|
|
||||||
|
PyDoc_STRVAR(time_clock_gettime_ns__doc__,
|
||||||
|
"clock_gettime_ns($module, clk_id, /)\n"
|
||||||
|
"--\n"
|
||||||
|
"\n"
|
||||||
|
"Return the time of the specified clock clk_id as nanoseconds (int).");
|
||||||
|
|
||||||
|
#define TIME_CLOCK_GETTIME_NS_METHODDEF \
|
||||||
|
{"clock_gettime_ns", (PyCFunction)time_clock_gettime_ns, METH_O, time_clock_gettime_ns__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
time_clock_gettime_ns_impl(PyObject *module, clockid_t clk_id);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
time_clock_gettime_ns(PyObject *module, PyObject *arg)
|
||||||
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
clockid_t clk_id;
|
||||||
|
|
||||||
|
if (!time_clockid_converter(arg, &clk_id)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
return_value = time_clock_gettime_ns_impl(module, clk_id);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* defined(HAVE_CLOCK_GETTIME) */
|
||||||
|
|
||||||
|
#ifndef TIME_CLOCK_GETTIME_METHODDEF
|
||||||
|
#define TIME_CLOCK_GETTIME_METHODDEF
|
||||||
|
#endif /* !defined(TIME_CLOCK_GETTIME_METHODDEF) */
|
||||||
|
|
||||||
|
#ifndef TIME_CLOCK_GETTIME_NS_METHODDEF
|
||||||
|
#define TIME_CLOCK_GETTIME_NS_METHODDEF
|
||||||
|
#endif /* !defined(TIME_CLOCK_GETTIME_NS_METHODDEF) */
|
||||||
|
/*[clinic end generated code: output=b589a2132aa9df47 input=a9049054013a1b77]*/
|
|
@ -63,6 +63,12 @@
|
||||||
#define SEC_TO_NS (1000 * 1000 * 1000)
|
#define SEC_TO_NS (1000 * 1000 * 1000)
|
||||||
|
|
||||||
|
|
||||||
|
/*[clinic input]
|
||||||
|
module time
|
||||||
|
[clinic start generated code]*/
|
||||||
|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a668a08771581f36]*/
|
||||||
|
|
||||||
|
|
||||||
#if defined(HAVE_TIMES) || defined(HAVE_CLOCK)
|
#if defined(HAVE_TIMES) || defined(HAVE_CLOCK)
|
||||||
static int
|
static int
|
||||||
check_ticks_per_second(long tps, const char *context)
|
check_ticks_per_second(long tps, const char *context)
|
||||||
|
@ -227,23 +233,52 @@ _PyTime_GetClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
|
||||||
#pragma clang diagnostic ignored "-Wunguarded-availability"
|
#pragma clang diagnostic ignored "-Wunguarded-availability"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static PyObject *
|
static int
|
||||||
time_clock_gettime(PyObject *self, PyObject *args)
|
time_clockid_converter(PyObject *obj, clockid_t *p)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
struct timespec tp;
|
|
||||||
|
|
||||||
#if defined(_AIX) && (SIZEOF_LONG == 8)
|
#if defined(_AIX) && (SIZEOF_LONG == 8)
|
||||||
long clk_id;
|
long clk_id = PyLong_AsLong(obj);
|
||||||
if (!PyArg_ParseTuple(args, "l:clock_gettime", &clk_id)) {
|
|
||||||
#else
|
#else
|
||||||
int clk_id;
|
int clk_id = PyLong_AsInt(obj);
|
||||||
if (!PyArg_ParseTuple(args, "i:clock_gettime", &clk_id)) {
|
|
||||||
#endif
|
#endif
|
||||||
return NULL;
|
if (clk_id == -1 && PyErr_Occurred()) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"clk_id should be integer, not %s",
|
||||||
|
_PyType_Name(Py_TYPE(obj)));
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clock_gettime((clockid_t)clk_id, &tp);
|
// Make sure that we picked the right type (check sizes type)
|
||||||
|
Py_BUILD_ASSERT(sizeof(clk_id) == sizeof(*p));
|
||||||
|
*p = (clockid_t)clk_id;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*[python input]
|
||||||
|
|
||||||
|
class clockid_t_converter(CConverter):
|
||||||
|
type = "clockid_t"
|
||||||
|
converter = 'time_clockid_converter'
|
||||||
|
|
||||||
|
[python start generated code]*/
|
||||||
|
/*[python end generated code: output=da39a3ee5e6b4b0d input=53867111501f46c8]*/
|
||||||
|
|
||||||
|
|
||||||
|
/*[clinic input]
|
||||||
|
time.clock_gettime
|
||||||
|
|
||||||
|
clk_id: clockid_t
|
||||||
|
/
|
||||||
|
|
||||||
|
Return the time of the specified clock clk_id as a float.
|
||||||
|
[clinic start generated code]*/
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
time_clock_gettime_impl(PyObject *module, clockid_t clk_id)
|
||||||
|
/*[clinic end generated code: output=832b9ebc03328020 input=7e89fcc42ca15e5d]*/
|
||||||
|
{
|
||||||
|
struct timespec tp;
|
||||||
|
int ret = clock_gettime(clk_id, &tp);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -251,38 +286,32 @@ time_clock_gettime(PyObject *self, PyObject *args)
|
||||||
return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
|
return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(clock_gettime_doc,
|
/*[clinic input]
|
||||||
"clock_gettime(clk_id) -> float\n\
|
time.clock_gettime_ns
|
||||||
\n\
|
|
||||||
Return the time of the specified clock clk_id.");
|
clk_id: clockid_t
|
||||||
|
/
|
||||||
|
|
||||||
|
Return the time of the specified clock clk_id as nanoseconds (int).
|
||||||
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
time_clock_gettime_ns(PyObject *self, PyObject *args)
|
time_clock_gettime_ns_impl(PyObject *module, clockid_t clk_id)
|
||||||
|
/*[clinic end generated code: output=4a045c3a36e60044 input=aabc248db8c8e3e5]*/
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
int clk_id;
|
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
_PyTime_t t;
|
int ret = clock_gettime(clk_id, &ts);
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "i:clock_gettime", &clk_id)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = clock_gettime((clockid_t)clk_id, &ts);
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_PyTime_t t;
|
||||||
if (_PyTime_FromTimespec(&t, &ts) < 0) {
|
if (_PyTime_FromTimespec(&t, &ts) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return _PyTime_AsNanosecondsObject(t);
|
return _PyTime_AsNanosecondsObject(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(clock_gettime_ns_doc,
|
|
||||||
"clock_gettime_ns(clk_id) -> int\n\
|
|
||||||
\n\
|
|
||||||
Return the time of the specified clock clk_id as nanoseconds.");
|
|
||||||
#endif /* HAVE_CLOCK_GETTIME */
|
#endif /* HAVE_CLOCK_GETTIME */
|
||||||
|
|
||||||
#ifdef HAVE_CLOCK_SETTIME
|
#ifdef HAVE_CLOCK_SETTIME
|
||||||
|
@ -1857,12 +1886,16 @@ init_timezone(PyObject *m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Include Argument Clinic code after defining converters such as
|
||||||
|
// time_clockid_converter().
|
||||||
|
#include "clinic/timemodule.c.h"
|
||||||
|
|
||||||
static PyMethodDef time_methods[] = {
|
static PyMethodDef time_methods[] = {
|
||||||
{"time", time_time, METH_NOARGS, time_doc},
|
{"time", time_time, METH_NOARGS, time_doc},
|
||||||
{"time_ns", time_time_ns, METH_NOARGS, time_ns_doc},
|
{"time_ns", time_time_ns, METH_NOARGS, time_ns_doc},
|
||||||
#ifdef HAVE_CLOCK_GETTIME
|
#ifdef HAVE_CLOCK_GETTIME
|
||||||
{"clock_gettime", time_clock_gettime, METH_VARARGS, clock_gettime_doc},
|
TIME_CLOCK_GETTIME_METHODDEF
|
||||||
{"clock_gettime_ns",time_clock_gettime_ns, METH_VARARGS, clock_gettime_ns_doc},
|
TIME_CLOCK_GETTIME_NS_METHODDEF
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_CLOCK_SETTIME
|
#ifdef HAVE_CLOCK_SETTIME
|
||||||
{"clock_settime", time_clock_settime, METH_VARARGS, clock_settime_doc},
|
{"clock_settime", time_clock_settime, METH_VARARGS, clock_settime_doc},
|
||||||
|
|
Loading…
Reference in New Issue