* ``'monotonic'``: :func:`time.monotonic`
* ``'perf_counter'``: :func:`time.perf_counter`
* ``'process_time'``: :func:`time.process_time`
+ * ``'thread_time'``: :func:`time.thread_time`
* ``'time'``: :func:`time.time`
The result has the following attributes:
of the calendar date may be accessed as attributes.
+.. function:: thread_time() -> float
+
+ .. index::
+ single: CPU time
+ single: processor time
+ single: benchmarking
+
+ Return the value (in fractional seconds) of the sum of the system and user
+ CPU time of the current thread. It does not include time elapsed during
+ sleep. It is thread-specific by definition. The reference point of the
+ returned value is undefined, so that only the difference between the results
+ of consecutive calls in the same thread is valid.
+
+ Availability: Windows, Linux, Unix systems supporting
+ ``CLOCK_THREAD_CPUTIME_ID``.
+
+ .. versionadded:: 3.7
+
+
+.. function:: thread_time_ns() -> int
+
+ Similar to :func:`thread_time` but return time as nanoseconds.
+
+ .. versionadded:: 3.7
+
+
.. function:: time_ns() -> int
Similar to :func:`time` but returns time as an integer number of nanoseconds
)
+def busy_wait(duration):
+ deadline = time.monotonic() + duration
+ while time.monotonic() < deadline:
+ pass
+
+
class TimeTestCase(unittest.TestCase):
def setUp(self):
check_ns(time.process_time(),
time.process_time_ns())
+ if hasattr(time, 'thread_time'):
+ check_ns(time.thread_time(),
+ time.thread_time_ns())
+
if hasattr(time, 'clock_gettime'):
check_ns(time.clock_gettime(time.CLOCK_REALTIME),
time.clock_gettime_ns(time.CLOCK_REALTIME))
# on Windows
self.assertLess(stop - start, 0.020)
+ # process_time() should include CPU time spent in any thread
+ start = time.process_time()
+ busy_wait(0.100)
+ stop = time.process_time()
+ self.assertGreaterEqual(stop - start, 0.020) # machine busy?
+
+ t = threading.Thread(target=busy_wait, args=(0.100,))
+ start = time.process_time()
+ t.start()
+ t.join()
+ stop = time.process_time()
+ self.assertGreaterEqual(stop - start, 0.020) # machine busy?
+
info = time.get_clock_info('process_time')
self.assertTrue(info.monotonic)
self.assertFalse(info.adjustable)
+ def test_thread_time(self):
+ if not hasattr(time, 'thread_time'):
+ if sys.platform.startswith(('linux', 'win')):
+ self.fail("time.thread_time() should be available on %r"
+ % (sys.platform,))
+ else:
+ self.skipTest("need time.thread_time")
+
+ # thread_time() should not include time spend during a sleep
+ start = time.thread_time()
+ time.sleep(0.100)
+ stop = time.thread_time()
+ # use 20 ms because thread_time() has usually a resolution of 15 ms
+ # on Windows
+ self.assertLess(stop - start, 0.020)
+
+ # thread_time() should include CPU time spent in current thread...
+ start = time.thread_time()
+ busy_wait(0.100)
+ stop = time.thread_time()
+ self.assertGreaterEqual(stop - start, 0.020) # machine busy?
+
+ # ...but not in other threads
+ t = threading.Thread(target=busy_wait, args=(0.100,))
+ start = time.thread_time()
+ t.start()
+ t.join()
+ stop = time.thread_time()
+ self.assertLess(stop - start, 0.020)
+
+ info = time.get_clock_info('thread_time')
+ self.assertTrue(info.monotonic)
+ self.assertFalse(info.adjustable)
+
@unittest.skipUnless(hasattr(time, 'clock_settime'),
'need time.clock_settime')
def test_monotonic_settime(self):
sum of the kernel and user-space CPU time.");
+#if defined(MS_WINDOWS)
+#define HAVE_THREAD_TIME
+static int
+_PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
+{
+ HANDLE thread;
+ FILETIME creation_time, exit_time, kernel_time, user_time;
+ ULARGE_INTEGER large;
+ _PyTime_t ktime, utime, t;
+ BOOL ok;
+
+ thread = GetCurrentThread();
+ ok = GetThreadTimes(thread, &creation_time, &exit_time,
+ &kernel_time, &user_time);
+ if (!ok) {
+ PyErr_SetFromWindowsErr(0);
+ return -1;
+ }
+
+ if (info) {
+ info->implementation = "GetThreadTimes()";
+ info->resolution = 1e-7;
+ info->monotonic = 1;
+ info->adjustable = 0;
+ }
+
+ 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;
+}
+
+#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
+#define HAVE_THREAD_TIME
+static int
+_PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
+{
+ struct timespec ts;
+ const clockid_t clk_id = CLOCK_THREAD_CPUTIME_ID;
+ const char *function = "clock_gettime(CLOCK_THREAD_CPUTIME_ID)";
+
+ if (clock_gettime(clk_id, &ts)) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return -1;
+ }
+ if (info) {
+ struct timespec res;
+ info->implementation = function;
+ info->monotonic = 1;
+ info->adjustable = 0;
+ if (clock_getres(clk_id, &res)) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return -1;
+ }
+ info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
+ }
+
+ if (_PyTime_FromTimespec(tp, &ts) < 0) {
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+#ifdef HAVE_THREAD_TIME
+static PyObject *
+time_thread_time(PyObject *self, PyObject *unused)
+{
+ _PyTime_t t;
+ if (_PyTime_GetThreadTimeWithInfo(&t, NULL) < 0) {
+ return NULL;
+ }
+ return _PyFloat_FromPyTime(t);
+}
+
+PyDoc_STRVAR(thread_time_doc,
+"thread_time() -> float\n\
+\n\
+Thread time for profiling: sum of the kernel and user-space CPU time.");
+
+static PyObject *
+time_thread_time_ns(PyObject *self, PyObject *unused)
+{
+ _PyTime_t t;
+ if (_PyTime_GetThreadTimeWithInfo(&t, NULL) < 0) {
+ return NULL;
+ }
+ return _PyTime_AsNanosecondsObject(t);
+}
+
+PyDoc_STRVAR(thread_time_ns_doc,
+"thread_time() -> int\n\
+\n\
+Thread time for profiling as nanoseconds:\n\
+sum of the kernel and user-space CPU time.");
+#endif
+
+
static PyObject *
time_get_clock_info(PyObject *self, PyObject *args)
{
return NULL;
}
}
+#ifdef HAVE_THREAD_TIME
+ else if (strcmp(name, "thread_time") == 0) {
+ if (_PyTime_GetThreadTimeWithInfo(&t, &info) < 0) {
+ return NULL;
+ }
+ }
+#endif
else {
PyErr_SetString(PyExc_ValueError, "unknown clock");
return NULL;
{"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},
+#ifdef HAVE_THREAD_TIME
+ {"thread_time", time_thread_time, METH_NOARGS, thread_time_doc},
+ {"thread_time_ns", time_thread_time_ns, METH_NOARGS, thread_time_ns_doc},
+#endif
{"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},