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)
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
module time
|
||||
[clinic start generated code]*/
|
||||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a668a08771581f36]*/
|
||||
|
||||
|
||||
#if defined(HAVE_TIMES) || defined(HAVE_CLOCK)
|
||||
static int
|
||||
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"
|
||||
#endif
|
||||
|
||||
static PyObject *
|
||||
time_clock_gettime(PyObject *self, PyObject *args)
|
||||
static int
|
||||
time_clockid_converter(PyObject *obj, clockid_t *p)
|
||||
{
|
||||
int ret;
|
||||
struct timespec tp;
|
||||
|
||||
#if defined(_AIX) && (SIZEOF_LONG == 8)
|
||||
long clk_id;
|
||||
if (!PyArg_ParseTuple(args, "l:clock_gettime", &clk_id)) {
|
||||
long clk_id = PyLong_AsLong(obj);
|
||||
#else
|
||||
int clk_id;
|
||||
if (!PyArg_ParseTuple(args, "i:clock_gettime", &clk_id)) {
|
||||
int clk_id = PyLong_AsInt(obj);
|
||||
#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) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
|
@ -251,38 +286,32 @@ time_clock_gettime(PyObject *self, PyObject *args)
|
|||
return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(clock_gettime_doc,
|
||||
"clock_gettime(clk_id) -> float\n\
|
||||
\n\
|
||||
Return the time of the specified clock clk_id.");
|
||||
/*[clinic input]
|
||||
time.clock_gettime_ns
|
||||
|
||||
clk_id: clockid_t
|
||||
/
|
||||
|
||||
Return the time of the specified clock clk_id as nanoseconds (int).
|
||||
[clinic start generated code]*/
|
||||
|
||||
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;
|
||||
_PyTime_t t;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:clock_gettime", &clk_id)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = clock_gettime((clockid_t)clk_id, &ts);
|
||||
int ret = clock_gettime(clk_id, &ts);
|
||||
if (ret != 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_PyTime_t t;
|
||||
if (_PyTime_FromTimespec(&t, &ts) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
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 */
|
||||
|
||||
#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[] = {
|
||||
{"time", time_time, METH_NOARGS, time_doc},
|
||||
{"time_ns", time_time_ns, METH_NOARGS, time_ns_doc},
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
{"clock_gettime", time_clock_gettime, METH_VARARGS, clock_gettime_doc},
|
||||
{"clock_gettime_ns",time_clock_gettime_ns, METH_VARARGS, clock_gettime_ns_doc},
|
||||
TIME_CLOCK_GETTIME_METHODDEF
|
||||
TIME_CLOCK_GETTIME_NS_METHODDEF
|
||||
#endif
|
||||
#ifdef HAVE_CLOCK_SETTIME
|
||||
{"clock_settime", time_clock_settime, METH_VARARGS, clock_settime_doc},
|
||||
|
|
Loading…
Reference in New Issue