Issue #10278: Add an optional strict argument to time.steady(), False by default

This commit is contained in:
Victor Stinner 2012-03-15 01:17:09 +01:00
parent ec919cc74d
commit 071eca3f5c
3 changed files with 57 additions and 18 deletions

View File

@ -226,7 +226,7 @@ The module defines the following functions and data items:
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:: steady() .. function:: steady(strict=False)
.. index:: .. index::
single: benchmarking single: benchmarking
@ -236,6 +236,11 @@ The module defines the following functions and data items:
adjusted. The reference point of the returned value is undefined so only the adjusted. The reference point of the returned value is undefined so only the
difference of consecutive calls is valid. difference of consecutive calls is valid.
If available, a monotonic clock is used. By default, if *strict* is False,
the function falls back to another clock if the monotonic clock failed or is
not available. If *strict* is True, raise an :exc:`OSError` on error or
:exc:`NotImplementedError` if no monotonic clock is available.
.. versionadded:: 3.3 .. versionadded:: 3.3

View File

@ -340,6 +340,16 @@ class TimeTestCase(unittest.TestCase):
self.assertGreater(t2, t1) self.assertGreater(t2, t1)
self.assertAlmostEqual(dt, 0.1, delta=0.2) self.assertAlmostEqual(dt, 0.1, delta=0.2)
def test_steady_strict(self):
try:
t1 = time.steady(strict=True)
except OSError as err:
self.skipTest("the monotonic clock failed: %s" % err)
except NotImplementedError:
self.skipTest("no monotonic clock available")
t2 = time.steady(strict=True)
self.assertGreaterEqual(t2, t1)
def test_localtime_failure(self): def test_localtime_failure(self):
# Issue #13847: check for localtime() failure # Issue #13847: check for localtime() failure
invalid_time_t = None invalid_time_t = None

View File

@ -45,18 +45,12 @@
/* Forward declarations */ /* Forward declarations */
static int floatsleep(double); static int floatsleep(double);
static double floattime(void); static PyObject* floattime(void);
static PyObject * static PyObject *
time_time(PyObject *self, PyObject *unused) time_time(PyObject *self, PyObject *unused)
{ {
double secs; return floattime();
secs = floattime();
if (secs == 0.0) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
return PyFloat_FromDouble(secs);
} }
PyDoc_STRVAR(time_doc, PyDoc_STRVAR(time_doc,
@ -768,11 +762,11 @@ the local timezone used by methods such as localtime, but this behaviour\n\
should not be relied on."); should not be relied on.");
#endif /* HAVE_WORKING_TZSET */ #endif /* HAVE_WORKING_TZSET */
static PyObject * static PyObject*
time_steady(PyObject *self, PyObject *unused) steady_clock(int strict)
{ {
#if defined(MS_WINDOWS) && !defined(__BORLANDC__) #if defined(MS_WINDOWS) && !defined(__BORLANDC__)
return win32_clock(1); return win32_clock(!strict);
#elif defined(__APPLE__) #elif defined(__APPLE__)
uint64_t time = mach_absolute_time(); uint64_t time = mach_absolute_time();
double secs; double secs;
@ -806,14 +800,37 @@ time_steady(PyObject *self, PyObject *unused)
if (Py_ARRAY_LENGTH(clk_ids) <= clk_index) if (Py_ARRAY_LENGTH(clk_ids) <= clk_index)
clk_index = -1; clk_index = -1;
} }
return time_time(self, NULL); if (strict) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
return floattime();
#else #else
return time_time(self, NULL); if (strict) {
PyErr_SetString(PyExc_NotImplementedError,
"no steady clock available on your platform");
return NULL;
}
return floattime();
#endif #endif
} }
static PyObject *
time_steady(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = {"strict", NULL};
int strict = 0;
if (!PyArg_ParseTupleAndKeywords(
args, kwargs, "|i:steady", kwlist,
&strict))
return NULL;
return steady_clock(strict);
}
PyDoc_STRVAR(steady_doc, PyDoc_STRVAR(steady_doc,
"steady() -> float\n\ "steady(strict=False) -> float\n\
\n\ \n\
Return the current time as a floating point number expressed in seconds.\n\ Return the current time as a floating point number expressed in seconds.\n\
This clock advances at a steady rate relative to real time and it may not\n\ This clock advances at a steady rate relative to real time and it may not\n\
@ -949,7 +966,8 @@ static PyMethodDef time_methods[] = {
#ifdef HAVE_MKTIME #ifdef HAVE_MKTIME
{"mktime", time_mktime, METH_O, mktime_doc}, {"mktime", time_mktime, METH_O, mktime_doc},
#endif #endif
{"steady", time_steady, METH_NOARGS, steady_doc}, {"steady", (PyCFunction)time_steady, METH_VARARGS|METH_KEYWORDS,
steady_doc},
#ifdef HAVE_STRFTIME #ifdef HAVE_STRFTIME
{"strftime", time_strftime, METH_VARARGS, strftime_doc}, {"strftime", time_strftime, METH_VARARGS, strftime_doc},
#endif #endif
@ -1041,12 +1059,18 @@ PyInit_time(void)
return m; return m;
} }
static double static PyObject*
floattime(void) floattime(void)
{ {
_PyTime_timeval t; _PyTime_timeval t;
double secs;
_PyTime_gettimeofday(&t); _PyTime_gettimeofday(&t);
return (double)t.tv_sec + t.tv_usec*0.000001; secs = (double)t.tv_sec + t.tv_usec*0.000001;
if (secs == 0.0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
return PyFloat_FromDouble(secs);
} }