Commit c29b585f authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

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
parent e314853d
...@@ -185,7 +185,7 @@ Functions ...@@ -185,7 +185,7 @@ Functions
.. versionadded:: 3.3 .. versionadded:: 3.3
.. function:: clock_gettime(clk_id) .. function:: clock_gettime(clk_id) -> float
Return the time of the specified clock *clk_id*. Refer to Return the time of the specified clock *clk_id*. Refer to
:ref:`time-clock-id-constants` for a list of accepted values for *clk_id*. :ref:`time-clock-id-constants` for a list of accepted values for *clk_id*.
...@@ -195,7 +195,16 @@ Functions ...@@ -195,7 +195,16 @@ Functions
.. versionadded:: 3.3 .. versionadded:: 3.3
.. function:: clock_settime(clk_id, time) .. function:: clock_gettime_ns(clk_id) -> int
Similar to :func:`clock_gettime` but return time as nanoseconds.
Availability: Unix.
.. versionadded:: 3.7
.. function:: clock_settime(clk_id, time: float)
Set the time of the specified clock *clk_id*. Currently, Set the time of the specified clock *clk_id*. Currently,
:data:`CLOCK_REALTIME` is the only accepted value for *clk_id*. :data:`CLOCK_REALTIME` is the only accepted value for *clk_id*.
...@@ -205,6 +214,15 @@ Functions ...@@ -205,6 +214,15 @@ Functions
.. versionadded:: 3.3 .. versionadded:: 3.3
.. function:: clock_settime_ns(clk_id, time: int)
Similar to :func:`clock_settime` but set time with nanoseconds.
Availability: Unix.
.. versionadded:: 3.7
.. function:: ctime([secs]) .. function:: ctime([secs])
Convert a time expressed in seconds since the epoch to a string representing Convert a time expressed in seconds since the epoch to a string representing
...@@ -267,7 +285,7 @@ Functions ...@@ -267,7 +285,7 @@ Functions
The earliest date for which it can generate a time is platform-dependent. The earliest date for which it can generate a time is platform-dependent.
.. function:: monotonic() .. function:: monotonic() -> float
Return the value (in fractional seconds) of a monotonic clock, i.e. a clock Return the value (in fractional seconds) of a monotonic clock, i.e. a clock
that cannot go backwards. The clock is not affected by system clock updates. that cannot go backwards. The clock is not affected by system clock updates.
...@@ -287,7 +305,13 @@ Functions ...@@ -287,7 +305,13 @@ Functions
The function is now always available. The function is now always available.
.. function:: perf_counter() .. function:: monotonic_ns() -> int
Similar to :func:`monotonic`, but return time as nanoseconds.
.. versionadded:: 3.7
.. function:: perf_counter() -> float
.. index:: .. index::
single: benchmarking single: benchmarking
...@@ -300,8 +324,14 @@ Functions ...@@ -300,8 +324,14 @@ Functions
.. versionadded:: 3.3 .. versionadded:: 3.3
.. function:: perf_counter_ns() -> int
Similar to :func:`perf_counter`, but return time as nanoseconds.
.. versionadded:: 3.7
.. function:: process_time()
.. function:: process_time() -> float
.. index:: .. index::
single: CPU time single: CPU time
...@@ -316,6 +346,12 @@ Functions ...@@ -316,6 +346,12 @@ Functions
.. versionadded:: 3.3 .. versionadded:: 3.3
.. function:: process_time_ns() -> int
Similar to :func:`process_time` but return time as nanoseconds.
.. versionadded:: 3.7
.. function:: sleep(secs) .. function:: sleep(secs)
Suspend execution of the calling thread for the given number of seconds. Suspend execution of the calling thread for the given number of seconds.
...@@ -541,7 +577,7 @@ Functions ...@@ -541,7 +577,7 @@ Functions
:class:`struct_time`, or having elements of the wrong type, a :class:`struct_time`, or having elements of the wrong type, a
:exc:`TypeError` is raised. :exc:`TypeError` is raised.
.. function:: time() .. function:: time() -> float
Return the time in seconds since the epoch_ as a floating point Return the time in seconds since the epoch_ as a floating point
number. The specific date of the epoch and the handling of number. The specific date of the epoch and the handling of
...@@ -567,6 +603,13 @@ Functions ...@@ -567,6 +603,13 @@ Functions
of the calendar date may be accessed as attributes. of the calendar date may be accessed as attributes.
.. function:: time_ns() -> int
Similar to :func:`time` but returns time as an integer number of nanoseconds
since the epoch_.
.. versionadded:: 3.7
.. function:: tzset() .. function:: tzset()
Reset the time conversion rules used by the library routines. The environment Reset the time conversion rules used by the library routines. The environment
......
...@@ -159,6 +159,32 @@ effort will be made to add such support. ...@@ -159,6 +159,32 @@ effort will be made to add such support.
PEP written by Erik M. Bray; implementation by Masayuki Yamamoto. PEP written by Erik M. Bray; implementation by Masayuki Yamamoto.
PEP 564: Add new time functions with nanosecond resolution
----------------------------------------------------------
Add six new "nanosecond" variants of existing functions to the :mod:`time`
module:
* :func:`time.clock_gettime_ns`
* :func:`time.clock_settime_ns`
* :func:`time.monotonic_ns`
* :func:`time.perf_counter_ns`
* :func:`time.process_time_ns`
* :func:`time.time_ns`
While similar to the existing functions without the ``_ns`` suffix, they
provide nanosecond resolution: they return a number of nanoseconds as a Python
``int``.
The ``time.time_ns()`` resolution is 3 times better than the ``time.time()``
resolution on Linux and Windows.
.. seealso::
:pep:`564` -- Add new time functions with nanosecond resolution
PEP written and implemented by Victor Stinner
Other Language Changes Other Language Changes
====================== ======================
...@@ -313,6 +339,15 @@ separately. (Contributed by Barry Warsaw in :issue:`1198569`.) ...@@ -313,6 +339,15 @@ separately. (Contributed by Barry Warsaw in :issue:`1198569`.)
time time
---- ----
The :pep:`564` added six new functions with nanosecond resolution:
* :func:`time.clock_gettime_ns`
* :func:`time.clock_settime_ns`
* :func:`time.monotonic_ns`
* :func:`time.perf_counter_ns`
* :func:`time.process_time_ns`
* :func:`time.time_ns`
Add new clock identifiers: Add new clock identifiers:
* :data:`time.CLOCK_BOOTTIME` (Linux): Identical to * :data:`time.CLOCK_BOOTTIME` (Linux): Identical to
......
...@@ -85,7 +85,11 @@ PyAPI_FUNC(_PyTime_t) _PyTime_FromSeconds(int seconds); ...@@ -85,7 +85,11 @@ PyAPI_FUNC(_PyTime_t) _PyTime_FromSeconds(int seconds);
((_PyTime_t)(seconds) * (1000 * 1000 * 1000)) ((_PyTime_t)(seconds) * (1000 * 1000 * 1000))
/* Create a timestamp from a number of nanoseconds. */ /* Create a timestamp from a number of nanoseconds. */
PyAPI_FUNC(_PyTime_t) _PyTime_FromNanoseconds(long long ns); PyAPI_FUNC(_PyTime_t) _PyTime_FromNanoseconds(_PyTime_t ns);
/* Create a timestamp from nanoseconds (Python int). */
PyAPI_FUNC(int) _PyTime_FromNanosecondsObject(_PyTime_t *t,
PyObject *obj);
/* Convert a number of seconds (Python float or int) to a timetamp. /* Convert a number of seconds (Python float or int) to a timetamp.
Raise an exception and return -1 on error, return 0 on success. */ Raise an exception and return -1 on error, return 0 on success. */
...@@ -114,6 +118,10 @@ PyAPI_FUNC(_PyTime_t) _PyTime_AsMicroseconds(_PyTime_t t, ...@@ -114,6 +118,10 @@ PyAPI_FUNC(_PyTime_t) _PyTime_AsMicroseconds(_PyTime_t t,
object. */ object. */
PyAPI_FUNC(PyObject *) _PyTime_AsNanosecondsObject(_PyTime_t t); PyAPI_FUNC(PyObject *) _PyTime_AsNanosecondsObject(_PyTime_t t);
/* Create a timestamp from a timeval structure.
Raise an exception and return -1 on overflow, return 0 on success. */
PyAPI_FUNC(int) _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv);
/* Convert a timestamp to a timeval structure (microsecond resolution). /* Convert a timestamp to a timeval structure (microsecond resolution).
tv_usec is always positive. tv_usec is always positive.
Raise an exception and return -1 if the conversion overflowed, Raise an exception and return -1 if the conversion overflowed,
...@@ -140,12 +148,22 @@ PyAPI_FUNC(int) _PyTime_AsTimevalTime_t( ...@@ -140,12 +148,22 @@ PyAPI_FUNC(int) _PyTime_AsTimevalTime_t(
_PyTime_round_t round); _PyTime_round_t round);
#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_KQUEUE) #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_KQUEUE)
/* Create a timestamp from a timespec structure.
Raise an exception and return -1 on overflow, return 0 on success. */
PyAPI_FUNC(int) _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts);
/* Convert a timestamp to a timespec structure (nanosecond resolution). /* Convert a timestamp to a timespec structure (nanosecond resolution).
tv_nsec is always positive. tv_nsec is always positive.
Raise an exception and return -1 on error, return 0 on success. */ Raise an exception and return -1 on error, return 0 on success. */
PyAPI_FUNC(int) _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts); PyAPI_FUNC(int) _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts);
#endif #endif
/* Compute ticks * mul / div.
The caller must ensure that ((div - 1) * mul) cannot overflow. */
PyAPI_FUNC(_PyTime_t) _PyTime_MulDiv(_PyTime_t ticks,
_PyTime_t mul,
_PyTime_t div);
/* Get the current time from the system clock. /* Get the current time from the system clock.
The function cannot fail. _PyTime_Init() ensures that the system clock The function cannot fail. _PyTime_Init() ensures that the system clock
......
...@@ -3549,6 +3549,23 @@ class TestPEP519(unittest.TestCase): ...@@ -3549,6 +3549,23 @@ class TestPEP519(unittest.TestCase):
self.assertRaises(ZeroDivisionError, self.fspath, self.assertRaises(ZeroDivisionError, self.fspath,
_PathLike(ZeroDivisionError())) _PathLike(ZeroDivisionError()))
class TimesTests(unittest.TestCase):
def test_times(self):
times = os.times()
self.assertIsInstance(times, os.times_result)
for field in ('user', 'system', 'children_user', 'children_system',
'elapsed'):
value = getattr(times, field)
self.assertIsInstance(value, float)
if os.name == 'nt':
self.assertEqual(times.children_user, 0)
self.assertEqual(times.children_system, 0)
self.assertEqual(times.elapsed, 0)
# Only test if the C version is provided, otherwise TestPEP519 already tested # Only test if the C version is provided, otherwise TestPEP519 already tested
# the pure Python implementation. # the pure Python implementation.
if hasattr(os, "_fspath"): if hasattr(os, "_fspath"):
......
...@@ -64,6 +64,27 @@ class TimeTestCase(unittest.TestCase): ...@@ -64,6 +64,27 @@ class TimeTestCase(unittest.TestCase):
self.assertFalse(info.monotonic) self.assertFalse(info.monotonic)
self.assertTrue(info.adjustable) self.assertTrue(info.adjustable)
def test_time_ns_type(self):
def check_ns(sec, ns):
self.assertIsInstance(ns, int)
sec_ns = int(sec * 1e9)
# tolerate a difference of 50 ms
self.assertLess((sec_ns - ns), 50 ** 6, (sec, ns))
check_ns(time.time(),
time.time_ns())
check_ns(time.monotonic(),
time.monotonic_ns())
check_ns(time.perf_counter(),
time.perf_counter_ns())
check_ns(time.process_time(),
time.process_time_ns())
if hasattr(time, 'clock_gettime'):
check_ns(time.clock_gettime(time.CLOCK_REALTIME),
time.clock_gettime_ns(time.CLOCK_REALTIME))
def test_clock(self): def test_clock(self):
with self.assertWarns(DeprecationWarning): with self.assertWarns(DeprecationWarning):
time.clock() time.clock()
...@@ -76,7 +97,8 @@ class TimeTestCase(unittest.TestCase): ...@@ -76,7 +97,8 @@ class TimeTestCase(unittest.TestCase):
@unittest.skipUnless(hasattr(time, 'clock_gettime'), @unittest.skipUnless(hasattr(time, 'clock_gettime'),
'need time.clock_gettime()') 'need time.clock_gettime()')
def test_clock_realtime(self): def test_clock_realtime(self):
time.clock_gettime(time.CLOCK_REALTIME) t = time.clock_gettime(time.CLOCK_REALTIME)
self.assertIsInstance(t, float)
@unittest.skipUnless(hasattr(time, 'clock_gettime'), @unittest.skipUnless(hasattr(time, 'clock_gettime'),
'need time.clock_gettime()') 'need time.clock_gettime()')
......
Implement the :pep:`564`, add new 6 new functions with nanosecond resolution to
the :mod:`time` module: :func:`~time.clock_gettime_ns`,
:func:`~time.clock_settime_ns`, :func:`~time.monotonic_ns`,
:func:`~time.perf_counter_ns`, :func:`~time.process_time_ns`,
:func:`~time.time_ns`.
...@@ -3946,13 +3946,16 @@ test_pytime_fromsecondsobject(PyObject *self, PyObject *args) ...@@ -3946,13 +3946,16 @@ test_pytime_fromsecondsobject(PyObject *self, PyObject *args)
static PyObject * static PyObject *
test_pytime_assecondsdouble(PyObject *self, PyObject *args) test_pytime_assecondsdouble(PyObject *self, PyObject *args)
{ {
long long ns; PyObject *obj;
_PyTime_t ts; _PyTime_t ts;
double d; double d;
if (!PyArg_ParseTuple(args, "L", &ns)) if (!PyArg_ParseTuple(args, "O", &obj)) {
return NULL;
}
if (_PyTime_FromNanosecondsObject(&ts, obj) < 0) {
return NULL; return NULL;
ts = _PyTime_FromNanoseconds(ns); }
d = _PyTime_AsSecondsDouble(ts); d = _PyTime_AsSecondsDouble(ts);
return PyFloat_FromDouble(d); return PyFloat_FromDouble(d);
} }
...@@ -3960,23 +3963,28 @@ test_pytime_assecondsdouble(PyObject *self, PyObject *args) ...@@ -3960,23 +3963,28 @@ test_pytime_assecondsdouble(PyObject *self, PyObject *args)
static PyObject * static PyObject *
test_PyTime_AsTimeval(PyObject *self, PyObject *args) test_PyTime_AsTimeval(PyObject *self, PyObject *args)
{ {
long long ns; PyObject *obj;
int round; int round;
_PyTime_t t; _PyTime_t t;
struct timeval tv; struct timeval tv;
PyObject *seconds; PyObject *seconds;
if (!PyArg_ParseTuple(args, "Li", &ns, &round)) if (!PyArg_ParseTuple(args, "Oi", &obj, &round))
return NULL; return NULL;
if (check_time_rounding(round) < 0) if (check_time_rounding(round) < 0) {
return NULL; return NULL;
t = _PyTime_FromNanoseconds(ns); }
if (_PyTime_AsTimeval(t, &tv, round) < 0) if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
return NULL; return NULL;
}
if (_PyTime_AsTimeval(t, &tv, round) < 0) {
return NULL;
}
seconds = PyLong_FromLongLong(tv.tv_sec); seconds = PyLong_FromLongLong(tv.tv_sec);
if (seconds == NULL) if (seconds == NULL) {
return NULL; return NULL;
}
return Py_BuildValue("Nl", seconds, tv.tv_usec); return Py_BuildValue("Nl", seconds, tv.tv_usec);
} }
...@@ -3984,15 +3992,19 @@ test_PyTime_AsTimeval(PyObject *self, PyObject *args) ...@@ -3984,15 +3992,19 @@ test_PyTime_AsTimeval(PyObject *self, PyObject *args)
static PyObject * static PyObject *
test_PyTime_AsTimespec(PyObject *self, PyObject *args) test_PyTime_AsTimespec(PyObject *self, PyObject *args)
{ {
long long ns; PyObject *obj;
_PyTime_t t; _PyTime_t t;
struct timespec ts; struct timespec ts;
if (!PyArg_ParseTuple(args, "L", &ns)) if (!PyArg_ParseTuple(args, "O", &obj)) {
return NULL; return NULL;
t = _PyTime_FromNanoseconds(ns); }
if (_PyTime_AsTimespec(t, &ts) == -1) if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
return NULL; return NULL;
}
if (_PyTime_AsTimespec(t, &ts) == -1) {
return NULL;
}
return Py_BuildValue("Nl", _PyLong_FromTime_t(ts.tv_sec), ts.tv_nsec); return Py_BuildValue("Nl", _PyLong_FromTime_t(ts.tv_sec), ts.tv_nsec);
} }
#endif #endif
...@@ -4000,15 +4012,19 @@ test_PyTime_AsTimespec(PyObject *self, PyObject *args) ...@@ -4000,15 +4012,19 @@ test_PyTime_AsTimespec(PyObject *self, PyObject *args)
static PyObject * static PyObject *
test_PyTime_AsMilliseconds(PyObject *self, PyObject *args) test_PyTime_AsMilliseconds(PyObject *self, PyObject *args)
{ {
long long ns; PyObject *obj;
int round; int round;
_PyTime_t t, ms; _PyTime_t t, ms;
if (!PyArg_ParseTuple(args, "Li", &ns, &round)) if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) {
return NULL; return NULL;
if (check_time_rounding(round) < 0) }
if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
return NULL;
}
if (check_time_rounding(round) < 0) {
return NULL; return NULL;
t = _PyTime_FromNanoseconds(ns); }
ms = _PyTime_AsMilliseconds(t, round); ms = _PyTime_AsMilliseconds(t, round);
/* This conversion rely on the fact that _PyTime_t is a number of /* This conversion rely on the fact that _PyTime_t is a number of
nanoseconds */ nanoseconds */
...@@ -4018,15 +4034,18 @@ test_PyTime_AsMilliseconds(PyObject *self, PyObject *args) ...@@ -4018,15 +4034,18 @@ test_PyTime_AsMilliseconds(PyObject *self, PyObject *args)
static PyObject * static PyObject *
test_PyTime_AsMicroseconds(PyObject *self, PyObject *args) test_PyTime_AsMicroseconds(PyObject *self, PyObject *args)
{ {
long long ns; PyObject *obj;
int round; int round;
_PyTime_t t, ms; _PyTime_t t, ms;
if (!PyArg_ParseTuple(args, "Li", &ns, &round)) if (!PyArg_ParseTuple(args, "Oi", &obj, &round))
return NULL; return NULL;
if (check_time_rounding(round) < 0) if (_PyTime_FromNanosecondsObject(&t, obj) < 0) {
return NULL; return NULL;
t = _PyTime_FromNanoseconds(ns); }
if (check_time_rounding(round) < 0) {
return NULL;
}
ms = _PyTime_AsMicroseconds(t, round); ms = _PyTime_AsMicroseconds(t, round);
/* This conversion rely on the fact that _PyTime_t is a number of /* This conversion rely on the fact that _PyTime_t is a number of
nanoseconds */ nanoseconds */
......
...@@ -34,57 +34,90 @@ ...@@ -34,57 +34,90 @@
#endif /* MS_WINDOWS */ #endif /* MS_WINDOWS */
#endif /* !__WATCOMC__ || __QNX__ */ #endif /* !__WATCOMC__ || __QNX__ */
#define SEC_TO_NS (1000 * 1000 * 1000)
/* Forward declarations */ /* Forward declarations */
static int pysleep(_PyTime_t); static int pysleep(_PyTime_t);
static PyObject* floattime(_Py_clock_info_t *info);
static PyObject*
_PyFloat_FromPyTime(_PyTime_t t)
{
double d = _PyTime_AsSecondsDouble(t);
return PyFloat_FromDouble(d);
}
static PyObject * static PyObject *
time_time(PyObject *self, PyObject *unused) time_time(PyObject *self, PyObject *unused)
{ {
return floattime(NULL); _PyTime_t t = _PyTime_GetSystemClock();
return _PyFloat_FromPyTime(t);
} }
PyDoc_STRVAR(time_doc, PyDoc_STRVAR(time_doc,
"time() -> floating point number\n\ "time() -> floating point number\n\
\n\ \n\
Return the current time in seconds since the Epoch.\n\ Return the current time in seconds since the Epoch.\n\
Fractions of a second may be present if the system clock provides them."); 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) #if defined(HAVE_CLOCK)
#ifndef CLOCKS_PER_SEC #ifndef CLOCKS_PER_SEC
#ifdef CLK_TCK # ifdef CLK_TCK
#define CLOCKS_PER_SEC CLK_TCK # define CLOCKS_PER_SEC CLK_TCK
#else # else
#define CLOCKS_PER_SEC 1000000 # define CLOCKS_PER_SEC 1000000
#endif # endif
#endif #endif
static PyObject* static int
_PyFloat_FromPyTime(_PyTime_t t) _PyTime_GetClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
{ {
double d = _PyTime_AsSecondsDouble(t); static int initialized = 0;
return PyFloat_FromDouble(d); clock_t ticks;
}
static PyObject * if (!initialized) {
floatclock(_Py_clock_info_t *info) initialized = 1;
{
clock_t value; /* must sure that _PyTime_MulDiv(ticks, SEC_TO_NS, CLOCKS_PER_SEC)
value = clock(); above cannot overflow */
if (value == (clock_t)-1) { if ((_PyTime_t)CLOCKS_PER_SEC > _PyTime_MAX / SEC_TO_NS) {
PyErr_SetString(PyExc_RuntimeError, PyErr_SetString(PyExc_OverflowError,
"the processor time used is not available " "CLOCKS_PER_SEC is too large");
"or its value cannot be represented"); return -1;
return NULL;
} }
}
if (info) { if (info) {
info->implementation = "clock()"; info->implementation = "clock()";
info->resolution = 1.0 / (double)CLOCKS_PER_SEC; info->resolution = 1.0 / (double)CLOCKS_PER_SEC;
info->monotonic = 1; info->monotonic = 1;
info->adjustable = 0; 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 */ #endif /* HAVE_CLOCK */
...@@ -95,8 +128,7 @@ perf_counter(_Py_clock_info_t *info) ...@@ -95,8 +128,7 @@ perf_counter(_Py_clock_info_t *info)
if (_PyTime_GetPerfCounterWithInfo(&t, info) < 0) { if (_PyTime_GetPerfCounterWithInfo(&t, info) < 0) {
return NULL; return NULL;
} }
double d = _PyTime_AsSecondsDouble(t); return _PyFloat_FromPyTime(t);
return PyFloat_FromDouble(d);
} }
#if defined(MS_WINDOWS) || defined(HAVE_CLOCK) #if defined(MS_WINDOWS) || defined(HAVE_CLOCK)
...@@ -111,10 +143,15 @@ pyclock(_Py_clock_info_t *info) ...@@ -111,10 +143,15 @@ pyclock(_Py_clock_info_t *info)
"instead", 1) < 0) { "instead", 1) < 0) {
return NULL; return NULL;
} }
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
return perf_counter(info); return perf_counter(info);
#else #else
return floatclock(info); _PyTime_t t;
if (_PyTime_GetClockWithInfo(&t, info) < 0) {
return NULL;
}
return _PyFloat_FromPyTime(t);
#endif #endif
} }
...@@ -140,8 +177,9 @@ time_clock_gettime(PyObject *self, PyObject *args) ...@@ -140,8 +177,9 @@ time_clock_gettime(PyObject *self, PyObject *args)
int clk_id; int clk_id;
struct timespec tp; struct timespec tp;
if (!PyArg_ParseTuple(args, "i:clock_gettime", &clk_id)) if (!PyArg_ParseTuple(args, "i:clock_gettime", &clk_id)) {
return NULL; return NULL;
}
ret = clock_gettime((clockid_t)clk_id, &tp); ret = clock_gettime((clockid_t)clk_id, &tp);
if (ret != 0) { if (ret != 0) {
...@@ -152,9 +190,37 @@ time_clock_gettime(PyObject *self, PyObject *args) ...@@ -152,9 +190,37 @@ time_clock_gettime(PyObject *self, PyObject *args)
} }
PyDoc_STRVAR(clock_gettime_doc, PyDoc_STRVAR(clock_gettime_doc,
"clock_gettime(clk_id) -> floating point number\n\ "clock_gettime(clk_id) -> float\n\
\n\ \n\
Return the time of the specified clock clk_id."); 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 */ #endif /* HAVE_CLOCK_GETTIME */
#ifdef HAVE_CLOCK_SETTIME #ifdef HAVE_CLOCK_SETTIME
...@@ -188,6 +254,39 @@ PyDoc_STRVAR(clock_settime_doc, ...@@ -188,6 +254,39 @@ PyDoc_STRVAR(clock_settime_doc,
"clock_settime(clk_id, time)\n\ "clock_settime(clk_id, time)\n\
\n\ \n\
Set the time of the specified clock clk_id."); 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 */ #endif /* HAVE_CLOCK_SETTIME */
#ifdef HAVE_CLOCK_GETRES #ifdef HAVE_CLOCK_GETRES
...@@ -927,26 +1026,28 @@ should not be relied on."); ...@@ -927,26 +1026,28 @@ should not be relied on.");
#endif /* HAVE_WORKING_TZSET */ #endif /* HAVE_WORKING_TZSET */
static PyObject * static PyObject *
pymonotonic(_Py_clock_info_t *info) time_monotonic(PyObject *self, PyObject *unused)
{ {
_PyTime_t t; _PyTime_t t = _PyTime_GetMonotonicClock();
if (_PyTime_GetMonotonicClockWithInfo(&t, info) < 0) {
assert(info != NULL);
return NULL;
}
return _PyFloat_FromPyTime(t); return _PyFloat_FromPyTime(t);
} }
PyDoc_STRVAR(monotonic_doc,
"monotonic() -> float\n\
\n\
Monotonic clock, cannot go backward.");
static PyObject * static PyObject *
time_monotonic(PyObject *self, PyObject *unused) time_monotonic_ns(PyObject *self, PyObject *unused)
{ {
return pymonotonic(NULL); _PyTime_t t = _PyTime_GetMonotonicClock();
return _PyTime_AsNanosecondsObject(t);
} }
PyDoc_STRVAR(monotonic_doc, PyDoc_STRVAR(monotonic_ns_doc,
"monotonic() -> float\n\ "monotonic_ns() -> int\n\
\n\ \n\
Monotonic clock, cannot go backward."); Monotonic clock, cannot go backward, as nanoseconds.");
static PyObject * static PyObject *
time_perf_counter(PyObject *self, PyObject *unused) time_perf_counter(PyObject *self, PyObject *unused)
...@@ -959,47 +1060,61 @@ PyDoc_STRVAR(perf_counter_doc, ...@@ -959,47 +1060,61 @@ PyDoc_STRVAR(perf_counter_doc,
\n\ \n\
Performance counter for benchmarking."); Performance counter for benchmarking.");
static PyObject* static PyObject *
py_process_time(_Py_clock_info_t *info) 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) #if defined(MS_WINDOWS)
HANDLE process; HANDLE process;
FILETIME creation_time, exit_time, kernel_time, user_time; FILETIME creation_time, exit_time, kernel_time, user_time;
ULARGE_INTEGER large; ULARGE_INTEGER large;
double total; _PyTime_t ktime, utime, t;
BOOL ok; BOOL ok;
process = GetCurrentProcess(); process = GetCurrentProcess();
ok = GetProcessTimes(process, &creation_time, &exit_time, &kernel_time, &user_time); ok = GetProcessTimes(process, &creation_time, &exit_time,
if (!ok) &kernel_time, &user_time);
return PyErr_SetFromWindowsErr(0); 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) { if (info) {
info->implementation = "GetProcessTimes()"; info->implementation = "GetProcessTimes()";
info->resolution = 1e-7; info->resolution = 1e-7;
info->monotonic = 1; info->monotonic = 1;
info->adjustable = 0; info->adjustable = 0;
} }
return PyFloat_FromDouble(total * 1e-7);
#else
#if defined(HAVE_SYS_RESOURCE_H) large.u.LowPart = kernel_time.dwLowDateTime;
struct rusage ru; large.u.HighPart = kernel_time.dwHighDateTime;
#endif ktime = large.QuadPart;
#ifdef HAVE_TIMES
struct tms t; large.u.LowPart = user_time.dwLowDateTime;
static long ticks_per_second = -1; large.u.HighPart = user_time.dwHighDateTime;
#endif utime = large.QuadPart;
/* ktime and utime have a resolution of 100 nanoseconds */
t = _PyTime_FromNanoseconds((ktime + utime) * 100);
*tp = t;
return 0;
#else
/* clock_gettime */
#if defined(HAVE_CLOCK_GETTIME) \ #if defined(HAVE_CLOCK_GETTIME) \
&& (defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_PROF)) && (defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_PROF))
struct timespec tp; struct timespec ts;
#ifdef CLOCK_PROF #ifdef CLOCK_PROF
const clockid_t clk_id = CLOCK_PROF; const clockid_t clk_id = CLOCK_PROF;
const char *function = "clock_gettime(CLOCK_PROF)"; const char *function = "clock_gettime(CLOCK_PROF)";
...@@ -1008,75 +1123,117 @@ py_process_time(_Py_clock_info_t *info) ...@@ -1008,75 +1123,117 @@ py_process_time(_Py_clock_info_t *info)
const char *function = "clock_gettime(CLOCK_PROCESS_CPUTIME_ID)"; const char *function = "clock_gettime(CLOCK_PROCESS_CPUTIME_ID)";
#endif #endif
if (clock_gettime(clk_id, &tp) == 0) { if (clock_gettime(clk_id, &ts) == 0) {
if (info) { if (info) {
struct timespec res; struct timespec res;
info->implementation = function; info->implementation = function;
info->monotonic = 1; info->monotonic = 1;
info->adjustable = 0; info->adjustable = 0;
if (clock_getres(clk_id, &res) == 0) if (clock_getres(clk_id, &res)) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
info->resolution = res.tv_sec + res.tv_nsec * 1e-9; info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
else
info->resolution = 1e-9;
} }
return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
if (_PyTime_FromTimespec(tp, &ts) < 0) {
return -1;
}
return 0;
} }
#endif #endif
/* getrusage(RUSAGE_SELF) */
#if defined(HAVE_SYS_RESOURCE_H) #if defined(HAVE_SYS_RESOURCE_H)
struct rusage ru;
if (getrusage(RUSAGE_SELF, &ru) == 0) { if (getrusage(RUSAGE_SELF, &ru) == 0) {
double total; _PyTime_t utime, stime;
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;
if (info) { if (info) {
info->implementation = "getrusage(RUSAGE_SELF)"; info->implementation = "getrusage(RUSAGE_SELF)";
info->monotonic = 1; info->monotonic = 1;
info->adjustable = 0; info->adjustable = 0;
info->resolution = 1e-6; 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 #endif
/* times() */
#ifdef HAVE_TIMES #ifdef HAVE_TIMES
struct tms t;
if (times(&t) != (clock_t)-1) { if (times(&t) != (clock_t)-1) {
double total; static long ticks_per_second = -1;
if (ticks_per_second == -1) { if (ticks_per_second == -1) {
long freq;
#if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK) #if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK)
ticks_per_second = sysconf(_SC_CLK_TCK); freq = sysconf(_SC_CLK_TCK);
if (ticks_per_second < 1) if (freq < 1) {
ticks_per_second = -1; freq = -1;
}
#elif defined(HZ) #elif defined(HZ)
ticks_per_second = HZ; freq = HZ;
#else #else
ticks_per_second = 60; /* magic fallback value; may be bogus */ freq = 60; /* magic fallback value; may be bogus */
#endif #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) { if (ticks_per_second != -1) {
total = (double)t.tms_utime / ticks_per_second;
total += (double)t.tms_stime / ticks_per_second;
if (info) { if (info) {
info->implementation = "times()"; info->implementation = "times()";
info->monotonic = 1; info->monotonic = 1;
info->adjustable = 0; 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 #endif
/* clock */
/* Currently, Python 3 requires clock() to build: see issue #22624 */ /* Currently, Python 3 requires clock() to build: see issue #22624 */
return floatclock(info); return _PyTime_GetClockWithInfo(tp, info);
#endif #endif
} }
static PyObject * static PyObject *
time_process_time(PyObject *self, PyObject *unused) 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, PyDoc_STRVAR(process_time_doc,
...@@ -1084,6 +1241,22 @@ PyDoc_STRVAR(process_time_doc, ...@@ -1084,6 +1241,22 @@ PyDoc_STRVAR(process_time_doc,
\n\ \n\
Process time for profiling: sum of the kernel and user-space CPU time."); 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 * static PyObject *
time_get_clock_info(PyObject *self, PyObject *args) time_get_clock_info(PyObject *self, PyObject *args)
...@@ -1091,9 +1264,11 @@ time_get_clock_info(PyObject *self, PyObject *args) ...@@ -1091,9 +1264,11 @@ time_get_clock_info(PyObject *self, PyObject *args)
char *name; char *name;
_Py_clock_info_t info; _Py_clock_info_t info;
PyObject *obj = NULL, *dict, *ns; 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; return NULL;
}
#ifdef Py_DEBUG #ifdef Py_DEBUG
info.implementation = NULL; info.implementation = NULL;
...@@ -1107,61 +1282,84 @@ time_get_clock_info(PyObject *self, PyObject *args) ...@@ -1107,61 +1282,84 @@ time_get_clock_info(PyObject *self, PyObject *args)
info.resolution = 1.0; info.resolution = 1.0;
#endif #endif
if (strcmp(name, "time") == 0) if (strcmp(name, "time") == 0) {
obj = floattime(&info); if (_PyTime_GetSystemClockWithInfo(&t, &info) < 0) {
return NULL;
}
}
#ifdef PYCLOCK #ifdef PYCLOCK
else if (strcmp(name, "clock") == 0) else if (strcmp(name, "clock") == 0) {
obj = pyclock(&info); obj = pyclock(&info);
if (obj == NULL) {
return NULL;
}
Py_DECREF(obj);
}
#endif #endif
else if (strcmp(name, "monotonic") == 0) else if (strcmp(name, "monotonic") == 0) {
obj = pymonotonic(&info); if (_PyTime_GetMonotonicClockWithInfo(&t, &info) < 0) {
else if (strcmp(name, "perf_counter") == 0) return NULL;
obj = perf_counter(&info); }
else if (strcmp(name, "process_time") == 0) }
obj = py_process_time(&info); 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 { else {
PyErr_SetString(PyExc_ValueError, "unknown clock"); PyErr_SetString(PyExc_ValueError, "unknown clock");
return NULL; return NULL;
} }
if (obj == NULL)
return NULL;
Py_DECREF(obj);
dict = PyDict_New(); dict = PyDict_New();
if (dict == NULL) if (dict == NULL) {
return NULL; return NULL;
}
assert(info.implementation != NULL); assert(info.implementation != NULL);
obj = PyUnicode_FromString(info.implementation); obj = PyUnicode_FromString(info.implementation);
if (obj == NULL) if (obj == NULL) {
goto error; goto error;
if (PyDict_SetItemString(dict, "implementation", obj) == -1) }
if (PyDict_SetItemString(dict, "implementation", obj) == -1) {
goto error; goto error;
}
Py_CLEAR(obj); Py_CLEAR(obj);
assert(info.monotonic != -1); assert(info.monotonic != -1);
obj = PyBool_FromLong(info.monotonic); obj = PyBool_FromLong(info.monotonic);
if (obj == NULL) if (obj == NULL) {
goto error; goto error;
if (PyDict_SetItemString(dict, "monotonic", obj) == -1) }
if (PyDict_SetItemString(dict, "monotonic", obj) == -1) {
goto error; goto error;
}
Py_CLEAR(obj); Py_CLEAR(obj);
assert(info.adjustable != -1); assert(info.adjustable != -1);
obj = PyBool_FromLong(info.adjustable); obj = PyBool_FromLong(info.adjustable);
if (obj == NULL) if (obj == NULL) {
goto error; goto error;
if (PyDict_SetItemString(dict, "adjustable", obj) == -1) }
if (PyDict_SetItemString(dict, "adjustable", obj) == -1) {
goto error; goto error;
}
Py_CLEAR(obj); Py_CLEAR(obj);
assert(info.resolution > 0.0); assert(info.resolution > 0.0);
assert(info.resolution <= 1.0); assert(info.resolution <= 1.0);
obj = PyFloat_FromDouble(info.resolution); obj = PyFloat_FromDouble(info.resolution);
if (obj == NULL) if (obj == NULL) {
goto error; goto error;
if (PyDict_SetItemString(dict, "resolution", obj) == -1) }
if (PyDict_SetItemString(dict, "resolution", obj) == -1) {
goto error; goto error;
}
Py_CLEAR(obj); Py_CLEAR(obj);
ns = _PyNamespace_New(dict); ns = _PyNamespace_New(dict);
...@@ -1284,14 +1482,17 @@ PyInit_timezone(PyObject *m) { ...@@ -1284,14 +1482,17 @@ PyInit_timezone(PyObject *m) {
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},
#ifdef PYCLOCK #ifdef PYCLOCK
{"clock", time_clock, METH_NOARGS, clock_doc}, {"clock", time_clock, METH_NOARGS, clock_doc},
#endif #endif
#ifdef HAVE_CLOCK_GETTIME #ifdef HAVE_CLOCK_GETTIME
{"clock_gettime", time_clock_gettime, METH_VARARGS, clock_gettime_doc}, {"clock_gettime", time_clock_gettime, METH_VARARGS, clock_gettime_doc},
{"clock_gettime_ns",time_clock_gettime_ns, METH_VARARGS, clock_gettime_ns_doc},
#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},
{"clock_settime_ns",time_clock_settime_ns, METH_VARARGS, clock_settime_ns_doc},
#endif #endif
#ifdef HAVE_CLOCK_GETRES #ifdef HAVE_CLOCK_GETRES
{"clock_getres", time_clock_getres, METH_VARARGS, clock_getres_doc}, {"clock_getres", time_clock_getres, METH_VARARGS, clock_getres_doc},
...@@ -1315,8 +1516,11 @@ static PyMethodDef time_methods[] = { ...@@ -1315,8 +1516,11 @@ static PyMethodDef time_methods[] = {
{"tzset", time_tzset, METH_NOARGS, tzset_doc}, {"tzset", time_tzset, METH_NOARGS, tzset_doc},
#endif #endif
{"monotonic", time_monotonic, METH_NOARGS, monotonic_doc}, {"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", 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", 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}, {"get_clock_info", time_get_clock_info, METH_VARARGS, get_clock_info_doc},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
...@@ -1411,18 +1615,6 @@ PyInit_time(void) ...@@ -1411,18 +1615,6 @@ PyInit_time(void)
return m; 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. /* Implement pysleep() for various platforms.
When interrupted (or when another error occurs), return -1 and When interrupted (or when another error occurs), return -1 and
set an exception; else return 0. */ set an exception; else return 0. */
......
...@@ -43,8 +43,7 @@ _PyTime_overflow(void) ...@@ -43,8 +43,7 @@ _PyTime_overflow(void)
} }
#if defined(MS_WINDOWS) || defined(__APPLE__) _PyTime_t
Py_LOCAL_INLINE(_PyTime_t)
_PyTime_MulDiv(_PyTime_t ticks, _PyTime_t mul, _PyTime_t div) _PyTime_MulDiv(_PyTime_t ticks, _PyTime_t mul, _PyTime_t div)
{ {
_PyTime_t intpart, remaining; _PyTime_t intpart, remaining;
...@@ -60,7 +59,6 @@ _PyTime_MulDiv(_PyTime_t ticks, _PyTime_t mul, _PyTime_t div) ...@@ -60,7 +59,6 @@ _PyTime_MulDiv(_PyTime_t ticks, _PyTime_t mul, _PyTime_t div)
remaining /= div; remaining /= div;
return intpart * mul + remaining; return intpart * mul + remaining;
} }
#endif /* defined(MS_WINDOWS) || defined(__APPLE__) */
time_t time_t
...@@ -254,19 +252,44 @@ _PyTime_FromSeconds(int seconds) ...@@ -254,19 +252,44 @@ _PyTime_FromSeconds(int seconds)
} }
_PyTime_t _PyTime_t
_PyTime_FromNanoseconds(long long ns) _PyTime_FromNanoseconds(_PyTime_t ns)
{ {
/* _PyTime_t already uses nanosecond resolution, no conversion needed */
return ns;
}
int
_PyTime_FromNanosecondsObject(_PyTime_t *tp, PyObject *obj)
{
long long nsec;
_PyTime_t t; _PyTime_t t;
Py_BUILD_ASSERT(sizeof(long long) <= sizeof(_PyTime_t));
t = Py_SAFE_DOWNCAST(ns, long long, _PyTime_t); if (!PyLong_Check(obj)) {
return t; PyErr_Format(PyExc_TypeError, "expect int, got %s",
Py_TYPE(obj)->tp_name);
return -1;
}
Py_BUILD_ASSERT(sizeof(long long) == sizeof(_PyTime_t));
nsec = PyLong_AsLongLong(obj);
if (nsec == -1 && PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
_PyTime_overflow();
}
return -1;
}
/* _PyTime_t already uses nanosecond resolution, no conversion needed */
t = (_PyTime_t)nsec;
*tp = t;
return 0;
} }
#ifdef HAVE_CLOCK_GETTIME #ifdef HAVE_CLOCK_GETTIME
static int static int
_PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts, int raise) pytime_fromtimespec(_PyTime_t *tp, struct timespec *ts, int raise)
{ {
_PyTime_t t; _PyTime_t t, nsec;
int res = 0; int res = 0;
Py_BUILD_ASSERT(sizeof(ts->tv_sec) <= sizeof(_PyTime_t)); Py_BUILD_ASSERT(sizeof(ts->tv_sec) <= sizeof(_PyTime_t));
...@@ -277,19 +300,42 @@ _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts, int raise) ...@@ -277,19 +300,42 @@ _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts, int raise)
_PyTime_overflow(); _PyTime_overflow();
} }
res = -1; res = -1;
t = (t > 0) ? _PyTime_MAX : _PyTime_MIN;
} }
else {
t = t * SEC_TO_NS; t = t * SEC_TO_NS;
}
t += ts->tv_nsec; nsec = ts->tv_nsec;
/* The following test is written for positive only nsec */
assert(nsec >= 0);
if (t > _PyTime_MAX - nsec) {
if (raise) {
_PyTime_overflow();
}
res = -1;
t = _PyTime_MAX;
}
else {
t += nsec;
}
*tp = t; *tp = t;
return res; return res;
} }
#elif !defined(MS_WINDOWS)
int
_PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts)
{
return pytime_fromtimespec(tp, ts, 1);
}
#endif
#if !defined(MS_WINDOWS)
static int static int
_PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv, int raise) pytime_fromtimeval(_PyTime_t *tp, struct timeval *tv, int raise)
{ {
_PyTime_t t; _PyTime_t t, usec;
int res = 0; int res = 0;
Py_BUILD_ASSERT(sizeof(tv->tv_sec) <= sizeof(_PyTime_t)); Py_BUILD_ASSERT(sizeof(tv->tv_sec) <= sizeof(_PyTime_t));
...@@ -300,14 +346,35 @@ _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv, int raise) ...@@ -300,14 +346,35 @@ _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv, int raise)
_PyTime_overflow(); _PyTime_overflow();
} }
res = -1; res = -1;
t = (t > 0) ? _PyTime_MAX : _PyTime_MIN;
} }
else {
t = t * SEC_TO_NS; t = t * SEC_TO_NS;
}
t += (_PyTime_t)tv->tv_usec * US_TO_NS; usec = (_PyTime_t)tv->tv_usec * US_TO_NS;
/* The following test is written for positive only usec */
assert(usec >= 0);
if (t > _PyTime_MAX - usec) {
if (raise) {
_PyTime_overflow();
}
res = -1;
t = _PyTime_MAX;
}
else {
t += usec;
}
*tp = t; *tp = t;
return res; return res;
} }
int
_PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv)
{
return pytime_fromtimeval(tp, tv, 1);
}
#endif #endif
static int static int
...@@ -632,7 +699,7 @@ pygettimeofday(_PyTime_t *tp, _Py_clock_info_t *info, int raise) ...@@ -632,7 +699,7 @@ pygettimeofday(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
} }
return -1; return -1;
} }
if (_PyTime_FromTimespec(tp, &ts, raise) < 0) { if (pytime_fromtimespec(tp, &ts, raise) < 0) {
return -1; return -1;
} }
...@@ -662,7 +729,7 @@ pygettimeofday(_PyTime_t *tp, _Py_clock_info_t *info, int raise) ...@@ -662,7 +729,7 @@ pygettimeofday(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
} }
return -1; return -1;
} }
if (_PyTime_FromTimeval(tp, &tv, raise) < 0) { if (pytime_fromtimeval(tp, &tv, raise) < 0) {
return -1; return -1;
} }
...@@ -841,7 +908,7 @@ pymonotonic(_PyTime_t *tp, _Py_clock_info_t *info, int raise) ...@@ -841,7 +908,7 @@ pymonotonic(_PyTime_t *tp, _Py_clock_info_t *info, int raise)
} }
info->resolution = res.tv_sec + res.tv_nsec * 1e-9; info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
} }
if (_PyTime_FromTimespec(tp, &ts, raise) < 0) { if (pytime_fromtimespec(tp, &ts, raise) < 0) {
return -1; return -1;
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment