diff --git a/Modules/timemodule.c b/Modules/timemodule.c --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -40,6 +40,19 @@ #include #endif +#if (defined(MS_WINDOWS) && !defined(__BORLANDC__)) || defined(HAVE_CLOCK) +# define HAVE_PYCLOCK +#endif + +#ifdef HAVE_CLOCK_GETTIME +typedef struct timespec _PyTime_timespec; +#else +typedef struct { + time_t tv_sec; /* seconds since Jan. 1, 1970 */ + long tv_nsec; /* and nanoseconds */ +} _PyTime_timespec; +#endif + /* Forward declarations */ static int floatsleep(double); static double floattime(void); @@ -56,6 +69,7 @@ time_time(PyObject *self, PyObject *unus return PyFloat_FromDouble(secs); } + PyDoc_STRVAR(time_doc, "time() -> floating point number\n\ \n\ @@ -63,34 +77,49 @@ Return the current time in seconds since Fractions of a second may be present if the system clock provides them."); #if defined(MS_WINDOWS) && !defined(__BORLANDC__) +typedef LARGE_INTEGER pyclock_t; + /* 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) +static int +pyclock(pyclock_t *value, pyclock_t *divisor) { static LARGE_INTEGER ctrStart; - static double divisor = 0.0; + static LARGE_INTEGER cpu_frequency = 0; LARGE_INTEGER now; double diff; - if (divisor == 0.0) { + if (cpu_frequency == 0) { LARGE_INTEGER freq; QueryPerformanceCounter(&ctrStart); - if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) { + if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) + { /* Unlikely to happen - this works on all intel machines at least! Revert to clock() */ - return PyFloat_FromDouble(((double)clock()) / - CLOCKS_PER_SEC); + clock_t processor_time; + processor_time = clock(); + if (processor_time == (clock_t)-1) { + PyErr_SetString(PyExc_RuntimeError, + "the processor time used is not available " + "or its value cannot be represented"); + return -1; + } + *value = processor_time; + *divisor = CLOCKS_PER_SEC; + return 0; } - divisor = (double)freq.QuadPart; + cpu_frequency = freq.QuadPart; } QueryPerformanceCounter(&now); - diff = (double)(now.QuadPart - ctrStart.QuadPart); - return PyFloat_FromDouble(diff / divisor); + *value = now.QuadPart - ctrStart.QuadPart; + *divisor = cpu_frequency; + return 0; } #elif defined(HAVE_CLOCK) +typedef clock_t pyclock_t; + #ifndef CLOCKS_PER_SEC #ifdef CLK_TCK #define CLOCKS_PER_SEC CLK_TCK @@ -99,13 +128,33 @@ time_clock(PyObject *self, PyObject *unu #endif #endif +static int +pyclock(pyclock_t *value, pyclock_t *divisor) +{ + clock_t processor_time; + processor_time = clock(); + if (processor_time == (clock_t)-1) { + PyErr_SetString(PyExc_RuntimeError, + "the processor time used is not available " + "or its value cannot be represented"); + return -1; + } + *value = processor_time; + *divisor = CLOCKS_PER_SEC; + return 0; +} +#endif /* HAVE_CLOCK */ + +#ifdef HAVE_PYCLOCK static PyObject * time_clock(PyObject *self, PyObject *unused) { - return PyFloat_FromDouble(((double)clock()) / CLOCKS_PER_SEC); + pyclock_t value, divisor; + if (pyclock(&value, &divisor)) + return NULL; + return PyFloat_FromDouble((double)value / (double)divisor); } -#endif /* HAVE_CLOCK */ - +#endif #ifdef HAVE_CLOCK PyDoc_STRVAR(clock_doc, @@ -737,12 +786,28 @@ the local timezone used by methods such should not be relied on."); #endif /* HAVE_WORKING_TZSET */ -static PyObject * -time_wallclock(PyObject *self, PyObject *unused) +static int +pywallclock(_PyTime_timespec *ts) { #if defined(MS_WINDOWS) && !defined(__BORLANDC__) - return time_clock(self, NULL); -#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + pyclock_t value, divisor; + unsigned long k; +#define NANOSEC 1000000000 + if (pyclock(&value, &divisor)) + return -1; + ts->tv_sec = value / divisor; + if (NANOSEC >= divisor) { + k = NANOSEC / divisor; + ts->tv_nsec = (value % divisor) * k; + } + else { + k = divisor / NANOSEC; + ts->tv_nsec = (value % divisor) / k; + } + return 0; +#else + +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) static int clk_index = 0; clockid_t clk_ids[] = { #ifdef CLOCK_MONOTONIC_RAW @@ -762,18 +827,34 @@ time_wallclock(PyObject *self, PyObject 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); + { + ts->tv_sec = tp.tv_sec; + ts->tv_nsec = tp.tv_nsec; + return 0; + } clk_index++; if (Py_ARRAY_LENGTH(clk_ids) <= clk_index) clk_index = -1; } - return time_time(self, NULL); -#else - return time_time(self, NULL); +#endif /* defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) */ + _PyTime_timeval t; + _PyTime_gettimeofday(&t); + ts->tv_sec = t.tv_sec; + ts->tv_nsec = t.tv_usec * 1000; + return 0; #endif } +static PyObject * +time_wallclock(PyObject *self, PyObject *unused) +{ + _PyTime_timespec ts; + if (pywallclock(&ts)) + return NULL; + return PyFloat_FromDouble(ts.tv_sec + ts.tv_nsec * 1e-9); +} + PyDoc_STRVAR(wallclock_doc, "wallclock() -> float\n\ \n\ @@ -894,7 +975,7 @@ PyInit_timezone(PyObject *m) { static PyMethodDef time_methods[] = { {"time", time_time, METH_NOARGS, time_doc}, -#if (defined(MS_WINDOWS) && !defined(__BORLANDC__)) || defined(HAVE_CLOCK) +#ifdef HAVE_PYCLOCK {"clock", time_clock, METH_NOARGS, clock_doc}, #endif #ifdef HAVE_CLOCK_GETTIME