diff options
author | Victor Stinner <victor.stinner@haypocalc.com> | 2012-02-07 22:29:46 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@haypocalc.com> | 2012-02-07 22:29:46 (GMT) |
commit | 8b30201f7d3028628aba1b4bec203a7b507de73b (patch) | |
tree | d28e1a3a7c771de2bc700e012272b9dfbe2f1417 | |
parent | d1cd99b533a32e063fc4602c439da334d5a10331 (diff) | |
download | cpython-8b30201f7d3028628aba1b4bec203a7b507de73b.zip cpython-8b30201f7d3028628aba1b4bec203a7b507de73b.tar.gz cpython-8b30201f7d3028628aba1b4bec203a7b507de73b.tar.bz2 |
Issue #13846: Add time.monotonic(), monotonic clock.
-rw-r--r-- | Doc/library/time.rst | 8 | ||||
-rw-r--r-- | Lib/test/test_time.py | 18 | ||||
-rw-r--r-- | Misc/NEWS | 2 | ||||
-rw-r--r-- | Modules/timemodule.c | 82 |
4 files changed, 94 insertions, 16 deletions
diff --git a/Doc/library/time.rst b/Doc/library/time.rst index 0415a16..7865b5a 100644 --- a/Doc/library/time.rst +++ b/Doc/library/time.rst @@ -226,6 +226,14 @@ The module defines the following functions and data items: The earliest date for which it can generate a time is platform-dependent. +.. function:: monotonic() + + Monotonic clock. The reference point of the returned value is undefined so + only the difference of consecutive calls is valid. + + .. versionadded: 3.3 + + .. function:: sleep(secs) Suspend execution for the given number of seconds. The argument may be a diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index f299266..a89c511 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -331,16 +331,32 @@ class TimeTestCase(unittest.TestCase): pass self.assertEqual(time.strftime('%Z', tt), tzname) + @unittest.skipUnless(hasattr(time, 'monotonic'), + 'need time.monotonic()') + def test_monotonic(self): + t1 = time.monotonic() + t2 = time.monotonic() + self.assertGreaterEqual(t2, t1) + + t1 = time.monotonic() + time.sleep(0.1) + t2 = time.monotonic() + dt = t2 - t1 + self.assertGreater(t2, t1) + self.assertAlmostEqual(dt, 0.1, delta=0.2) + def test_wallclock(self): t1 = time.wallclock() t2 = time.wallclock() + # may fail if the system clock was changed self.assertGreaterEqual(t2, t1) t1 = time.wallclock() time.sleep(0.1) t2 = time.wallclock() - self.assertGreater(t2, t1) dt = t2 - t1 + # may fail if the system clock was changed + self.assertGreater(t2, t1) self.assertAlmostEqual(dt, 0.1, delta=0.2) def test_localtime_failure(self): @@ -466,6 +466,8 @@ Core and Builtins Library ------- +- Issue #13846: Add time.monotonic(), monotonic clock. + - Issue #10811: Fix recursive usage of cursors. Instead of crashing, raise a ProgrammingError now. diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 30a01f5..34c7019 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -91,39 +91,44 @@ pyclock(void) /* Win32 has better clock replacement; we have our own version, due to Mark Hammond and Tim Peters */ static PyObject * -time_clock(PyObject *self, PyObject *unused) +win32_clock(int fallback) { - static LARGE_INTEGER ctrStart; - static double divisor = 0.0; + static LONGLONG cpu_frequency = 0; + static LONGLONG ctrStart; LARGE_INTEGER now; double diff; - if (divisor == 0.0) { + if (cpu_frequency == 0) { LARGE_INTEGER freq; - QueryPerformanceCounter(&ctrStart); + QueryPerformanceCounter(&now); + ctrStart = now.QuadPart; if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) { /* Unlikely to happen - this works on all intel machines at least! Revert to clock() */ - return pyclock(); + if (fallback) + return pyclock(); + else + return PyErr_SetFromWindowsErr(0); } - divisor = (double)freq.QuadPart; + cpu_frequency = freq.QuadPart; } QueryPerformanceCounter(&now); - diff = (double)(now.QuadPart - ctrStart.QuadPart); - return PyFloat_FromDouble(diff / divisor); + diff = (double)(now.QuadPart - ctrStart); + return PyFloat_FromDouble(diff / (double)cpu_frequency); } +#endif -#elif defined(HAVE_CLOCK) - +#if (defined(MS_WINDOWS) && !defined(__BORLANDC__)) || defined(HAVE_CLOCK) static PyObject * time_clock(PyObject *self, PyObject *unused) { +#if defined(MS_WINDOWS) && !defined(__BORLANDC__) + return win32_clock(1); +#else return pyclock(); +#endif } -#endif /* HAVE_CLOCK */ - -#ifdef HAVE_CLOCK PyDoc_STRVAR(clock_doc, "clock() -> floating point number\n\ \n\ @@ -767,7 +772,7 @@ static PyObject * time_wallclock(PyObject *self, PyObject *unused) { #if defined(MS_WINDOWS) && !defined(__BORLANDC__) - return time_clock(self, NULL); + return win32_clock(1); #elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) static int clk_index = 0; clockid_t clk_ids[] = { @@ -809,6 +814,50 @@ required, i.e. when \"processor time\" is inappropriate. The reference point\n\ of the returned value is undefined so only the difference of consecutive\n\ calls is valid."); +#if (defined(MS_WINDOWS) && !defined(__BORLANDC__)) \ + || (defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)) +# define HAVE_PYTIME_MONOTONIC +#endif + +#ifdef HAVE_PYTIME_MONOTONIC +static PyObject * +time_monotonic(PyObject *self, PyObject *unused) +{ +#if defined(MS_WINDOWS) && !defined(__BORLANDC__) + return win32_clock(0); +#else + static int clk_index = 0; + clockid_t clk_ids[] = { +#ifdef CLOCK_MONOTONIC_RAW + CLOCK_MONOTONIC_RAW, +#endif + CLOCK_MONOTONIC + }; + int ret; + struct timespec tp; + + while (0 <= clk_index) { + clockid_t clk_id = clk_ids[clk_index]; + ret = clock_gettime(clk_id, &tp); + if (ret == 0) + return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); + + clk_index++; + if (Py_ARRAY_LENGTH(clk_ids) <= clk_index) + clk_index = -1; + } + PyErr_SetFromErrno(PyExc_OSError); + return NULL; +#endif +} + +PyDoc_STRVAR(monotonic_doc, +"monotonic() -> float\n\ +\n\ +Monotonic clock. The reference point of the returned value is undefined so\n\ +only the difference of consecutive calls is valid."); +#endif + static void PyInit_timezone(PyObject *m) { /* This code moved from PyInit_time wholesale to allow calling it from @@ -937,6 +986,9 @@ static PyMethodDef time_methods[] = { #ifdef HAVE_MKTIME {"mktime", time_mktime, METH_O, mktime_doc}, #endif +#ifdef HAVE_PYTIME_MONOTONIC + {"monotonic", time_monotonic, METH_NOARGS, monotonic_doc}, +#endif #ifdef HAVE_STRFTIME {"strftime", time_strftime, METH_VARARGS, strftime_doc}, #endif |