diff -r 66bd85bcf916 -r aac59a3c11ef Doc/c-api/exceptions.rst --- a/Doc/c-api/exceptions.rst Tue Apr 17 19:14:26 2012 -0400 +++ b/Doc/c-api/exceptions.rst Wed Apr 18 01:15:52 2012 +0200 @@ -229,12 +229,27 @@ Similar to :c:func:`PyErr_SetFromWindowsErrWithFilename`, with an additional parameter specifying the exception type to be raised. Availability: Windows. -.. c:function:: PyObject* PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path) +.. c:function:: PyObject* PyErr_SetExcWithArgsKwargs(PyObject *exc, PyObject *args, PyObject *kwargs) + + This is a convenience function to set an *exc* with the given *args* and + *kwargs* values. If *args* is ``NULL``, an empty :func:`tuple` will be + created when *exc* is created via :c:func:`PyObject_Call`. + + .. versionadded:: 3.3 + +.. c:function:: PyObject* PyErr_SetFromImportErrorWithName(PyObject *msg, PyObject *name) This is a convenience function to raise :exc:`ImportError`. *msg* will be - set as the exception's message string. *name* and *path*, both of which can - be ``NULL``, will be set as the :exc:`ImportError`'s respective ``name`` - and ``path`` attributes. + set as the exception's message string, and *name* will be set as the + :exc:`ImportError`'s ``name`` attribute. + + .. versionadded:: 3.3 + +.. c:function:: PyObject* PyErr_SetFromImportErrorWithNameAndPath(PyObject *msg, PyObject *name, PyObject *path) + + This is a convenience function to raise :exc:`ImportError`. *msg* will be + set as the exception's message string. Both *name* and *path* will be set + as the :exc:`ImportError`'s respective ``name`` and ``path`` attributes. .. versionadded:: 3.3 diff -r 66bd85bcf916 -r aac59a3c11ef Doc/library/time.rst --- a/Doc/library/time.rst Tue Apr 17 19:14:26 2012 -0400 +++ b/Doc/library/time.rst Wed Apr 18 01:15:52 2012 +0200 @@ -220,6 +220,33 @@ Nonzero if a DST timezone is defined. +.. function:: get_clock_info(name) + + Get information of the specified clock. Supported clocks: + + * ``'clock'``: :func:`time.clock` + * ``'monotonic'``: :func:`time.monotonic` + * ``'perf_counter'``: :func:`time.perf_counter` + * ``'process_time'``: :func:`time.process_time` + * ``'time'``: :func:`time.time` + + Return a dictionary with the following keys: + + * Mandatory keys + + * ``'function'`` (:class:`str`): name of the underlying C function used + to get the clock value + * ``'is_monotonic'`` (:class:`bool`): ``True`` if the clock cannot go + backward, ``False`` otherwise + * ``'resolution'`` (:class:`float`): Resolution of the clock in seconds + + * Optional keys + + * ``'precision'`` (:class:`float`): Precision of the clock in seconds + * ``'is_adjusted'`` (:class:`bool`): ``True`` if the clock can be + adjusted (e.g. by a NTP daemon) + + .. function:: gmtime([secs]) Convert a time expressed in seconds since the epoch to a :class:`struct_time` in @@ -249,20 +276,35 @@ The earliest date for which it can generate a time is platform-dependent. -.. function:: steady(strict=False) +.. function:: monotonic() - .. index:: - single: benchmarking + Monotonic clock, cannot go backward. Return the current time as a floating + point number expressed in seconds. The reference point of the returned + value is undefined so only the difference of consecutive calls is valid. - Return the current time as a floating point number expressed in seconds. - This clock advances at a steady rate relative to real time and it may not be - adjusted. The reference point of the returned value is undefined so only the - difference of consecutive calls is valid. + Availability: Windows, Mac OS X, Unix. - If available, a monotonic clock is used. By default, - 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 + + +.. function:: perf_counter() + + Performance counter for benchmarking. It is monotonic, i.e. cannot go + backward. It does include time elapsed during sleep. The reference point of + the returned value is undefined, so that only the difference between the + results of consecutive calls is valid and is number of seconds. + + Availability: Windows, Mac OS X, Unix. + + .. versionadded:: 3.3 + + +.. function:: process_time() + + Process time for profiling: sum of the kernel and user-space CPU time. + It does not include time elapsed during sleep. The reference point of the + returned value is undefined, so that only the difference between the + results of consecutive calls is valid. .. versionadded:: 3.3 diff -r 66bd85bcf916 -r aac59a3c11ef Include/pyerrors.h --- a/Include/pyerrors.h Tue Apr 17 19:14:26 2012 -0400 +++ b/Include/pyerrors.h Wed Apr 18 01:15:52 2012 +0200 @@ -265,8 +265,9 @@ PyAPI_FUNC(PyObject *) PyErr_SetExcWithArgsKwargs(PyObject *, PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyErr_SetImportError(PyObject *, PyObject *, - PyObject *); +PyAPI_FUNC(PyObject *) PyErr_SetFromImportErrorWithNameAndPath(PyObject *, + PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyErr_SetFromImportErrorWithName(PyObject *, PyObject *); /* Export the old function so that the existing API remains available: */ PyAPI_FUNC(void) PyErr_BadInternalCall(void); diff -r 66bd85bcf916 -r aac59a3c11ef Include/pytime.h --- a/Include/pytime.h Tue Apr 17 19:14:26 2012 -0400 +++ b/Include/pytime.h Wed Apr 18 01:15:52 2012 +0200 @@ -22,11 +22,28 @@ } _PyTime_timeval; #endif +/* Structure used by time.get_clock_info() */ +typedef struct { + /* mandatory */ + const char *implementation; + double resolution; + int is_monotonic; + /* optional */ + double precision; /* -1.0 if unknown */ + int is_adjusted; /* -1 if unknown */ +} _Py_clock_info_t; + /* Similar to POSIX gettimeofday but cannot fail. If system gettimeofday * fails or is not available, fall back to lower resolution clocks. */ PyAPI_FUNC(void) _PyTime_gettimeofday(_PyTime_timeval *tp); +/* Similar to _PyTime_gettimeofday() but retrieve also information on the + * clock used to get the current time. */ +PyAPI_FUNC(void) _PyTime_gettimeofday_info( + _PyTime_timeval *tp, + _Py_clock_info_t *info); + #define _PyTime_ADD_SECONDS(tv, interval) \ do { \ tv.tv_usec += (long) (((long) interval - interval) * 1000000); \ diff -r 66bd85bcf916 -r aac59a3c11ef Lib/imp.py --- a/Lib/imp.py Tue Apr 17 19:14:26 2012 -0400 +++ b/Lib/imp.py Wed Apr 18 01:15:52 2012 +0200 @@ -14,7 +14,7 @@ from _imp import (get_magic, get_tag, get_suffixes, cache_from_source, source_from_cache) # Should be re-implemented here (and mostly deprecated) -from _imp import (find_module, NullImporter, +from _imp import (find_module, load_compiled, NullImporter, SEARCH_ERROR, PY_SOURCE, PY_COMPILED, C_EXTENSION, PY_RESOURCE, PKG_DIRECTORY, C_BUILTIN, PY_FROZEN, PY_CODERESOURCE, IMP_HOOK) @@ -25,17 +25,17 @@ import os -class _HackedGetData: +class _LoadSourceCompatibility(_bootstrap._SourceFileLoader): - """Compatibiilty support for 'file' arguments of various load_*() - functions.""" + """Compatibility support for implementing load_source().""" def __init__(self, fullname, path, file=None): super().__init__(fullname, path) self.file = file def get_data(self, path): - """Gross hack to contort loader to deal w/ load_*()'s bad API.""" + """Gross hack to contort SourceFileLoader to deal w/ load_source()'s bad + API.""" if self.file and path == self._path: with self.file: # Technically should be returning bytes, but @@ -48,25 +48,10 @@ return super().get_data(path) -class _LoadSourceCompatibility(_HackedGetData, _bootstrap._SourceFileLoader): - - """Compatibility support for implementing load_source().""" - - def load_source(name, pathname, file=None): return _LoadSourceCompatibility(name, pathname, file).load_module(name) -class _LoadCompiledCompatibility(_HackedGetData, - _bootstrap._SourcelessFileLoader): - - """Compatibility support for implementing load_compiled().""" - - -def load_compiled(name, pathname, file=None): - return _LoadCompiledCompatibility(name, pathname, file).load_module(name) - - def load_package(name, path): if os.path.isdir(path): extensions = _bootstrap._suffix_list(PY_SOURCE) diff -r 66bd85bcf916 -r aac59a3c11ef Lib/importlib/test/import_/test_relative_imports.py --- a/Lib/importlib/test/import_/test_relative_imports.py Tue Apr 17 19:14:26 2012 -0400 +++ b/Lib/importlib/test/import_/test_relative_imports.py Wed Apr 18 01:15:52 2012 +0200 @@ -203,11 +203,6 @@ self.assertEqual(mod.__name__, 'crash.mod') self.relative_import_test(create, globals_, callback) - def test_relative_import_no_globals(self): - # No globals for a relative import is an error. - with self.assertRaises(KeyError): - import_util.import_('sys', level=1) - def test_main(): from test.support import run_unittest diff -r 66bd85bcf916 -r aac59a3c11ef Lib/queue.py --- a/Lib/queue.py Tue Apr 17 19:14:26 2012 -0400 +++ b/Lib/queue.py Wed Apr 18 01:15:52 2012 +0200 @@ -6,7 +6,10 @@ import dummy_threading as threading from collections import deque from heapq import heappush, heappop -from time import steady as time +try: + from time import monotonic as time +except ImportError: + from time import time __all__ = ['Empty', 'Full', 'Queue', 'PriorityQueue', 'LifoQueue'] diff -r 66bd85bcf916 -r aac59a3c11ef Lib/test/test_time.py --- a/Lib/test/test_time.py Tue Apr 17 19:14:26 2012 -0400 +++ b/Lib/test/test_time.py Wed Apr 18 01:15:52 2012 +0200 @@ -5,6 +5,10 @@ import sysconfig import sys import platform +try: + import threading +except ImportError: + threading = None # Max year is only limited by the size of C int. SIZEOF_INT = sysconfig.get_config_var('SIZEOF_INT') or 4 @@ -56,7 +60,9 @@ except PermissionError: pass - self.assertRaises(OSError, time.clock_settime, time.CLOCK_MONOTONIC, 0) + if hasattr(time, 'CLOCK_MONOTONIC'): + self.assertRaises(OSError, + time.clock_settime, time.CLOCK_MONOTONIC, 0) def test_conversions(self): self.assertEqual(time.ctime(self.t), @@ -342,23 +348,63 @@ pass self.assertEqual(time.strftime('%Z', tt), tzname) - def test_steady(self): - t1 = time.steady() + @unittest.skipUnless(hasattr(time, 'monotonic'), + 'need time.monotonic') + def test_monotonic(self): + t1 = time.monotonic() time.sleep(0.1) - t2 = time.steady() + t2 = time.monotonic() 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_steady_strict(self): + info = time.get_clock_info('monotonic') + self.assertEqual(info['is_monotonic'], True) + if sys.platform == 'linux': + self.assertEqual(info['is_adjusted'], True) + + def test_perf_counter(self): + time.perf_counter() + + def test_process_time(self): + start = time.process_time() + time.sleep(0.1) + stop = time.process_time() + self.assertLess(stop - start, 0.01) + + @unittest.skipUnless(threading, + 'need threading') + def test_process_time_threads(self): + class BusyThread(threading.Thread): + def run(self): + while not self.stop: + pass + + thread = BusyThread() + thread.stop = False + t1 = time.process_time() + thread.start() + time.sleep(0.1) + t2 = time.process_time() + thread.stop = True + thread.join() + self.assertGreater(t2 - t1, 0.09) + + @unittest.skipUnless(hasattr(time, 'monotonic'), + 'need time.monotonic') + @unittest.skipUnless(hasattr(time, 'clock_settime'), + 'need time.clock_settime') + def test_monotonic_settime(self): + t1 = time.monotonic() + realtime = time.clock_gettime(time.CLOCK_REALTIME) + # jump backward with an offset of 1 hour 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) + time.clock_settime(time.CLOCK_REALTIME, realtime - 3600) + except PermissionError as err: + self.skipTest(err) + t2 = time.monotonic() + time.clock_settime(time.CLOCK_REALTIME, realtime) + # monotonic must not be affected by system clock updates self.assertGreaterEqual(t2, t1) def test_localtime_failure(self): @@ -378,6 +424,32 @@ self.assertRaises(OSError, time.localtime, invalid_time_t) self.assertRaises(OSError, time.ctime, invalid_time_t) + def test_get_clock_info(self): + clocks = ['clock', 'perf_counter', 'process_time', 'time'] + if hasattr(time, 'monotonic'): + clocks.append('monotonic') + + for name in clocks: + info = time.get_clock_info(name) + self.assertIsInstance(info, dict) + self.assertIsInstance(info['implementation'], str) + self.assertNotEqual(info['implementation'], '') + self.assertIsInstance(info['is_monotonic'], bool) + self.assertIsInstance(info['resolution'], float) + # 0 < resolution <= 1.0 + self.assertGreater(info['resolution'], 0) + self.assertLessEqual(info['resolution'], 1) + if 'accuracy' in info: + self.assertIsInstance(info['accuracy'], float) + # 0 < accuracy <= 1.0 + self.assertGreater(info['accuracy'], 0) + self.assertLessEqual(info['accuracy'], 1) + if 'is_adjusted' in info: + self.assertIsInstance(info['is_adjusted'], bool) + + self.assertRaises(ValueError, time.get_clock_info, 'xxx') + + class TestLocale(unittest.TestCase): def setUp(self): self.oldloc = locale.setlocale(locale.LC_ALL) diff -r 66bd85bcf916 -r aac59a3c11ef Lib/threading.py --- a/Lib/threading.py Tue Apr 17 19:14:26 2012 -0400 +++ b/Lib/threading.py Wed Apr 18 01:15:52 2012 +0200 @@ -3,7 +3,11 @@ import sys as _sys import _thread -from time import steady as _time, sleep as _sleep +from time import sleep as _sleep +try: + from time import monotonic as _time +except ImportError: + from time import time as _time from traceback import format_exc as _format_exc from _weakrefset import WeakSet diff -r 66bd85bcf916 -r aac59a3c11ef Misc/NEWS --- a/Misc/NEWS Tue Apr 17 19:14:26 2012 -0400 +++ b/Misc/NEWS Wed Apr 18 01:15:52 2012 +0200 @@ -10,9 +10,6 @@ Core and Builtins ----------------- -- Issue #14592: Attempting a relative import w/o __package__ or __name__ set in - globals raises a KeyError. - - Issue #10854: The ImportError raised when an extension module on Windows fails to import now uses the new path and name attributes from Issue #1559549. diff -r 66bd85bcf916 -r aac59a3c11ef Modules/timemodule.c --- a/Modules/timemodule.c Tue Apr 17 19:14:26 2012 -0400 +++ b/Modules/timemodule.c Wed Apr 18 01:15:52 2012 +0200 @@ -4,9 +4,17 @@ #include +#ifdef HAVE_SYS_TIMES_H +#include +#endif + #ifdef HAVE_SYS_TYPES_H #include -#endif /* HAVE_SYS_TYPES_H */ +#endif + +#if defined(HAVE_SYS_RESOURCE_H) +#include +#endif #ifdef QUICKWIN #include @@ -45,12 +53,16 @@ /* Forward declarations */ static int floatsleep(double); -static PyObject* floattime(void); +static PyObject* floattime(_Py_clock_info_t *info); + +#ifdef MS_WINDOWS +static OSVERSIONINFOEX winver; +#endif static PyObject * time_time(PyObject *self, PyObject *unused) { - return floattime(); + return floattime(NULL); } PyDoc_STRVAR(time_doc, @@ -70,7 +82,7 @@ #endif static PyObject * -pyclock(void) +floatclock(_Py_clock_info_t *info) { clock_t value; value = clock(); @@ -80,15 +92,23 @@ "or its value cannot be represented"); return NULL; } + if (info) { + info->implementation = "clock()"; + info->resolution = 1.0 / (double)CLOCKS_PER_SEC; + info->precision = info->resolution; + info->is_monotonic = 1; + info->is_adjusted = 0; + } return PyFloat_FromDouble((double)value / CLOCKS_PER_SEC); } #endif /* HAVE_CLOCK */ #if defined(MS_WINDOWS) && !defined(__BORLANDC__) +#define WIN32_PERF_COUNTER /* Win32 has better clock replacement; we have our own version, due to Mark Hammond and Tim Peters */ -static PyObject * -win32_clock(int fallback) +static int +win_perf_counter(_Py_clock_info_t *info, PyObject **result) { static LONGLONG cpu_frequency = 0; static LONGLONG ctrStart; @@ -102,28 +122,42 @@ if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) { /* Unlikely to happen - this works on all intel machines at least! Revert to clock() */ - if (fallback) - return pyclock(); - else - return PyErr_SetFromWindowsErr(0); + *result = NULL; + return -1; } cpu_frequency = freq.QuadPart; } QueryPerformanceCounter(&now); diff = (double)(now.QuadPart - ctrStart); - return PyFloat_FromDouble(diff / (double)cpu_frequency); + if (info) { + info->implementation = "QueryPerformanceCounter()"; + info->resolution = 1.0 / (double)cpu_frequency; + info->precision = info->resolution; + info->is_monotonic = 1; + info->is_adjusted = 0; + } + *result = PyFloat_FromDouble(diff / (double)cpu_frequency); + return 0; } #endif -#if (defined(MS_WINDOWS) && !defined(__BORLANDC__)) || defined(HAVE_CLOCK) +#if defined(WIN32_PERF_COUNTER) || defined(HAVE_CLOCK) +#define PYCLOCK +static PyObject* +pyclock(_Py_clock_info_t *info) +{ +#ifdef WIN32_PERF_COUNTER + PyObject *res; + if (win_perf_counter(info, &res) == 0) + return res; +#endif + return floatclock(info); +} + static PyObject * time_clock(PyObject *self, PyObject *unused) { -#if defined(MS_WINDOWS) && !defined(__BORLANDC__) - return win32_clock(1); -#else - return pyclock(); -#endif + return pyclock(NULL); } PyDoc_STRVAR(clock_doc, @@ -150,7 +184,6 @@ PyErr_SetFromErrno(PyExc_IOError); return NULL; } - return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); } @@ -787,11 +820,75 @@ should not be relied on."); #endif /* HAVE_WORKING_TZSET */ +#if defined(MS_WINDOWS) || defined(__APPLE__) \ + || (defined(HAVE_CLOCK_GETTIME) \ + && (defined(CLOCK_HIGHRES) || defined(CLOCK_MONOTONIC))) +#define PYMONOTONIC +#endif + +#ifdef PYMONOTONIC static PyObject* -steady_clock(int strict) +pymonotonic(_Py_clock_info_t *info) { -#if defined(MS_WINDOWS) && !defined(__BORLANDC__) - return win32_clock(!strict); +#if defined(MS_WINDOWS) + static ULONGLONG (*GetTickCount64) (void) = NULL; + static ULONGLONG (CALLBACK *Py_GetTickCount64)(void); + static int has_getickcount64 = -1; + double result; + + if (has_getickcount64 == -1) { + /* GetTickCount64() was added to Windows Vista */ + if (winver.dwMajorVersion >= 6) { + HINSTANCE hKernel32; + hKernel32 = GetModuleHandleW(L"KERNEL32"); + *(FARPROC*)&Py_GetTickCount64 = GetProcAddress(hKernel32, + "GetTickCount64"); + has_getickcount64 = (Py_GetTickCount64 != NULL); + } + else + has_getickcount64 = 0; + } + + if (has_getickcount64) { + ULONGLONG ticks; + ticks = Py_GetTickCount64(); + result = (double)ticks * 1e-3; + } + else { + static DWORD last_ticks = 0; + static DWORD n_overflow = 0; + DWORD ticks; + + ticks = GetTickCount(); + if (ticks < last_ticks) + n_overflow++; + last_ticks = ticks; + + result = ldexp(n_overflow, 32); + result += ticks; + result *= 1e-3; + } + + if (info) { + DWORD timeAdjustment, timeIncrement; + BOOL isTimeAdjustmentDisabled, ok; + if (has_getickcount64) + info->implementation = "GetTickCount64()"; + else + info->implementation = "GetTickCount()"; + info->is_monotonic = 1; + info->resolution = 1e-3; + ok = GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, + &isTimeAdjustmentDisabled); + if (!ok) { + PyErr_SetFromWindowsErr(0); + return NULL; + } + info->precision = timeIncrement * 1e-7; + info->is_adjusted = 0; + } + return PyFloat_FromDouble(result); + #elif defined(__APPLE__) static mach_timebase_info_data_t timebase; uint64_t time; @@ -805,88 +902,326 @@ time = mach_absolute_time(); secs = (double)time * timebase.numer / timebase.denom * 1e-9; + if (info) { + info->implementation = "mach_absolute_time()"; + info->precision = (double)timebase.numer / timebase.denom * 1e-9; + info->resolution = info->precision; + info->is_monotonic = 1; + info->is_adjusted = 0; + } + return PyFloat_FromDouble(secs); - return PyFloat_FromDouble(secs); -#elif defined(HAVE_CLOCK_GETTIME) - static int steady_clk_index = 0; - static int monotonic_clk_index = 0; - int *clk_index; - clockid_t steady_clk_ids[] = { -#ifdef CLOCK_MONOTONIC_RAW - CLOCK_MONOTONIC_RAW, +#elif defined(HAVE_CLOCK_GETTIME) && (defined(CLOCK_HIGHRES) || defined(CLOCK_MONOTONIC)) + struct timespec tp; +#ifdef CLOCK_HIGHRES + const clockid_t clk_id = CLOCK_HIGHRES; + const char *function = "clock_gettime(CLOCK_HIGHRES)"; +#else + const clockid_t clk_id = CLOCK_MONOTONIC; + const char *function = "clock_gettime(CLOCK_MONOTONIC)"; #endif - CLOCK_MONOTONIC, - CLOCK_REALTIME - }; - clockid_t monotonic_clk_ids[] = { -#ifdef CLOCK_MONOTONIC_RAW - CLOCK_MONOTONIC_RAW, -#endif - CLOCK_MONOTONIC - }; - clockid_t *clk_ids; - int clk_ids_len; - int ret; - struct timespec tp; - if (strict) { - clk_index = &monotonic_clk_index; - clk_ids = monotonic_clk_ids; - clk_ids_len = Py_ARRAY_LENGTH(monotonic_clk_ids); - } - else { - clk_index = &steady_clk_index; - clk_ids = steady_clk_ids; - clk_ids_len = Py_ARRAY_LENGTH(steady_clk_ids); - } - - 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 (clk_ids_len <= *clk_index) - (*clk_index) = -1; - } - if (strict) { + if (clock_gettime(clk_id, &tp) != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } - return floattime(); + + if (info) { + struct timespec res; + info->is_monotonic = 1; + info->implementation = function; +#ifdef CLOCK_HIGHRES + info->is_adjusted = 0; #else - if (strict) { - PyErr_SetString(PyExc_NotImplementedError, - "no steady clock available on your platform"); - return NULL; +#if defined(linux) || defined(__linux) || defined(__linux__) + info->is_adjusted = 1; +#endif +#endif + info->resolution = 1e-9; + if (clock_getres(clk_id, &res) == 0) + info->precision = res.tv_sec + res.tv_nsec * 1e-9; } - return floattime(); + return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); #endif } static PyObject * -time_steady(PyObject *self, PyObject *args, PyObject *kwargs) +time_monotonic(PyObject *self, PyObject *unused) { - static char *kwlist[] = {"strict", NULL}; - int strict = 0; + return pymonotonic(NULL); +} - if (!PyArg_ParseTupleAndKeywords( - args, kwargs, "|i:steady", kwlist, - &strict)) +PyDoc_STRVAR(monotonic_doc, +"monotonic() -> float\n\ +\n\ +Monotonic clock, cannot go backward."); +#endif /* PYMONOTONIC */ + +static PyObject* +perf_counter(_Py_clock_info_t *info) +{ +#if defined(WIN32_PERF_COUNTER) || defined(PYMONOTONIC) + PyObject *res; +#endif +#if defined(WIN32_PERF_COUNTER) + static int use_perf_counter = 1; +#endif +#ifdef PYMONOTONIC + static int use_monotonic = 1; +#endif + +#ifdef WIN32_PERF_COUNTER + if (use_perf_counter) { + if (win_perf_counter(info, &res) == 0) + return res; + use_perf_counter = 0; + } +#endif + +#ifdef PYMONOTONIC + if (use_monotonic) { + res = pymonotonic(info); + if (res != NULL) + return res; + use_monotonic = 0; + PyErr_Clear(); + } +#endif + + return floattime(info); +} + +static PyObject * +time_perf_counter(PyObject *self, PyObject *unused) +{ + return perf_counter(NULL); +} + +PyDoc_STRVAR(perf_counter_doc, +"perf_counter() -> float\n\ +\n\ +Performance counter for benchmarking."); + +static PyObject* +py_process_time(_Py_clock_info_t *info) +{ +#if defined(MS_WINDOWS) + HANDLE process; + FILETIME creation_time, exit_time, kernel_time, user_time; + ULARGE_INTEGER large; + double total; + BOOL ok; + + process = GetCurrentProcess(); + ok = GetProcessTimes(process, &creation_time, &exit_time, &kernel_time, &user_time); + if (!ok) + return PyErr_SetFromWindowsErr(0); + + 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) { + info->implementation = "GetProcessTimes()"; + info->resolution = 1e-7; + info->is_monotonic = 1; + info->is_adjusted = 0; + } + return PyFloat_FromDouble(total * 1e-7); +#else + +#if defined(HAVE_SYS_RESOURCE_H) + struct rusage ru; +#endif +#ifdef HAVE_TIMES + struct tms t; + static long ticks_per_second = -1; +#endif + +#if defined(HAVE_CLOCK_GETTIME) \ + && (defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_PROF)) + struct timespec tp; +#ifdef CLOCK_PROF + const clockid_t clk_id = CLOCK_PROF; + const char *function = "clock_gettime(CLOCK_PROF)"; +#else + const clockid_t clk_id = CLOCK_PROCESS_CPUTIME_ID; + const char *function = "clock_gettime(CLOCK_PROCESS_CPUTIME_ID)"; +#endif + + if (clock_gettime(clk_id, &tp) == 0) { + if (info) { + struct timespec precision; + info->implementation = function; + info->is_monotonic = 1; + info->is_adjusted = 0; + info->resolution = 1e-9; + if (clock_getres(clk_id, &precision) == 0) + info->precision = precision.tv_sec + precision.tv_nsec * 1e-9; + } + return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); + } +#endif + +#if defined(HAVE_SYS_RESOURCE_H) + if (getrusage(RUSAGE_SELF, &ru) == 0) { + double total; + 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) { + info->implementation = "getrusage(RUSAGE_SELF)"; + info->is_monotonic = 1; + info->is_adjusted = 0; + info->resolution = 1e-6; + } + return PyFloat_FromDouble(total); + } +#endif + +#ifdef HAVE_TIMES + if (times(&t) != (clock_t)-1) { + double total; + + if (ticks_per_second == -1) { +#if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK) + ticks_per_second = sysconf(_SC_CLK_TCK); + if (ticks_per_second < 1) + ticks_per_second = -1; +#elif defined(HZ) + ticks_per_second = HZ; +#else + ticks_per_second = 60; /* magic fallback value; may be bogus */ +#endif + } + + if (ticks_per_second != -1) { + total = (double)t.tms_utime / ticks_per_second; + total += (double)t.tms_stime / ticks_per_second; + if (info) { + info->implementation = "times()"; + info->is_monotonic = 1; + info->is_adjusted = 0; + info->resolution = 1.0 / ticks_per_second; + info->precision = info->resolution; + } + return PyFloat_FromDouble(total); + } + } +#endif + + return floatclock(info); +#endif +} + +static PyObject * +time_process_time(PyObject *self, PyObject *unused) +{ + return py_process_time(NULL); +} + +PyDoc_STRVAR(process_time_doc, +"process_time() -> float\n\ +\n\ +Process time for profiling: sum of the kernel and user-space CPU time."); + + +static PyObject * +time_get_clock_info(PyObject *self, PyObject *args) +{ + char *name; + PyObject *dict, *obj; + int err; + _Py_clock_info_t info; + + if (!PyArg_ParseTuple(args, "s:get_clock_info", &name)) return NULL; - return steady_clock(strict); + info.precision = -1.0; + info.is_adjusted = -1; + + if (strcmp(name, "time") == 0) + obj = floattime(&info); +#ifdef PYCLOCK + else if (strcmp(name, "clock") == 0) + obj = pyclock(&info); +#endif +#ifdef PYMONOTONIC + else if (strcmp(name, "monotonic") == 0) + obj = pymonotonic(&info); +#endif + else if (strcmp(name, "perf_counter") == 0) + obj = perf_counter(&info); + else if (strcmp(name, "process_time") == 0) + obj = py_process_time(&info); + else { + PyErr_SetString(PyExc_ValueError, "unknown clock"); + return NULL; + } + if (obj == NULL) + return NULL; + Py_DECREF(obj); + + dict = PyDict_New(); + if (dict == NULL) + return NULL; + + obj = PyUnicode_FromString(info.implementation); + if (obj == NULL) + goto error; + err = PyDict_SetItemString(dict, "implementation", obj); + Py_DECREF(obj); + if (err) + goto error; + + obj = PyFloat_FromDouble(info.resolution); + if (obj == NULL) + goto error; + err = PyDict_SetItemString(dict, "resolution", obj); + Py_DECREF(obj); + if (err) + goto error; + + obj = PyBool_FromLong(info.is_monotonic); + if (obj == NULL) + goto error; + err = PyDict_SetItemString(dict, "is_monotonic", obj); + Py_DECREF(obj); + if (err) + goto error; + + if (info.precision != -1.0) { + obj = PyFloat_FromDouble(info.precision); + if (obj == NULL) + goto error; + err = PyDict_SetItemString(dict, "precision", obj); + Py_DECREF(obj); + if (err) + goto error; + } + + if (info.is_adjusted != -1) { + obj = PyBool_FromLong(info.is_adjusted); + if (obj == NULL) + goto error; + err = PyDict_SetItemString(dict, "is_adjusted", obj); + Py_DECREF(obj); + if (err) + goto error; + } + + return dict; + +error: + Py_DECREF(dict); + return NULL; } -PyDoc_STRVAR(steady_doc, -"steady(strict=False) -> float\n\ +PyDoc_STRVAR(get_clock_info_doc, +"get_clock_info(name: str) -> dict\n\ \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\ -be adjusted. The reference point of the returned value is undefined so only\n\ -the difference of consecutive calls is valid."); - +Get information of the specified clock."); static void PyInit_timezone(PyObject *m) { @@ -977,10 +1312,8 @@ #endif /* __CYGWIN__ */ #endif /* !HAVE_TZNAME || __GLIBC__ || __CYGWIN__*/ -#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_GETRES) -#ifdef CLOCK_REALTIME +#if defined(HAVE_CLOCK_GETTIME) PyModule_AddIntMacro(m, CLOCK_REALTIME); -#endif #ifdef CLOCK_MONOTONIC PyModule_AddIntMacro(m, CLOCK_MONOTONIC); #endif @@ -1002,7 +1335,7 @@ static PyMethodDef time_methods[] = { {"time", time_time, METH_NOARGS, time_doc}, -#if (defined(MS_WINDOWS) && !defined(__BORLANDC__)) || defined(HAVE_CLOCK) +#ifdef PYCLOCK {"clock", time_clock, METH_NOARGS, clock_doc}, #endif #ifdef HAVE_CLOCK_GETTIME @@ -1018,8 +1351,6 @@ #ifdef HAVE_MKTIME {"mktime", time_mktime, METH_O, mktime_doc}, #endif - {"steady", (PyCFunction)time_steady, METH_VARARGS|METH_KEYWORDS, - steady_doc}, #ifdef HAVE_STRFTIME {"strftime", time_strftime, METH_VARARGS, strftime_doc}, #endif @@ -1027,6 +1358,12 @@ #ifdef HAVE_WORKING_TZSET {"tzset", time_tzset, METH_NOARGS, tzset_doc}, #endif +#ifdef PYMONOTONIC + {"monotonic", time_monotonic, METH_NOARGS, monotonic_doc}, +#endif + {"process_time", time_process_time, METH_NOARGS, process_time_doc}, + {"perf_counter", time_perf_counter, METH_NOARGS, perf_counter_doc}, + {"get_clock_info", time_get_clock_info, METH_VARARGS, get_clock_info_doc}, {NULL, NULL} /* sentinel */ }; @@ -1104,6 +1441,15 @@ if (!initialized) { PyStructSequence_InitType(&StructTimeType, &struct_time_type_desc); + +#ifdef MS_WINDOWS + winver.dwOSVersionInfoSize = sizeof(winver); + if (!GetVersionEx((OSVERSIONINFO*)&winver)) { + Py_DECREF(m); + PyErr_SetFromWindowsErr(0); + return NULL; + } +#endif } Py_INCREF(&StructTimeType); PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType); @@ -1112,7 +1458,7 @@ } static PyObject* -floattime(void) +floattime(_Py_clock_info_t *info) { _PyTime_timeval t; #ifdef HAVE_CLOCK_GETTIME @@ -1123,10 +1469,20 @@ because it would require to link Python to the rt (real-time) library, at least on Linux */ ret = clock_gettime(CLOCK_REALTIME, &tp); - if (ret == 0) + if (ret == 0) { + if (info) { + struct timespec res; + info->implementation = "clock_gettime(CLOCK_REALTIME)"; + info->is_monotonic = 0; + info->is_adjusted = 1; + info->resolution = 1e-9; + if (clock_getres(CLOCK_REALTIME, &res) == 0) + info->precision = res.tv_sec + res.tv_nsec * 1e-9; + } return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); + } #endif - _PyTime_gettimeofday(&t); + _PyTime_gettimeofday_info(&t, info); return PyFloat_FromDouble((double)t.tv_sec + t.tv_usec * 1e-6); } diff -r 66bd85bcf916 -r aac59a3c11ef Python/dynload_win.c --- a/Python/dynload_win.c Tue Apr 17 19:14:26 2012 -0400 +++ b/Python/dynload_win.c Wed Apr 18 01:15:52 2012 +0200 @@ -254,9 +254,9 @@ theLength)); } if (message != NULL) { - PyErr_SetImportError(message, PyUnicode_FromString(shortname), - pathname); - Py_DECREF(message); + PyErr_SetFromImportErrorWithNameAndPath(message, + PyUnicode_FromString(shortname), + pathname); } return NULL; } else { diff -r 66bd85bcf916 -r aac59a3c11ef Python/errors.c --- a/Python/errors.c Tue Apr 17 19:14:26 2012 -0400 +++ b/Python/errors.c Wed Apr 18 01:15:52 2012 +0200 @@ -586,43 +586,50 @@ #endif /* MS_WINDOWS */ PyObject * -PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path) +PyErr_SetExcWithArgsKwargs(PyObject *exc, PyObject *args, PyObject *kwargs) { - PyObject *args, *kwargs, *error; - - args = PyTuple_New(1); - if (args == NULL) - return NULL; - - kwargs = PyDict_New(); - if (args == NULL) - return NULL; - - if (name == NULL) - name = Py_None; - - if (path == NULL) - path = Py_None; - - Py_INCREF(msg); - PyTuple_SetItem(args, 0, msg); - PyDict_SetItemString(kwargs, "name", name); - PyDict_SetItemString(kwargs, "path", path); + PyObject *val; /* args must at least be an empty tuple */ if (args == NULL) args = PyTuple_New(0); - error = PyObject_Call(PyExc_ImportError, args, kwargs); - if (error!= NULL) { - PyErr_SetObject((PyObject *) Py_TYPE(error), error); - Py_DECREF(error); + val = PyObject_Call(exc, args, kwargs); + if (val != NULL) { + PyErr_SetObject((PyObject *) Py_TYPE(val), val); + Py_DECREF(val); } + return NULL; +} + +PyObject * +PyErr_SetFromImportErrorWithNameAndPath(PyObject *msg, + PyObject *name, PyObject *path) +{ + PyObject *args = PyTuple_New(1); + PyObject *kwargs = PyDict_New(); + PyObject *result; + + if (path == NULL) + path = Py_None; + + PyTuple_SetItem(args, 0, msg); + PyDict_SetItemString(kwargs, "name", name); + PyDict_SetItemString(kwargs, "path", path); + + result = PyErr_SetExcWithArgsKwargs(PyExc_ImportError, args, kwargs); + Py_DECREF(args); Py_DECREF(kwargs); - return NULL; + return result; +} + +PyObject * +PyErr_SetFromImportErrorWithName(PyObject *msg, PyObject *name) +{ + return PyErr_SetFromImportErrorWithNameAndPath(msg, name, NULL); } void diff -r 66bd85bcf916 -r aac59a3c11ef Python/import.c --- a/Python/import.c Tue Apr 17 19:14:26 2012 -0400 +++ b/Python/import.c Wed Apr 18 01:15:52 2012 +0200 @@ -1062,6 +1062,58 @@ } +/* Read a code object from a file and check it for validity */ + +static PyCodeObject * +read_compiled_module(PyObject *cpathname, FILE *fp) +{ + PyObject *co; + + co = PyMarshal_ReadLastObjectFromFile(fp); + if (co == NULL) + return NULL; + if (!PyCode_Check(co)) { + PyErr_Format(PyExc_ImportError, + "Non-code object in %R", cpathname); + Py_DECREF(co); + return NULL; + } + return (PyCodeObject *)co; +} + + +/* Load a module from a compiled file, execute it, and return its + module object WITH INCREMENTED REFERENCE COUNT */ + +static PyObject * +load_compiled_module(PyObject *name, PyObject *cpathname, FILE *fp) +{ + long magic; + PyCodeObject *co; + PyObject *m; + + magic = PyMarshal_ReadLongFromFile(fp); + if (magic != pyc_magic) { + PyErr_Format(PyExc_ImportError, + "Bad magic number in %R", cpathname); + return NULL; + } + /* Skip mtime and size */ + (void) PyMarshal_ReadLongFromFile(fp); + (void) PyMarshal_ReadLongFromFile(fp); + co = read_compiled_module(cpathname, fp); + if (co == NULL) + return NULL; + if (Py_VerboseFlag) + PySys_FormatStderr("import %U # precompiled from %R\n", + name, cpathname); + m = PyImport_ExecCodeModuleObject(name, (PyObject *)co, + cpathname, cpathname); + Py_DECREF(co); + + return m; +} + static void update_code_filenames(PyCodeObject *co, PyObject *oldname, PyObject *newname) { @@ -2303,9 +2355,8 @@ } } else { - package = _PyDict_GetItemId(globals, &PyId___name__); + package = _PyDict_GetItemIdWithError(globals, &PyId___name__); if (package == NULL) { - PyErr_SetString(PyExc_KeyError, "'__name__' not in globals"); goto error; } else if (!PyUnicode_Check(package)) { @@ -2409,8 +2460,7 @@ PyObject *msg = PyUnicode_FromFormat("import of %R halted; " "None in sys.modules", abs_name); if (msg != NULL) { - PyErr_SetImportError(msg, abs_name, NULL); - Py_DECREF(msg); + PyErr_SetFromImportErrorWithName(msg, abs_name); } mod = NULL; goto error_with_unlock; @@ -2958,6 +3008,29 @@ } } +static PyObject * +imp_load_compiled(PyObject *self, PyObject *args) +{ + PyObject *name, *pathname; + PyObject *fob = NULL; + PyObject *m; + FILE *fp; + if (!PyArg_ParseTuple(args, "UO&|O:load_compiled", + &name, + PyUnicode_FSDecoder, &pathname, + &fob)) + return NULL; + fp = get_file(pathname, fob, "rb"); + if (fp == NULL) { + Py_DECREF(pathname); + return NULL; + } + m = load_compiled_module(name, pathname, fp); + fclose(fp); + Py_DECREF(pathname); + return m; +} + #ifdef HAVE_DYNAMIC_LOADING static PyObject * @@ -3134,6 +3207,7 @@ {"init_frozen", imp_init_frozen, METH_VARARGS}, {"is_builtin", imp_is_builtin, METH_VARARGS}, {"is_frozen", imp_is_frozen, METH_VARARGS}, + {"load_compiled", imp_load_compiled, METH_VARARGS}, #ifdef HAVE_DYNAMIC_LOADING {"load_dynamic", imp_load_dynamic, METH_VARARGS}, #endif diff -r 66bd85bcf916 -r aac59a3c11ef Python/pytime.c --- a/Python/pytime.c Tue Apr 17 19:14:26 2012 -0400 +++ b/Python/pytime.c Wed Apr 18 01:15:52 2012 +0200 @@ -18,8 +18,8 @@ extern int ftime(struct timeb *); #endif -void -_PyTime_gettimeofday(_PyTime_timeval *tp) +static void +pygettimeofday(_PyTime_timeval *tp, _Py_clock_info_t *info) { #ifdef MS_WINDOWS FILETIME system_time; @@ -35,6 +35,21 @@ microseconds = large.QuadPart / 10 - 11644473600000000; tp->tv_sec = microseconds / 1000000; tp->tv_usec = microseconds % 1000000; + if (info) { + DWORD timeAdjustment, timeIncrement; + BOOL isTimeAdjustmentDisabled; + + info->implementation = "GetSystemTimeAsFileTime()"; + info->resolution = 1e-7; + info->is_monotonic = 0; + (void) GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, + &isTimeAdjustmentDisabled); + info->precision = timeIncrement * 1e-7; + if (isTimeAdjustmentDisabled) + info->is_adjusted = 0; + else + info->is_adjusted = 1; + } #else /* There are three ways to get the time: (1) gettimeofday() -- resolution in microseconds @@ -46,14 +61,22 @@ Note: clock resolution does not imply clock accuracy! */ #ifdef HAVE_GETTIMEOFDAY + int err; #ifdef GETTIMEOFDAY_NO_TZ - if (gettimeofday(tp) == 0) + err = gettimeofday(tp); +#else + err = gettimeofday(tp, (struct timezone *)NULL); +#endif + if (err == 0) { + if (info) { + info->implementation = "gettimeofday()"; + info->resolution = 1e-6; + info->is_monotonic = 0; + info->is_adjusted = 1; + } return; -#else /* !GETTIMEOFDAY_NO_TZ */ - if (gettimeofday(tp, (struct timezone *)NULL) == 0) - return; -#endif /* !GETTIMEOFDAY_NO_TZ */ -#endif /* !HAVE_GETTIMEOFDAY */ + } +#endif /* HAVE_GETTIMEOFDAY */ #if defined(HAVE_FTIME) { @@ -61,15 +84,39 @@ ftime(&t); tp->tv_sec = t.time; tp->tv_usec = t.millitm * 1000; + if (info) { + info->implementation = "ftime()"; + info->resolution = 1e-3; + info->is_monotonic = 0; + info->is_adjusted = 1; + } } #else /* !HAVE_FTIME */ tp->tv_sec = time(NULL); tp->tv_usec = 0; + if (info) { + info->implementation = "time()"; + info->resolution = 1; + info->is_monotonic = 0; + info->is_adjusted = 1; + } #endif /* !HAVE_FTIME */ #endif /* MS_WINDOWS */ } +void +_PyTime_gettimeofday(_PyTime_timeval *tp) +{ + pygettimeofday(tp, NULL); +} + +void +_PyTime_gettimeofday_info(_PyTime_timeval *tp, _Py_clock_info_t *info) +{ + pygettimeofday(tp, info); +} + static void error_time_t_overflow(void) {