Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(343)

Delta Between Two Patch Sets: Modules/timemodule.c

Issue 22043: Use a monotonic clock to compute timeouts
Left Patch Set: Created 3 years, 3 months ago
Right Patch Set: Created 3 years, 2 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Modules/socketmodule.c ('k') | Python/pytime.c » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* Time module */ 1 /* Time module */
2 2
3 #include "Python.h" 3 #include "Python.h"
4 4
5 #include <ctype.h> 5 #include <ctype.h>
6 6
7 #ifdef HAVE_SYS_TIMES_H 7 #ifdef HAVE_SYS_TIMES_H
8 #include <sys/times.h> 8 #include <sys/times.h>
9 #endif 9 #endif
10 10
(...skipping 19 matching lines...) Expand all
30 30
31 #if defined(__BORLANDC__) 31 #if defined(__BORLANDC__)
32 /* These overrides not needed for Win32 */ 32 /* These overrides not needed for Win32 */
33 #define timezone _timezone 33 #define timezone _timezone
34 #define tzname _tzname 34 #define tzname _tzname
35 #define daylight _daylight 35 #define daylight _daylight
36 #endif /* __BORLANDC__ */ 36 #endif /* __BORLANDC__ */
37 #endif /* MS_WINDOWS */ 37 #endif /* MS_WINDOWS */
38 #endif /* !__WATCOMC__ || __QNX__ */ 38 #endif /* !__WATCOMC__ || __QNX__ */
39 39
40 #if defined(__APPLE__)
41 #include <mach/mach_time.h>
42 #endif
43
44 /* Forward declarations */ 40 /* Forward declarations */
45 static int floatsleep(double); 41 static int floatsleep(double);
46 static PyObject* floattime(_Py_clock_info_t *info); 42 static PyObject* floattime(_Py_clock_info_t *info);
47 43
48 #ifdef MS_WINDOWS 44 #ifdef MS_WINDOWS
49 static OSVERSIONINFOEX winver; 45 static OSVERSIONINFOEX winver;
50 #endif 46 #endif
51 47
52 static PyObject * 48 static PyObject *
53 time_time(PyObject *self, PyObject *unused) 49 time_time(PyObject *self, PyObject *unused)
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 info->adjustable = 0; 85 info->adjustable = 0;
90 } 86 }
91 return PyFloat_FromDouble((double)value / CLOCKS_PER_SEC); 87 return PyFloat_FromDouble((double)value / CLOCKS_PER_SEC);
92 } 88 }
93 #endif /* HAVE_CLOCK */ 89 #endif /* HAVE_CLOCK */
94 90
95 #if defined(MS_WINDOWS) && !defined(__BORLANDC__) 91 #if defined(MS_WINDOWS) && !defined(__BORLANDC__)
96 #define WIN32_PERF_COUNTER 92 #define WIN32_PERF_COUNTER
97 /* Win32 has better clock replacement; we have our own version, due to Mark 93 /* Win32 has better clock replacement; we have our own version, due to Mark
98 Hammond and Tim Peters */ 94 Hammond and Tim Peters */
99 static int 95 static PyObject*
100 win_perf_counter(_Py_clock_info_t *info, PyObject **result) 96 win_perf_counter(_Py_clock_info_t *info)
101 { 97 {
102 static LONGLONG cpu_frequency = 0; 98 static LONGLONG cpu_frequency = 0;
103 static LONGLONG ctrStart; 99 static LONGLONG ctrStart;
104 LARGE_INTEGER now; 100 LARGE_INTEGER now;
105 double diff; 101 double diff;
106 102
107 if (cpu_frequency == 0) { 103 if (cpu_frequency == 0) {
108 LARGE_INTEGER freq; 104 LARGE_INTEGER freq;
109 QueryPerformanceCounter(&now); 105 QueryPerformanceCounter(&now);
110 ctrStart = now.QuadPart; 106 ctrStart = now.QuadPart;
111 if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) { 107 if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) {
112 /* Unlikely to happen - this works on all intel 108 PyErr_SetFromWindowsErr(0);
113 machines at least! Revert to clock() */ 109 return NULL;
114 *result = NULL;
115 return -1;
116 } 110 }
117 cpu_frequency = freq.QuadPart; 111 cpu_frequency = freq.QuadPart;
118 } 112 }
119 QueryPerformanceCounter(&now); 113 QueryPerformanceCounter(&now);
120 diff = (double)(now.QuadPart - ctrStart); 114 diff = (double)(now.QuadPart - ctrStart);
121 if (info) { 115 if (info) {
122 info->implementation = "QueryPerformanceCounter()"; 116 info->implementation = "QueryPerformanceCounter()";
123 info->resolution = 1.0 / (double)cpu_frequency; 117 info->resolution = 1.0 / (double)cpu_frequency;
124 info->monotonic = 1; 118 info->monotonic = 1;
125 info->adjustable = 0; 119 info->adjustable = 0;
126 } 120 }
127 *result = PyFloat_FromDouble(diff / (double)cpu_frequency); 121 return PyFloat_FromDouble(diff / (double)cpu_frequency);
128 return 0;
129 } 122 }
130 #endif 123 #endif
131 124
132 #if defined(WIN32_PERF_COUNTER) || defined(HAVE_CLOCK) 125 #if defined(WIN32_PERF_COUNTER) || defined(HAVE_CLOCK)
133 #define PYCLOCK 126 #define PYCLOCK
134 static PyObject* 127 static PyObject*
135 pyclock(_Py_clock_info_t *info) 128 pyclock(_Py_clock_info_t *info)
136 { 129 {
137 #ifdef WIN32_PERF_COUNTER 130 #ifdef WIN32_PERF_COUNTER
138 PyObject *res; 131 return win_perf_counter(info);
139 if (win_perf_counter(info, &res) == 0) 132 #else
140 return res;
141 #endif
142 return floatclock(info); 133 return floatclock(info);
134 #endif
143 } 135 }
144 136
145 static PyObject * 137 static PyObject *
146 time_clock(PyObject *self, PyObject *unused) 138 time_clock(PyObject *self, PyObject *unused)
147 { 139 {
148 return pyclock(NULL); 140 return pyclock(NULL);
149 } 141 }
150 142
151 PyDoc_STRVAR(clock_doc, 143 PyDoc_STRVAR(clock_doc,
152 "clock() -> floating point number\n\ 144 "clock() -> floating point number\n\
(...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after
896 os.environ['TZ']. The TZ environment variable should be specified in\n\ 888 os.environ['TZ']. The TZ environment variable should be specified in\n\
897 standard Unix timezone format as documented in the tzset man page\n\ 889 standard Unix timezone format as documented in the tzset man page\n\
898 (eg. 'US/Eastern', 'Europe/Amsterdam'). Unknown timezones will silently\n\ 890 (eg. 'US/Eastern', 'Europe/Amsterdam'). Unknown timezones will silently\n\
899 fall back to UTC. If the TZ environment variable is not set, the local\n\ 891 fall back to UTC. If the TZ environment variable is not set, the local\n\
900 timezone is set to the systems best guess of wallclock time.\n\ 892 timezone is set to the systems best guess of wallclock time.\n\
901 Changing the TZ environment variable without calling tzset *may* change\n\ 893 Changing the TZ environment variable without calling tzset *may* change\n\
902 the local timezone used by methods such as localtime, but this behaviour\n\ 894 the local timezone used by methods such as localtime, but this behaviour\n\
903 should not be relied on."); 895 should not be relied on.");
904 #endif /* HAVE_WORKING_TZSET */ 896 #endif /* HAVE_WORKING_TZSET */
905 897
906 #if defined(MS_WINDOWS) || defined(__APPLE__) \ 898 static PyObject *
907 || (defined(HAVE_CLOCK_GETTIME) \
908 && (defined(CLOCK_HIGHRES) || defined(CLOCK_MONOTONIC)))
909 #define PYMONOTONIC
910 #endif
911
912 #ifdef PYMONOTONIC
913 static PyObject*
914 pymonotonic(_Py_clock_info_t *info) 899 pymonotonic(_Py_clock_info_t *info)
915 { 900 {
916 #if defined(MS_WINDOWS) 901 _PyTime_timeval tv;
917 static ULONGLONG (*GetTickCount64) (void) = NULL; 902 if (_PyTime_monotonic_info(&tv, info) < 0) {
918 static ULONGLONG (CALLBACK *Py_GetTickCount64)(void); 903 assert(info != NULL);
919 static int has_getickcount64 = -1; 904 return NULL;
920 double result; 905 }
921 906 return PyFloat_FromDouble((double)tv.tv_sec + tv.tv_usec * 1e-6);
922 if (has_getickcount64 == -1) {
923 /* GetTickCount64() was added to Windows Vista */
924 if (winver.dwMajorVersion >= 6) {
925 HINSTANCE hKernel32;
926 hKernel32 = GetModuleHandleW(L"KERNEL32");
927 *(FARPROC*)&Py_GetTickCount64 = GetProcAddress(hKernel32,
928 "GetTickCount64");
929 has_getickcount64 = (Py_GetTickCount64 != NULL);
930 }
931 else
932 has_getickcount64 = 0;
933 }
934
935 if (has_getickcount64) {
936 ULONGLONG ticks;
937 ticks = Py_GetTickCount64();
938 result = (double)ticks * 1e-3;
939 }
940 else {
941 static DWORD last_ticks = 0;
942 static DWORD n_overflow = 0;
943 DWORD ticks;
944
945 ticks = GetTickCount();
946 if (ticks < last_ticks)
947 n_overflow++;
948 last_ticks = ticks;
949
950 result = ldexp(n_overflow, 32);
951 result += ticks;
952 result *= 1e-3;
953 }
954
955 if (info) {
956 DWORD timeAdjustment, timeIncrement;
957 BOOL isTimeAdjustmentDisabled, ok;
958 if (has_getickcount64)
959 info->implementation = "GetTickCount64()";
960 else
961 info->implementation = "GetTickCount()";
962 info->monotonic = 1;
963 ok = GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement,
964 &isTimeAdjustmentDisabled);
965 if (!ok) {
966 PyErr_SetFromWindowsErr(0);
967 return NULL;
968 }
969 info->resolution = timeIncrement * 1e-7;
970 info->adjustable = 0;
971 }
972 return PyFloat_FromDouble(result);
973
974 #elif defined(__APPLE__)
975 static mach_timebase_info_data_t timebase;
976 uint64_t time;
977 double secs;
978
979 if (timebase.denom == 0) {
980 /* According to the Technical Q&A QA1398, mach_timebase_info() cannot
981 fail: https://developer.apple.com/library/mac/#qa/qa1398/ */
982 (void)mach_timebase_info(&timebase);
983 }
984
985 time = mach_absolute_time();
986 secs = (double)time * timebase.numer / timebase.denom * 1e-9;
987 if (info) {
988 info->implementation = "mach_absolute_time()";
989 info->resolution = (double)timebase.numer / timebase.denom * 1e-9;
990 info->monotonic = 1;
991 info->adjustable = 0;
992 }
993 return PyFloat_FromDouble(secs);
994
995 #elif defined(HAVE_CLOCK_GETTIME) && (defined(CLOCK_HIGHRES) || defined(CLOCK_MO NOTONIC))
996 struct timespec tp;
997 #ifdef CLOCK_HIGHRES
998 const clockid_t clk_id = CLOCK_HIGHRES;
999 const char *function = "clock_gettime(CLOCK_HIGHRES)";
1000 #else
1001 const clockid_t clk_id = CLOCK_MONOTONIC;
1002 const char *function = "clock_gettime(CLOCK_MONOTONIC)";
1003 #endif
1004
1005 if (clock_gettime(clk_id, &tp) != 0) {
1006 PyErr_SetFromErrno(PyExc_OSError);
1007 return NULL;
1008 }
1009
1010 if (info) {
1011 struct timespec res;
1012 info->monotonic = 1;
1013 info->implementation = function;
1014 info->adjustable = 0;
1015 if (clock_getres(clk_id, &res) == 0)
1016 info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
1017 else
1018 info->resolution = 1e-9;
1019 }
1020 return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
1021 #endif
1022 } 907 }
1023 908
1024 static PyObject * 909 static PyObject *
1025 time_monotonic(PyObject *self, PyObject *unused) 910 time_monotonic(PyObject *self, PyObject *unused)
1026 { 911 {
1027 return pymonotonic(NULL); 912 return pymonotonic(NULL);
1028 } 913 }
1029 914
1030 PyDoc_STRVAR(monotonic_doc, 915 PyDoc_STRVAR(monotonic_doc,
1031 "monotonic() -> float\n\ 916 "monotonic() -> float\n\
1032 \n\ 917 \n\
1033 Monotonic clock, cannot go backward."); 918 Monotonic clock, cannot go backward.");
1034 #endif /* PYMONOTONIC */
1035 919
1036 static PyObject* 920 static PyObject*
1037 perf_counter(_Py_clock_info_t *info) 921 perf_counter(_Py_clock_info_t *info)
1038 { 922 {
1039 #if defined(WIN32_PERF_COUNTER) || defined(PYMONOTONIC)
1040 PyObject *res;
1041 #endif
1042 #if defined(WIN32_PERF_COUNTER)
1043 static int use_perf_counter = 1;
1044 #endif
1045 #ifdef PYMONOTONIC
1046 static int use_monotonic = 1;
1047 #endif
1048
1049 #ifdef WIN32_PERF_COUNTER 923 #ifdef WIN32_PERF_COUNTER
1050 if (use_perf_counter) { 924 return win_perf_counter(info);
1051 if (win_perf_counter(info, &res) == 0) 925 #else
1052 return res; 926 return pymonotonic(info);
1053 use_perf_counter = 0; 927 #endif
1054 }
1055 #endif
1056
1057 #ifdef PYMONOTONIC
1058 if (use_monotonic) {
1059 res = pymonotonic(info);
1060 if (res != NULL)
1061 return res;
1062 use_monotonic = 0;
1063 PyErr_Clear();
1064 }
1065 #endif
1066
1067 return floattime(info);
1068 } 928 }
1069 929
1070 static PyObject * 930 static PyObject *
1071 time_perf_counter(PyObject *self, PyObject *unused) 931 time_perf_counter(PyObject *self, PyObject *unused)
1072 { 932 {
1073 return perf_counter(NULL); 933 return perf_counter(NULL);
1074 } 934 }
1075 935
1076 PyDoc_STRVAR(perf_counter_doc, 936 PyDoc_STRVAR(perf_counter_doc,
1077 "perf_counter() -> float\n\ 937 "perf_counter() -> float\n\
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
1224 info.adjustable = 0; 1084 info.adjustable = 0;
1225 info.resolution = 1.0; 1085 info.resolution = 1.0;
1226 #endif 1086 #endif
1227 1087
1228 if (strcmp(name, "time") == 0) 1088 if (strcmp(name, "time") == 0)
1229 obj = floattime(&info); 1089 obj = floattime(&info);
1230 #ifdef PYCLOCK 1090 #ifdef PYCLOCK
1231 else if (strcmp(name, "clock") == 0) 1091 else if (strcmp(name, "clock") == 0)
1232 obj = pyclock(&info); 1092 obj = pyclock(&info);
1233 #endif 1093 #endif
1234 #ifdef PYMONOTONIC
1235 else if (strcmp(name, "monotonic") == 0) 1094 else if (strcmp(name, "monotonic") == 0)
1236 obj = pymonotonic(&info); 1095 obj = pymonotonic(&info);
1237 #endif
1238 else if (strcmp(name, "perf_counter") == 0) 1096 else if (strcmp(name, "perf_counter") == 0)
1239 obj = perf_counter(&info); 1097 obj = perf_counter(&info);
1240 else if (strcmp(name, "process_time") == 0) 1098 else if (strcmp(name, "process_time") == 0)
1241 obj = py_process_time(&info); 1099 obj = py_process_time(&info);
1242 else { 1100 else {
1243 PyErr_SetString(PyExc_ValueError, "unknown clock"); 1101 PyErr_SetString(PyExc_ValueError, "unknown clock");
1244 return NULL; 1102 return NULL;
1245 } 1103 }
1246 if (obj == NULL) 1104 if (obj == NULL)
1247 return NULL; 1105 return NULL;
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
1419 #ifdef HAVE_MKTIME 1277 #ifdef HAVE_MKTIME
1420 {"mktime", time_mktime, METH_O, mktime_doc}, 1278 {"mktime", time_mktime, METH_O, mktime_doc},
1421 #endif 1279 #endif
1422 #ifdef HAVE_STRFTIME 1280 #ifdef HAVE_STRFTIME
1423 {"strftime", time_strftime, METH_VARARGS, strftime_doc}, 1281 {"strftime", time_strftime, METH_VARARGS, strftime_doc},
1424 #endif 1282 #endif
1425 {"strptime", time_strptime, METH_VARARGS, strptime_doc}, 1283 {"strptime", time_strptime, METH_VARARGS, strptime_doc},
1426 #ifdef HAVE_WORKING_TZSET 1284 #ifdef HAVE_WORKING_TZSET
1427 {"tzset", time_tzset, METH_NOARGS, tzset_doc}, 1285 {"tzset", time_tzset, METH_NOARGS, tzset_doc},
1428 #endif 1286 #endif
1429 #ifdef PYMONOTONIC
1430 {"monotonic", time_monotonic, METH_NOARGS, monotonic_doc}, 1287 {"monotonic", time_monotonic, METH_NOARGS, monotonic_doc},
1431 #endif
1432 {"process_time", time_process_time, METH_NOARGS, process_time_doc}, 1288 {"process_time", time_process_time, METH_NOARGS, process_time_doc},
1433 {"perf_counter", time_perf_counter, METH_NOARGS, perf_counter_doc}, 1289 {"perf_counter", time_perf_counter, METH_NOARGS, perf_counter_doc},
1434 {"get_clock_info", time_get_clock_info, METH_VARARGS, get_clock_info_doc}, 1290 {"get_clock_info", time_get_clock_info, METH_VARARGS, get_clock_info_doc},
1435 {NULL, NULL} /* sentinel */ 1291 {NULL, NULL} /* sentinel */
1436 }; 1292 };
1437 1293
1438 1294
1439 PyDoc_STRVAR(module_doc, 1295 PyDoc_STRVAR(module_doc,
1440 "This module provides various functions to manipulate time values.\n\ 1296 "This module provides various functions to manipulate time values.\n\
1441 \n\ 1297 \n\
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
1527 PyModule_AddIntConstant(m, "_STRUCT_TM_ITEMS", 9); 1383 PyModule_AddIntConstant(m, "_STRUCT_TM_ITEMS", 9);
1528 #endif 1384 #endif
1529 PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType); 1385 PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType);
1530 initialized = 1; 1386 initialized = 1;
1531 return m; 1387 return m;
1532 } 1388 }
1533 1389
1534 static PyObject* 1390 static PyObject*
1535 floattime(_Py_clock_info_t *info) 1391 floattime(_Py_clock_info_t *info)
1536 { 1392 {
1537 _PyTimeSpec ts; 1393 _PyTime_timeval t;
1538 #ifdef HAVE_CLOCK_GETTIME 1394 if (_PyTime_gettimeofday_info(&t, info) < 0) {
1539 struct timespec tp; 1395 assert(info != NULL);
1540 int ret; 1396 return NULL;
1541 1397 }
1542 /* _PyTime_gettimeofday() does not use clock_gettime() 1398 return PyFloat_FromDouble((double)t.tv_sec + t.tv_usec * 1e-6);
1543 because it would require to link Python to the rt (real-time)
1544 library, at least on Linux */
1545 ret = clock_gettime(CLOCK_REALTIME, &tp);
1546 if (ret == 0) {
1547 if (info) {
1548 struct timespec res;
1549 info->implementation = "clock_gettime(CLOCK_REALTIME)";
1550 info->monotonic = 0;
1551 info->adjustable = 1;
1552 if (clock_getres(CLOCK_REALTIME, &res) == 0)
1553 info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
1554 else
1555 info->resolution = 1e-9;
1556 }
1557 return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
1558 }
1559 #endif
1560 if (_PyTimeSpec_get_time_info(&ts, info) < 0) {
1561 assert(0 && "_PyTimeSpec_get_time_info should never fail");
Charles-François Natali 2014/07/31 19:50:26 This is ugly.
haypo 2014/08/01 01:44:20 Done.
1562 return NULL;
1563 }
1564 return PyFloat_FromDouble((double)ts.tv_sec + ts.tv_nsec * 1e-9);
1565 } 1399 }
1566 1400
1567 1401
1568 /* Implement floatsleep() for various platforms. 1402 /* Implement floatsleep() for various platforms.
1569 When interrupted (or when another error occurs), return -1 and 1403 When interrupted (or when another error occurs), return -1 and
1570 set an exception; else return 0. */ 1404 set an exception; else return 0. */
1571 1405
1572 static int 1406 static int
1573 floatsleep(double secs) 1407 floatsleep(double secs)
1574 { 1408 {
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
1636 } 1470 }
1637 #else 1471 #else
1638 /* XXX Can't interrupt this sleep */ 1472 /* XXX Can't interrupt this sleep */
1639 Py_BEGIN_ALLOW_THREADS 1473 Py_BEGIN_ALLOW_THREADS
1640 sleep((int)secs); 1474 sleep((int)secs);
1641 Py_END_ALLOW_THREADS 1475 Py_END_ALLOW_THREADS
1642 #endif 1476 #endif
1643 1477
1644 return 0; 1478 return 0;
1645 } 1479 }
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7