mirror of
https://github.com/python/cpython
synced 2026-09-29 12:10:30 +03:00
bpo-31784: Implement PEP 564: add time.time_ns() (#3989)
Add new time functions: * time.clock_gettime_ns() * time.clock_settime_ns() * time.monotonic_ns() * time.perf_counter_ns() * time.process_time_ns() * time.time_ns() Add new _PyTime functions: * _PyTime_FromTimespec() * _PyTime_FromNanosecondsObject() * _PyTime_FromTimeval() Other changes: * Add also os.times() tests to test_os. * pytime_fromtimeval() and pytime_fromtimeval() now return _PyTime_MAX or _PyTime_MIN on overflow, rather than undefined behaviour * _PyTime_FromNanoseconds() parameter type changes from long long to _PyTime_t
This commit is contained in:
parent
e314853d57
commit
c29b585fd4
9 changed files with 593 additions and 175 deletions
|
|
@ -3946,13 +3946,16 @@ test_pytime_fromsecondsobject(PyObject *self, PyObject *args)
|
|||
static PyObject *
|
||||
test_pytime_assecondsdouble(PyObject *self, PyObject *args)
|
||||
{
|
||||
long long ns;
|
||||
PyObject *obj;
|
||||
_PyTime_t ts;
|
||||
double d;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "L", &ns))
|
||||
if (!PyArg_ParseTuple(args, "O", &obj)) {
|
||||
return NULL;
|
||||
ts = _PyTime_FromNanoseconds(ns);
|
||||
}
|
||||
if (_PyTime_FromNanosecondsObject(&ts, obj) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
d = _PyTime_AsSecondsDouble(ts);
|
||||
return PyFloat_FromDouble(d);
|
||||
}
|
||||
|
|
@ -3960,23 +3963,28 @@ test_pytime_assecondsdouble(PyObject *self, PyObject *args)
|
|||
static PyObject *
|
||||
test_PyTime_AsTimeval(PyObject *self, PyObject *args)
|
||||
{
|
||||
long long ns;
|
||||
PyObject *obj;
|
||||
int round;
|
||||
_PyTime_t t;
|
||||
struct timeval tv;
|
||||
PyObject *seconds;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "Li", &ns, &round))
|
||||
if (!PyArg_ParseTuple(args, "Oi", &obj, &round))
|
||||
return NULL;
|
||||
if (check_time_rounding(round) < 0)
|
||||
if (check_time_rounding(round) < 0) {
|
||||
return NULL;
|
||||
t = _PyTime_FromNanoseconds(ns);
|
||||
if (_PyTime_AsTimeval(t, &tv, round) < 0)
|
||||
}
|
||||
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (_PyTime_AsTimeval(t, &tv, round) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
seconds = PyLong_FromLongLong(tv.tv_sec);
|
||||
if (seconds == NULL)
|
||||
if (seconds == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return Py_BuildValue("Nl", seconds, tv.tv_usec);
|
||||
}
|
||||
|
||||
|
|
@ -3984,15 +3992,19 @@ test_PyTime_AsTimeval(PyObject *self, PyObject *args)
|
|||
static PyObject *
|
||||
test_PyTime_AsTimespec(PyObject *self, PyObject *args)
|
||||
{
|
||||
long long ns;
|
||||
PyObject *obj;
|
||||
_PyTime_t t;
|
||||
struct timespec ts;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "L", &ns))
|
||||
if (!PyArg_ParseTuple(args, "O", &obj)) {
|
||||
return NULL;
|
||||
t = _PyTime_FromNanoseconds(ns);
|
||||
if (_PyTime_AsTimespec(t, &ts) == -1)
|
||||
}
|
||||
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (_PyTime_AsTimespec(t, &ts) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
return Py_BuildValue("Nl", _PyLong_FromTime_t(ts.tv_sec), ts.tv_nsec);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -4000,15 +4012,19 @@ test_PyTime_AsTimespec(PyObject *self, PyObject *args)
|
|||
static PyObject *
|
||||
test_PyTime_AsMilliseconds(PyObject *self, PyObject *args)
|
||||
{
|
||||
long long ns;
|
||||
PyObject *obj;
|
||||
int round;
|
||||
_PyTime_t t, ms;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "Li", &ns, &round))
|
||||
if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) {
|
||||
return NULL;
|
||||
if (check_time_rounding(round) < 0)
|
||||
}
|
||||
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
|
||||
return NULL;
|
||||
t = _PyTime_FromNanoseconds(ns);
|
||||
}
|
||||
if (check_time_rounding(round) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
ms = _PyTime_AsMilliseconds(t, round);
|
||||
/* This conversion rely on the fact that _PyTime_t is a number of
|
||||
nanoseconds */
|
||||
|
|
@ -4018,15 +4034,18 @@ test_PyTime_AsMilliseconds(PyObject *self, PyObject *args)
|
|||
static PyObject *
|
||||
test_PyTime_AsMicroseconds(PyObject *self, PyObject *args)
|
||||
{
|
||||
long long ns;
|
||||
PyObject *obj;
|
||||
int round;
|
||||
_PyTime_t t, ms;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "Li", &ns, &round))
|
||||
if (!PyArg_ParseTuple(args, "Oi", &obj, &round))
|
||||
return NULL;
|
||||
if (check_time_rounding(round) < 0)
|
||||
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
|
||||
return NULL;
|
||||
t = _PyTime_FromNanoseconds(ns);
|
||||
}
|
||||
if (check_time_rounding(round) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
ms = _PyTime_AsMicroseconds(t, round);
|
||||
/* This conversion rely on the fact that _PyTime_t is a number of
|
||||
nanoseconds */
|
||||
|
|
|
|||
|
|
@ -34,31 +34,11 @@
|
|||
#endif /* MS_WINDOWS */
|
||||
#endif /* !__WATCOMC__ || __QNX__ */
|
||||
|
||||
#define SEC_TO_NS (1000 * 1000 * 1000)
|
||||
|
||||
/* Forward declarations */
|
||||
static int pysleep(_PyTime_t);
|
||||
static PyObject* floattime(_Py_clock_info_t *info);
|
||||
|
||||
static PyObject *
|
||||
time_time(PyObject *self, PyObject *unused)
|
||||
{
|
||||
return floattime(NULL);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(time_doc,
|
||||
"time() -> floating point number\n\
|
||||
\n\
|
||||
Return the current time in seconds since the Epoch.\n\
|
||||
Fractions of a second may be present if the system clock provides them.");
|
||||
|
||||
#if defined(HAVE_CLOCK)
|
||||
|
||||
#ifndef CLOCKS_PER_SEC
|
||||
#ifdef CLK_TCK
|
||||
#define CLOCKS_PER_SEC CLK_TCK
|
||||
#else
|
||||
#define CLOCKS_PER_SEC 1000000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static PyObject*
|
||||
_PyFloat_FromPyTime(_PyTime_t t)
|
||||
|
|
@ -67,24 +47,77 @@ _PyFloat_FromPyTime(_PyTime_t t)
|
|||
return PyFloat_FromDouble(d);
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
floatclock(_Py_clock_info_t *info)
|
||||
time_time(PyObject *self, PyObject *unused)
|
||||
{
|
||||
clock_t value;
|
||||
value = clock();
|
||||
if (value == (clock_t)-1) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"the processor time used is not available "
|
||||
"or its value cannot be represented");
|
||||
return NULL;
|
||||
_PyTime_t t = _PyTime_GetSystemClock();
|
||||
return _PyFloat_FromPyTime(t);
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(time_doc,
|
||||
"time() -> floating point number\n\
|
||||
\n\
|
||||
Return the current time in seconds since the Epoch.\n\
|
||||
Fractions of a second may be present if the system clock provides them.");
|
||||
|
||||
static PyObject *
|
||||
time_time_ns(PyObject *self, PyObject *unused)
|
||||
{
|
||||
_PyTime_t t = _PyTime_GetSystemClock();
|
||||
return _PyTime_AsNanosecondsObject(t);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(time_ns_doc,
|
||||
"time_ns() -> int\n\
|
||||
\n\
|
||||
Return the current time in nanoseconds since the Epoch.");
|
||||
|
||||
#if defined(HAVE_CLOCK)
|
||||
|
||||
#ifndef CLOCKS_PER_SEC
|
||||
# ifdef CLK_TCK
|
||||
# define CLOCKS_PER_SEC CLK_TCK
|
||||
# else
|
||||
# define CLOCKS_PER_SEC 1000000
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static int
|
||||
_PyTime_GetClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
|
||||
{
|
||||
static int initialized = 0;
|
||||
clock_t ticks;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = 1;
|
||||
|
||||
/* must sure that _PyTime_MulDiv(ticks, SEC_TO_NS, CLOCKS_PER_SEC)
|
||||
above cannot overflow */
|
||||
if ((_PyTime_t)CLOCKS_PER_SEC > _PyTime_MAX / SEC_TO_NS) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"CLOCKS_PER_SEC is too large");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (info) {
|
||||
info->implementation = "clock()";
|
||||
info->resolution = 1.0 / (double)CLOCKS_PER_SEC;
|
||||
info->monotonic = 1;
|
||||
info->adjustable = 0;
|
||||
}
|
||||
return PyFloat_FromDouble((double)value / CLOCKS_PER_SEC);
|
||||
|
||||
ticks = clock();
|
||||
if (ticks == (clock_t)-1) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"the processor time used is not available "
|
||||
"or its value cannot be represented");
|
||||
return -1;
|
||||
}
|
||||
*tp = _PyTime_MulDiv(ticks, SEC_TO_NS, (_PyTime_t)CLOCKS_PER_SEC);
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_CLOCK */
|
||||
|
||||
|
|
@ -95,8 +128,7 @@ perf_counter(_Py_clock_info_t *info)
|
|||
if (_PyTime_GetPerfCounterWithInfo(&t, info) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
double d = _PyTime_AsSecondsDouble(t);
|
||||
return PyFloat_FromDouble(d);
|
||||
return _PyFloat_FromPyTime(t);
|
||||
}
|
||||
|
||||
#if defined(MS_WINDOWS) || defined(HAVE_CLOCK)
|
||||
|
|
@ -111,10 +143,15 @@ pyclock(_Py_clock_info_t *info)
|
|||
"instead", 1) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
return perf_counter(info);
|
||||
#else
|
||||
return floatclock(info);
|
||||
_PyTime_t t;
|
||||
if (_PyTime_GetClockWithInfo(&t, info) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return _PyFloat_FromPyTime(t);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -140,8 +177,9 @@ time_clock_gettime(PyObject *self, PyObject *args)
|
|||
int clk_id;
|
||||
struct timespec tp;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:clock_gettime", &clk_id))
|
||||
if (!PyArg_ParseTuple(args, "i:clock_gettime", &clk_id)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = clock_gettime((clockid_t)clk_id, &tp);
|
||||
if (ret != 0) {
|
||||
|
|
@ -152,9 +190,37 @@ time_clock_gettime(PyObject *self, PyObject *args)
|
|||
}
|
||||
|
||||
PyDoc_STRVAR(clock_gettime_doc,
|
||||
"clock_gettime(clk_id) -> floating point number\n\
|
||||
"clock_gettime(clk_id) -> float\n\
|
||||
\n\
|
||||
Return the time of the specified clock clk_id.");
|
||||
|
||||
static PyObject *
|
||||
time_clock_gettime_ns(PyObject *self, PyObject *args)
|
||||
{
|
||||
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);
|
||||
if (ret != 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
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
|
||||
|
|
@ -188,6 +254,39 @@ PyDoc_STRVAR(clock_settime_doc,
|
|||
"clock_settime(clk_id, time)\n\
|
||||
\n\
|
||||
Set the time of the specified clock clk_id.");
|
||||
|
||||
static PyObject *
|
||||
time_clock_settime_ns(PyObject *self, PyObject *args)
|
||||
{
|
||||
int clk_id;
|
||||
PyObject *obj;
|
||||
_PyTime_t t;
|
||||
struct timespec ts;
|
||||
int ret;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iO:clock_settime", &clk_id, &obj)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (_PyTime_AsTimespec(t, &ts) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = clock_settime((clockid_t)clk_id, &ts);
|
||||
if (ret != 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(clock_settime_ns_doc,
|
||||
"clock_settime_ns(clk_id, time)\n\
|
||||
\n\
|
||||
Set the time of the specified clock clk_id with nanoseconds.");
|
||||
#endif /* HAVE_CLOCK_SETTIME */
|
||||
|
||||
#ifdef HAVE_CLOCK_GETRES
|
||||
|
|
@ -926,21 +1025,11 @@ the local timezone used by methods such as localtime, but this behaviour\n\
|
|||
should not be relied on.");
|
||||
#endif /* HAVE_WORKING_TZSET */
|
||||
|
||||
static PyObject *
|
||||
pymonotonic(_Py_clock_info_t *info)
|
||||
{
|
||||
_PyTime_t t;
|
||||
if (_PyTime_GetMonotonicClockWithInfo(&t, info) < 0) {
|
||||
assert(info != NULL);
|
||||
return NULL;
|
||||
}
|
||||
return _PyFloat_FromPyTime(t);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
time_monotonic(PyObject *self, PyObject *unused)
|
||||
{
|
||||
return pymonotonic(NULL);
|
||||
_PyTime_t t = _PyTime_GetMonotonicClock();
|
||||
return _PyFloat_FromPyTime(t);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(monotonic_doc,
|
||||
|
|
@ -948,6 +1037,18 @@ PyDoc_STRVAR(monotonic_doc,
|
|||
\n\
|
||||
Monotonic clock, cannot go backward.");
|
||||
|
||||
static PyObject *
|
||||
time_monotonic_ns(PyObject *self, PyObject *unused)
|
||||
{
|
||||
_PyTime_t t = _PyTime_GetMonotonicClock();
|
||||
return _PyTime_AsNanosecondsObject(t);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(monotonic_ns_doc,
|
||||
"monotonic_ns() -> int\n\
|
||||
\n\
|
||||
Monotonic clock, cannot go backward, as nanoseconds.");
|
||||
|
||||
static PyObject *
|
||||
time_perf_counter(PyObject *self, PyObject *unused)
|
||||
{
|
||||
|
|
@ -959,47 +1060,61 @@ PyDoc_STRVAR(perf_counter_doc,
|
|||
\n\
|
||||
Performance counter for benchmarking.");
|
||||
|
||||
static PyObject*
|
||||
py_process_time(_Py_clock_info_t *info)
|
||||
static PyObject *
|
||||
time_perf_counter_ns(PyObject *self, PyObject *unused)
|
||||
{
|
||||
_PyTime_t t = _PyTime_GetPerfCounter();
|
||||
return _PyTime_AsNanosecondsObject(t);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(perf_counter_ns_doc,
|
||||
"perf_counter_ns() -> int\n\
|
||||
\n\
|
||||
Performance counter for benchmarking as nanoseconds.");
|
||||
|
||||
static int
|
||||
_PyTime_GetProcessTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
|
||||
{
|
||||
#if defined(MS_WINDOWS)
|
||||
HANDLE process;
|
||||
FILETIME creation_time, exit_time, kernel_time, user_time;
|
||||
ULARGE_INTEGER large;
|
||||
double total;
|
||||
_PyTime_t ktime, utime, t;
|
||||
BOOL ok;
|
||||
|
||||
process = GetCurrentProcess();
|
||||
ok = GetProcessTimes(process, &creation_time, &exit_time, &kernel_time, &user_time);
|
||||
if (!ok)
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
ok = GetProcessTimes(process, &creation_time, &exit_time,
|
||||
&kernel_time, &user_time);
|
||||
if (!ok) {
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
large.u.LowPart = kernel_time.dwLowDateTime;
|
||||
large.u.HighPart = kernel_time.dwHighDateTime;
|
||||
total = (double)large.QuadPart;
|
||||
large.u.LowPart = user_time.dwLowDateTime;
|
||||
large.u.HighPart = user_time.dwHighDateTime;
|
||||
total += (double)large.QuadPart;
|
||||
if (info) {
|
||||
info->implementation = "GetProcessTimes()";
|
||||
info->resolution = 1e-7;
|
||||
info->monotonic = 1;
|
||||
info->adjustable = 0;
|
||||
}
|
||||
return PyFloat_FromDouble(total * 1e-7);
|
||||
|
||||
large.u.LowPart = kernel_time.dwLowDateTime;
|
||||
large.u.HighPart = kernel_time.dwHighDateTime;
|
||||
ktime = large.QuadPart;
|
||||
|
||||
large.u.LowPart = user_time.dwLowDateTime;
|
||||
large.u.HighPart = user_time.dwHighDateTime;
|
||||
utime = large.QuadPart;
|
||||
|
||||
/* ktime and utime have a resolution of 100 nanoseconds */
|
||||
t = _PyTime_FromNanoseconds((ktime + utime) * 100);
|
||||
*tp = t;
|
||||
return 0;
|
||||
#else
|
||||
|
||||
#if defined(HAVE_SYS_RESOURCE_H)
|
||||
struct rusage ru;
|
||||
#endif
|
||||
#ifdef HAVE_TIMES
|
||||
struct tms t;
|
||||
static long ticks_per_second = -1;
|
||||
#endif
|
||||
|
||||
/* clock_gettime */
|
||||
#if defined(HAVE_CLOCK_GETTIME) \
|
||||
&& (defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_PROF))
|
||||
struct timespec tp;
|
||||
struct timespec ts;
|
||||
#ifdef CLOCK_PROF
|
||||
const clockid_t clk_id = CLOCK_PROF;
|
||||
const char *function = "clock_gettime(CLOCK_PROF)";
|
||||
|
|
@ -1008,75 +1123,117 @@ py_process_time(_Py_clock_info_t *info)
|
|||
const char *function = "clock_gettime(CLOCK_PROCESS_CPUTIME_ID)";
|
||||
#endif
|
||||
|
||||
if (clock_gettime(clk_id, &tp) == 0) {
|
||||
if (clock_gettime(clk_id, &ts) == 0) {
|
||||
if (info) {
|
||||
struct timespec res;
|
||||
info->implementation = function;
|
||||
info->monotonic = 1;
|
||||
info->adjustable = 0;
|
||||
if (clock_getres(clk_id, &res) == 0)
|
||||
info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
|
||||
else
|
||||
info->resolution = 1e-9;
|
||||
if (clock_getres(clk_id, &res)) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return -1;
|
||||
}
|
||||
info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
|
||||
}
|
||||
return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
|
||||
|
||||
if (_PyTime_FromTimespec(tp, &ts) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* getrusage(RUSAGE_SELF) */
|
||||
#if defined(HAVE_SYS_RESOURCE_H)
|
||||
struct rusage ru;
|
||||
|
||||
if (getrusage(RUSAGE_SELF, &ru) == 0) {
|
||||
double total;
|
||||
total = ru.ru_utime.tv_sec + ru.ru_utime.tv_usec * 1e-6;
|
||||
total += ru.ru_stime.tv_sec + ru.ru_stime.tv_usec * 1e-6;
|
||||
_PyTime_t utime, stime;
|
||||
|
||||
if (info) {
|
||||
info->implementation = "getrusage(RUSAGE_SELF)";
|
||||
info->monotonic = 1;
|
||||
info->adjustable = 0;
|
||||
info->resolution = 1e-6;
|
||||
}
|
||||
return PyFloat_FromDouble(total);
|
||||
|
||||
if (_PyTime_FromTimeval(&utime, &ru.ru_utime) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (_PyTime_FromTimeval(&stime, &ru.ru_stime) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_PyTime_t total = utime + utime;
|
||||
*tp = total;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* times() */
|
||||
#ifdef HAVE_TIMES
|
||||
struct tms t;
|
||||
|
||||
if (times(&t) != (clock_t)-1) {
|
||||
double total;
|
||||
static long ticks_per_second = -1;
|
||||
|
||||
if (ticks_per_second == -1) {
|
||||
long freq;
|
||||
#if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK)
|
||||
ticks_per_second = sysconf(_SC_CLK_TCK);
|
||||
if (ticks_per_second < 1)
|
||||
ticks_per_second = -1;
|
||||
freq = sysconf(_SC_CLK_TCK);
|
||||
if (freq < 1) {
|
||||
freq = -1;
|
||||
}
|
||||
#elif defined(HZ)
|
||||
ticks_per_second = HZ;
|
||||
freq = HZ;
|
||||
#else
|
||||
ticks_per_second = 60; /* magic fallback value; may be bogus */
|
||||
freq = 60; /* magic fallback value; may be bogus */
|
||||
#endif
|
||||
|
||||
if (freq != -1) {
|
||||
/* check that _PyTime_MulDiv(t, SEC_TO_NS, ticks_per_second)
|
||||
cannot overflow below */
|
||||
if ((_PyTime_t)freq > _PyTime_MAX / SEC_TO_NS) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"_SC_CLK_TCK is too large");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ticks_per_second = freq;
|
||||
}
|
||||
}
|
||||
|
||||
if (ticks_per_second != -1) {
|
||||
total = (double)t.tms_utime / ticks_per_second;
|
||||
total += (double)t.tms_stime / ticks_per_second;
|
||||
if (info) {
|
||||
info->implementation = "times()";
|
||||
info->monotonic = 1;
|
||||
info->adjustable = 0;
|
||||
info->resolution = 1.0 / ticks_per_second;
|
||||
info->resolution = 1.0 / (double)ticks_per_second;
|
||||
}
|
||||
return PyFloat_FromDouble(total);
|
||||
|
||||
_PyTime_t total;
|
||||
total = _PyTime_MulDiv(t.tms_utime, SEC_TO_NS, ticks_per_second);
|
||||
total += _PyTime_MulDiv(t.tms_stime, SEC_TO_NS, ticks_per_second);
|
||||
*tp = total;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* clock */
|
||||
/* Currently, Python 3 requires clock() to build: see issue #22624 */
|
||||
return floatclock(info);
|
||||
return _PyTime_GetClockWithInfo(tp, info);
|
||||
#endif
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
time_process_time(PyObject *self, PyObject *unused)
|
||||
{
|
||||
return py_process_time(NULL);
|
||||
_PyTime_t t;
|
||||
if (_PyTime_GetProcessTimeWithInfo(&t, NULL) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return _PyFloat_FromPyTime(t);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(process_time_doc,
|
||||
|
|
@ -1084,6 +1241,22 @@ PyDoc_STRVAR(process_time_doc,
|
|||
\n\
|
||||
Process time for profiling: sum of the kernel and user-space CPU time.");
|
||||
|
||||
static PyObject *
|
||||
time_process_time_ns(PyObject *self, PyObject *unused)
|
||||
{
|
||||
_PyTime_t t;
|
||||
if (_PyTime_GetProcessTimeWithInfo(&t, NULL) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return _PyTime_AsNanosecondsObject(t);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(process_time_ns_doc,
|
||||
"process_time() -> int\n\
|
||||
\n\
|
||||
Process time for profiling as nanoseconds:\n\
|
||||
sum of the kernel and user-space CPU time.");
|
||||
|
||||
|
||||
static PyObject *
|
||||
time_get_clock_info(PyObject *self, PyObject *args)
|
||||
|
|
@ -1091,9 +1264,11 @@ time_get_clock_info(PyObject *self, PyObject *args)
|
|||
char *name;
|
||||
_Py_clock_info_t info;
|
||||
PyObject *obj = NULL, *dict, *ns;
|
||||
_PyTime_t t;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s:get_clock_info", &name))
|
||||
if (!PyArg_ParseTuple(args, "s:get_clock_info", &name)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef Py_DEBUG
|
||||
info.implementation = NULL;
|
||||
|
|
@ -1107,61 +1282,84 @@ time_get_clock_info(PyObject *self, PyObject *args)
|
|||
info.resolution = 1.0;
|
||||
#endif
|
||||
|
||||
if (strcmp(name, "time") == 0)
|
||||
obj = floattime(&info);
|
||||
if (strcmp(name, "time") == 0) {
|
||||
if (_PyTime_GetSystemClockWithInfo(&t, &info) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#ifdef PYCLOCK
|
||||
else if (strcmp(name, "clock") == 0)
|
||||
else if (strcmp(name, "clock") == 0) {
|
||||
obj = pyclock(&info);
|
||||
if (obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(obj);
|
||||
}
|
||||
#endif
|
||||
else if (strcmp(name, "monotonic") == 0)
|
||||
obj = pymonotonic(&info);
|
||||
else if (strcmp(name, "perf_counter") == 0)
|
||||
obj = perf_counter(&info);
|
||||
else if (strcmp(name, "process_time") == 0)
|
||||
obj = py_process_time(&info);
|
||||
else if (strcmp(name, "monotonic") == 0) {
|
||||
if (_PyTime_GetMonotonicClockWithInfo(&t, &info) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (strcmp(name, "perf_counter") == 0) {
|
||||
if (_PyTime_GetPerfCounterWithInfo(&t, &info) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (strcmp(name, "process_time") == 0) {
|
||||
if (_PyTime_GetProcessTimeWithInfo(&t, &info) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_ValueError, "unknown clock");
|
||||
return NULL;
|
||||
}
|
||||
if (obj == NULL)
|
||||
return NULL;
|
||||
Py_DECREF(obj);
|
||||
|
||||
dict = PyDict_New();
|
||||
if (dict == NULL)
|
||||
if (dict == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(info.implementation != NULL);
|
||||
obj = PyUnicode_FromString(info.implementation);
|
||||
if (obj == NULL)
|
||||
if (obj == NULL) {
|
||||
goto error;
|
||||
if (PyDict_SetItemString(dict, "implementation", obj) == -1)
|
||||
}
|
||||
if (PyDict_SetItemString(dict, "implementation", obj) == -1) {
|
||||
goto error;
|
||||
}
|
||||
Py_CLEAR(obj);
|
||||
|
||||
assert(info.monotonic != -1);
|
||||
obj = PyBool_FromLong(info.monotonic);
|
||||
if (obj == NULL)
|
||||
if (obj == NULL) {
|
||||
goto error;
|
||||
if (PyDict_SetItemString(dict, "monotonic", obj) == -1)
|
||||
}
|
||||
if (PyDict_SetItemString(dict, "monotonic", obj) == -1) {
|
||||
goto error;
|
||||
}
|
||||
Py_CLEAR(obj);
|
||||
|
||||
assert(info.adjustable != -1);
|
||||
obj = PyBool_FromLong(info.adjustable);
|
||||
if (obj == NULL)
|
||||
if (obj == NULL) {
|
||||
goto error;
|
||||
if (PyDict_SetItemString(dict, "adjustable", obj) == -1)
|
||||
}
|
||||
if (PyDict_SetItemString(dict, "adjustable", obj) == -1) {
|
||||
goto error;
|
||||
}
|
||||
Py_CLEAR(obj);
|
||||
|
||||
assert(info.resolution > 0.0);
|
||||
assert(info.resolution <= 1.0);
|
||||
obj = PyFloat_FromDouble(info.resolution);
|
||||
if (obj == NULL)
|
||||
if (obj == NULL) {
|
||||
goto error;
|
||||
if (PyDict_SetItemString(dict, "resolution", obj) == -1)
|
||||
}
|
||||
if (PyDict_SetItemString(dict, "resolution", obj) == -1) {
|
||||
goto error;
|
||||
}
|
||||
Py_CLEAR(obj);
|
||||
|
||||
ns = _PyNamespace_New(dict);
|
||||
|
|
@ -1284,14 +1482,17 @@ PyInit_timezone(PyObject *m) {
|
|||
|
||||
static PyMethodDef time_methods[] = {
|
||||
{"time", time_time, METH_NOARGS, time_doc},
|
||||
{"time_ns", time_time_ns, METH_NOARGS, time_ns_doc},
|
||||
#ifdef PYCLOCK
|
||||
{"clock", time_clock, METH_NOARGS, clock_doc},
|
||||
#endif
|
||||
#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},
|
||||
#endif
|
||||
#ifdef HAVE_CLOCK_SETTIME
|
||||
{"clock_settime", time_clock_settime, METH_VARARGS, clock_settime_doc},
|
||||
{"clock_settime_ns",time_clock_settime_ns, METH_VARARGS, clock_settime_ns_doc},
|
||||
#endif
|
||||
#ifdef HAVE_CLOCK_GETRES
|
||||
{"clock_getres", time_clock_getres, METH_VARARGS, clock_getres_doc},
|
||||
|
|
@ -1315,8 +1516,11 @@ static PyMethodDef time_methods[] = {
|
|||
{"tzset", time_tzset, METH_NOARGS, tzset_doc},
|
||||
#endif
|
||||
{"monotonic", time_monotonic, METH_NOARGS, monotonic_doc},
|
||||
{"monotonic_ns", time_monotonic_ns, METH_NOARGS, monotonic_ns_doc},
|
||||
{"process_time", time_process_time, METH_NOARGS, process_time_doc},
|
||||
{"process_time_ns", time_process_time_ns, METH_NOARGS, process_time_ns_doc},
|
||||
{"perf_counter", time_perf_counter, METH_NOARGS, perf_counter_doc},
|
||||
{"perf_counter_ns", time_perf_counter_ns, METH_NOARGS, perf_counter_ns_doc},
|
||||
{"get_clock_info", time_get_clock_info, METH_VARARGS, get_clock_info_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
|
@ -1411,18 +1615,6 @@ PyInit_time(void)
|
|||
return m;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
floattime(_Py_clock_info_t *info)
|
||||
{
|
||||
_PyTime_t t;
|
||||
if (_PyTime_GetSystemClockWithInfo(&t, info) < 0) {
|
||||
assert(info != NULL);
|
||||
return NULL;
|
||||
}
|
||||
return _PyFloat_FromPyTime(t);
|
||||
}
|
||||
|
||||
|
||||
/* Implement pysleep() for various platforms.
|
||||
When interrupted (or when another error occurs), return -1 and
|
||||
set an exception; else return 0. */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue