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

Delta Between Two Patch Sets: Modules/timemodule.c

Issue 22043: Use a monotonic clock to compute timeouts
Left Patch Set: Created 3 years, 4 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\
153 \n\ 145 \n\
154 Return the CPU time or real time since the start of the process or since\n\ 146 Return the CPU time or real time since the start of the process or since\n\
155 the first call to clock(). This has as much precision as the system\n\ 147 the first call to clock(). This has as much precision as the system\n\
156 records."); 148 records.");
157 #endif 149 #endif
158 150
159 #ifdef HAVE_CLOCK_GETTIME 151 #ifdef HAVE_CLOCK_GETTIME
160 static PyObject * 152 static PyObject *
161 time_clock_gettime(PyObject *self, PyObject *args) 153 time_clock_gettime(PyObject *self, PyObject *args)
162 { 154 {
163 int ret; 155 int ret;
164 int clk_id; 156 int clk_id;
165 struct timespec tp; 157 struct timespec tp;
166 158
167 if (!PyArg_ParseTuple(args, "i:clock_gettime", &clk_id)) 159 if (!PyArg_ParseTuple(args, "i:clock_gettime", &clk_id))
168 return NULL; 160 return NULL;
169 161
170 ret = clock_gettime((clockid_t)clk_id, &tp); 162 ret = clock_gettime((clockid_t)clk_id, &tp);
171 if (ret != 0) { 163 if (ret != 0) {
172 PyErr_SetFromErrno(PyExc_IOError); 164 PyErr_SetFromErrno(PyExc_OSError);
173 return NULL; 165 return NULL;
174 } 166 }
175 return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); 167 return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
176 } 168 }
177 169
178 PyDoc_STRVAR(clock_gettime_doc, 170 PyDoc_STRVAR(clock_gettime_doc,
179 "clock_gettime(clk_id) -> floating point number\n\ 171 "clock_gettime(clk_id) -> floating point number\n\
180 \n\ 172 \n\
181 Return the time of the specified clock clk_id."); 173 Return the time of the specified clock clk_id.");
182 174
(...skipping 10 matching lines...) Expand all
193 if (!PyArg_ParseTuple(args, "iO:clock_settime", &clk_id, &obj)) 185 if (!PyArg_ParseTuple(args, "iO:clock_settime", &clk_id, &obj))
194 return NULL; 186 return NULL;
195 187
196 if (_PyTime_ObjectToTimespec(obj, &tv_sec, &tv_nsec, _PyTime_ROUND_DOWN) == -1) 188 if (_PyTime_ObjectToTimespec(obj, &tv_sec, &tv_nsec, _PyTime_ROUND_DOWN) == -1)
197 return NULL; 189 return NULL;
198 tp.tv_sec = tv_sec; 190 tp.tv_sec = tv_sec;
199 tp.tv_nsec = tv_nsec; 191 tp.tv_nsec = tv_nsec;
200 192
201 ret = clock_settime((clockid_t)clk_id, &tp); 193 ret = clock_settime((clockid_t)clk_id, &tp);
202 if (ret != 0) { 194 if (ret != 0) {
203 PyErr_SetFromErrno(PyExc_IOError); 195 PyErr_SetFromErrno(PyExc_OSError);
204 return NULL; 196 return NULL;
205 } 197 }
206 Py_RETURN_NONE; 198 Py_RETURN_NONE;
207 } 199 }
208 200
209 PyDoc_STRVAR(clock_settime_doc, 201 PyDoc_STRVAR(clock_settime_doc,
210 "clock_settime(clk_id, time)\n\ 202 "clock_settime(clk_id, time)\n\
211 \n\ 203 \n\
212 Set the time of the specified clock clk_id."); 204 Set the time of the specified clock clk_id.");
213 205
214 static PyObject * 206 static PyObject *
215 time_clock_getres(PyObject *self, PyObject *args) 207 time_clock_getres(PyObject *self, PyObject *args)
216 { 208 {
217 int ret; 209 int ret;
218 int clk_id; 210 int clk_id;
219 struct timespec tp; 211 struct timespec tp;
220 212
221 if (!PyArg_ParseTuple(args, "i:clock_getres", &clk_id)) 213 if (!PyArg_ParseTuple(args, "i:clock_getres", &clk_id))
222 return NULL; 214 return NULL;
223 215
224 ret = clock_getres((clockid_t)clk_id, &tp); 216 ret = clock_getres((clockid_t)clk_id, &tp);
225 if (ret != 0) { 217 if (ret != 0) {
226 PyErr_SetFromErrno(PyExc_IOError); 218 PyErr_SetFromErrno(PyExc_OSError);
227 return NULL; 219 return NULL;
228 } 220 }
229 221
230 return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9); 222 return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
231 } 223 }
232 224
233 PyDoc_STRVAR(clock_getres_doc, 225 PyDoc_STRVAR(clock_getres_doc,
234 "clock_getres(clk_id) -> floating point number\n\ 226 "clock_getres(clk_id) -> floating point number\n\
235 \n\ 227 \n\
236 Return the resolution (precision) of the specified clock clk_id."); 228 Return the resolution (precision) of the specified clock clk_id.");
(...skipping 659 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 static PyObject* 898 static PyObject *
907 pymonotonic(_Py_clock_info_t *info) 899 pymonotonic(_Py_clock_info_t *info)
908 { 900 {
909 _PyTime_timespec ts; 901 _PyTime_timeval tv;
910 902 if (_PyTime_monotonic_info(&tv, info) < 0) {
911 if (_PyTime_monotonic_info(&ts, info) < 0) 903 assert(info != NULL);
912 return NULL; 904 return NULL;
913 905 }
914 return PyFloat_FromDouble(ts.tv_sec + ts.tv_nsec * 1e-9); 906 return PyFloat_FromDouble((double)tv.tv_sec + tv.tv_usec * 1e-6);
915 } 907 }
916 908
917 static PyObject * 909 static PyObject *
918 time_monotonic(PyObject *self, PyObject *unused) 910 time_monotonic(PyObject *self, PyObject *unused)
919 { 911 {
920 return pymonotonic(NULL); 912 return pymonotonic(NULL);
921 } 913 }
922 914
923 PyDoc_STRVAR(monotonic_doc, 915 PyDoc_STRVAR(monotonic_doc,
924 "monotonic() -> float\n\ 916 "monotonic() -> float\n\
925 \n\ 917 \n\
926 Monotonic clock, cannot go backward."); 918 Monotonic clock, cannot go backward.");
927 919
928 static PyObject* 920 static PyObject*
929 perf_counter(_Py_clock_info_t *info) 921 perf_counter(_Py_clock_info_t *info)
930 { 922 {
931 PyObject *res;
932 #ifdef WIN32_PERF_COUNTER 923 #ifdef WIN32_PERF_COUNTER
933 static int use_perf_counter = 1; 924 return win_perf_counter(info);
934 #endif 925 #else
935 static int use_monotonic = 1; 926 return pymonotonic(info);
936 927 #endif
937 #ifdef WIN32_PERF_COUNTER
938 if (use_perf_counter) {
939 if (win_perf_counter(info, &res) == 0)
940 return res;
941 use_perf_counter = 0;
942 }
943 #endif
944
945 if (use_monotonic) {
946 res = pymonotonic(info);
947 if (res != NULL)
948 return res;
949 use_monotonic = 0;
950 PyErr_Clear();
951 }
952
953 return floattime(info);
954 } 928 }
955 929
956 static PyObject * 930 static PyObject *
957 time_perf_counter(PyObject *self, PyObject *unused) 931 time_perf_counter(PyObject *self, PyObject *unused)
958 { 932 {
959 return perf_counter(NULL); 933 return perf_counter(NULL);
960 } 934 }
961 935
962 PyDoc_STRVAR(perf_counter_doc, 936 PyDoc_STRVAR(perf_counter_doc,
963 "perf_counter() -> float\n\ 937 "perf_counter() -> float\n\
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after
1409 PyModule_AddIntConstant(m, "_STRUCT_TM_ITEMS", 9); 1383 PyModule_AddIntConstant(m, "_STRUCT_TM_ITEMS", 9);
1410 #endif 1384 #endif
1411 PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType); 1385 PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType);
1412 initialized = 1; 1386 initialized = 1;
1413 return m; 1387 return m;
1414 } 1388 }
1415 1389
1416 static PyObject* 1390 static PyObject*
1417 floattime(_Py_clock_info_t *info) 1391 floattime(_Py_clock_info_t *info)
1418 { 1392 {
1419 _PyTime_timespec ts; 1393 _PyTime_timeval t;
1420 _PyTime_gettimeofday_info(&ts, info); 1394 if (_PyTime_gettimeofday_info(&t, info) < 0) {
1421 return PyFloat_FromDouble((double)ts.tv_sec + ts.tv_nsec * 1e-9); 1395 assert(info != NULL);
1396 return NULL;
1397 }
1398 return PyFloat_FromDouble((double)t.tv_sec + t.tv_usec * 1e-6);
1422 } 1399 }
1423 1400
1424 1401
1425 /* Implement floatsleep() for various platforms. 1402 /* Implement floatsleep() for various platforms.
1426 When interrupted (or when another error occurs), return -1 and 1403 When interrupted (or when another error occurs), return -1 and
1427 set an exception; else return 0. */ 1404 set an exception; else return 0. */
1428 1405
1429 static int 1406 static int
1430 floatsleep(double secs) 1407 floatsleep(double secs)
1431 { 1408 {
(...skipping 12 matching lines...) Expand all
1444 Py_END_ALLOW_THREADS 1421 Py_END_ALLOW_THREADS
1445 if (err != 0) { 1422 if (err != 0) {
1446 #ifdef EINTR 1423 #ifdef EINTR
1447 if (errno == EINTR) { 1424 if (errno == EINTR) {
1448 if (PyErr_CheckSignals()) 1425 if (PyErr_CheckSignals())
1449 return -1; 1426 return -1;
1450 } 1427 }
1451 else 1428 else
1452 #endif 1429 #endif
1453 { 1430 {
1454 PyErr_SetFromErrno(PyExc_IOError); 1431 PyErr_SetFromErrno(PyExc_OSError);
1455 return -1; 1432 return -1;
1456 } 1433 }
1457 } 1434 }
1458 #elif defined(__WATCOMC__) && !defined(__QNX__) 1435 #elif defined(__WATCOMC__) && !defined(__QNX__)
1459 /* XXX Can't interrupt this sleep */ 1436 /* XXX Can't interrupt this sleep */
1460 Py_BEGIN_ALLOW_THREADS 1437 Py_BEGIN_ALLOW_THREADS
1461 delay((int)(secs * 1000 + 0.5)); /* delay() uses milliseconds */ 1438 delay((int)(secs * 1000 + 0.5)); /* delay() uses milliseconds */
1462 Py_END_ALLOW_THREADS 1439 Py_END_ALLOW_THREADS
1463 #elif defined(MS_WINDOWS) 1440 #elif defined(MS_WINDOWS)
1464 { 1441 {
(...skipping 13 matching lines...) Expand all
1478 if (ul_millis == 0 || !_PyOS_IsMainThread()) 1455 if (ul_millis == 0 || !_PyOS_IsMainThread())
1479 Sleep(ul_millis); 1456 Sleep(ul_millis);
1480 else { 1457 else {
1481 DWORD rc; 1458 DWORD rc;
1482 HANDLE hInterruptEvent = _PyOS_SigintEvent(); 1459 HANDLE hInterruptEvent = _PyOS_SigintEvent();
1483 ResetEvent(hInterruptEvent); 1460 ResetEvent(hInterruptEvent);
1484 rc = WaitForSingleObjectEx(hInterruptEvent, ul_millis, FALSE); 1461 rc = WaitForSingleObjectEx(hInterruptEvent, ul_millis, FALSE);
1485 if (rc == WAIT_OBJECT_0) { 1462 if (rc == WAIT_OBJECT_0) {
1486 Py_BLOCK_THREADS 1463 Py_BLOCK_THREADS
1487 errno = EINTR; 1464 errno = EINTR;
1488 PyErr_SetFromErrno(PyExc_IOError); 1465 PyErr_SetFromErrno(PyExc_OSError);
1489 return -1; 1466 return -1;
1490 } 1467 }
1491 } 1468 }
1492 Py_END_ALLOW_THREADS 1469 Py_END_ALLOW_THREADS
1493 } 1470 }
1494 #else 1471 #else
1495 /* XXX Can't interrupt this sleep */ 1472 /* XXX Can't interrupt this sleep */
1496 Py_BEGIN_ALLOW_THREADS 1473 Py_BEGIN_ALLOW_THREADS
1497 sleep((int)secs); 1474 sleep((int)secs);
1498 Py_END_ALLOW_THREADS 1475 Py_END_ALLOW_THREADS
1499 #endif 1476 #endif
1500 1477
1501 return 0; 1478 return 0;
1502 } 1479 }
LEFTRIGHT

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