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

Side by Side Diff: Modules/timemodule.c

Issue 22043: Use a monotonic clock to compute timeouts
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:
View unified diff | Download patch
« no previous file with comments | « Modules/socketmodule.c ('k') | Python/pytime.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 18 matching lines...) Expand all
29 #include "pythread.h" 29 #include "pythread.h"
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
40 #if defined(__APPLE__)
41 #include <mach/mach_time.h>
42 #endif
43 39
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 *
(...skipping 839 matching lines...) Expand 10 before | Expand all | Expand 10 after
892 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\
893 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\
894 (eg. 'US/Eastern', 'Europe/Amsterdam'). Unknown timezones will silently\n\ 890 (eg. 'US/Eastern', 'Europe/Amsterdam'). Unknown timezones will silently\n\
895 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\
896 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\
897 Changing the TZ environment variable without calling tzset *may* change\n\ 893 Changing the TZ environment variable without calling tzset *may* change\n\
898 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\
899 should not be relied on."); 895 should not be relied on.");
900 #endif /* HAVE_WORKING_TZSET */ 896 #endif /* HAVE_WORKING_TZSET */
901 897
902 #if defined(MS_WINDOWS) || defined(__APPLE__) \ 898 static PyObject *
903 || (defined(HAVE_CLOCK_GETTIME) \
904 && (defined(CLOCK_HIGHRES) || defined(CLOCK_MONOTONIC)))
905 #define PYMONOTONIC
906 #endif
907
908 #ifdef PYMONOTONIC
909 static PyObject*
910 pymonotonic(_Py_clock_info_t *info) 899 pymonotonic(_Py_clock_info_t *info)
911 { 900 {
912 #if defined(MS_WINDOWS) 901 _PyTime_timeval tv;
913 static ULONGLONG (*GetTickCount64) (void) = NULL; 902 if (_PyTime_monotonic_info(&tv, info) < 0) {
914 static ULONGLONG (CALLBACK *Py_GetTickCount64)(void); 903 assert(info != NULL);
915 static int has_getickcount64 = -1;
916 double result;
917
918 if (has_getickcount64 == -1) {
919 /* GetTickCount64() was added to Windows Vista */
920 if (winver.dwMajorVersion >= 6) {
921 HINSTANCE hKernel32;
922 hKernel32 = GetModuleHandleW(L"KERNEL32");
923 *(FARPROC*)&Py_GetTickCount64 = GetProcAddress(hKernel32,
924 "GetTickCount64");
925 has_getickcount64 = (Py_GetTickCount64 != NULL);
926 }
927 else
928 has_getickcount64 = 0;
929 }
930
931 if (has_getickcount64) {
932 ULONGLONG ticks;
933 ticks = Py_GetTickCount64();
934 result = (double)ticks * 1e-3;
935 }
936 else {
937 static DWORD last_ticks = 0;
938 static DWORD n_overflow = 0;
939 DWORD ticks;
940
941 ticks = GetTickCount();
942 if (ticks < last_ticks)
943 n_overflow++;
944 last_ticks = ticks;
945
946 result = ldexp(n_overflow, 32);
947 result += ticks;
948 result *= 1e-3;
949 }
950
951 if (info) {
952 DWORD timeAdjustment, timeIncrement;
953 BOOL isTimeAdjustmentDisabled, ok;
954 if (has_getickcount64)
955 info->implementation = "GetTickCount64()";
956 else
957 info->implementation = "GetTickCount()";
958 info->monotonic = 1;
959 ok = GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement,
960 &isTimeAdjustmentDisabled);
961 if (!ok) {
962 PyErr_SetFromWindowsErr(0);
963 return NULL;
964 }
965 info->resolution = timeIncrement * 1e-7;
966 info->adjustable = 0;
967 }
968 return PyFloat_FromDouble(result);
969
970 #elif defined(__APPLE__)
971 static mach_timebase_info_data_t timebase;
972 uint64_t time;
973 double secs;
974
975 if (timebase.denom == 0) {
976 /* According to the Technical Q&A QA1398, mach_timebase_info() cannot
977 fail: https://developer.apple.com/library/mac/#qa/qa1398/ */
978 (void)mach_timebase_info(&timebase);
979 }
980
981 time = mach_absolute_time();
982 secs = (double)time * timebase.numer / timebase.denom * 1e-9;
983 if (info) {
984 info->implementation = "mach_absolute_time()";
985 info->resolution = (double)timebase.numer / timebase.denom * 1e-9;
986 info->monotonic = 1;
987 info->adjustable = 0;
988 }
989 return PyFloat_FromDouble(secs);
990
991 #elif defined(HAVE_CLOCK_GETTIME) && (defined(CLOCK_HIGHRES) || defined(CLOCK_MO NOTONIC))
992 struct timespec tp;
993 #ifdef CLOCK_HIGHRES
994 const clockid_t clk_id = CLOCK_HIGHRES;
995 const char *function = "clock_gettime(CLOCK_HIGHRES)";
996 #else
997 const clockid_t clk_id = CLOCK_MONOTONIC;
998 const char *function = "clock_gettime(CLOCK_MONOTONIC)";
999 #endif
1000
1001 if (clock_gettime(clk_id, &tp) != 0) {
1002 PyErr_SetFromErrno(PyExc_OSError);
1003 return NULL; 904 return NULL;
1004 } 905 }
1005 906 return PyFloat_FromDouble((double)tv.tv_sec + tv.tv_usec * 1e-6);
1006 if (info) {
1007 struct timespec res;
1008 info->monotonic = 1;
1009 info->implementation = function;
1010 info->adjustable = 0;
1011 if (clock_getres(clk_id, &res) == 0)
1012 info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
1013 else
1014 info->resolution = 1e-9;
1015 }
1016 return PyFloat_FromDouble(tp.tv_sec + tp.tv_nsec * 1e-9);
1017 #endif
1018 } 907 }
1019 908
1020 static PyObject * 909 static PyObject *
1021 time_monotonic(PyObject *self, PyObject *unused) 910 time_monotonic(PyObject *self, PyObject *unused)
1022 { 911 {
1023 return pymonotonic(NULL); 912 return pymonotonic(NULL);
1024 } 913 }
1025 914
1026 PyDoc_STRVAR(monotonic_doc, 915 PyDoc_STRVAR(monotonic_doc,
1027 "monotonic() -> float\n\ 916 "monotonic() -> float\n\
1028 \n\ 917 \n\
1029 Monotonic clock, cannot go backward."); 918 Monotonic clock, cannot go backward.");
1030 #endif /* PYMONOTONIC */
1031 919
1032 static PyObject* 920 static PyObject*
1033 perf_counter(_Py_clock_info_t *info) 921 perf_counter(_Py_clock_info_t *info)
1034 { 922 {
1035 #ifdef WIN32_PERF_COUNTER 923 #ifdef WIN32_PERF_COUNTER
1036 return win_perf_counter(info); 924 return win_perf_counter(info);
1037 #else 925 #else
1038 926 return pymonotonic(info);
1039 #ifdef PYMONOTONIC
1040 static int use_monotonic = 1;
1041
1042 if (use_monotonic) {
1043 PyObject *res = pymonotonic(info);
1044 if (res != NULL)
1045 return res;
1046 use_monotonic = 0;
1047 PyErr_Clear();
1048 }
1049 #endif
1050 return floattime(info);
1051
1052 #endif 927 #endif
1053 } 928 }
1054 929
1055 static PyObject * 930 static PyObject *
1056 time_perf_counter(PyObject *self, PyObject *unused) 931 time_perf_counter(PyObject *self, PyObject *unused)
1057 { 932 {
1058 return perf_counter(NULL); 933 return perf_counter(NULL);
1059 } 934 }
1060 935
1061 PyDoc_STRVAR(perf_counter_doc, 936 PyDoc_STRVAR(perf_counter_doc,
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
1209 info.adjustable = 0; 1084 info.adjustable = 0;
1210 info.resolution = 1.0; 1085 info.resolution = 1.0;
1211 #endif 1086 #endif
1212 1087
1213 if (strcmp(name, "time") == 0) 1088 if (strcmp(name, "time") == 0)
1214 obj = floattime(&info); 1089 obj = floattime(&info);
1215 #ifdef PYCLOCK 1090 #ifdef PYCLOCK
1216 else if (strcmp(name, "clock") == 0) 1091 else if (strcmp(name, "clock") == 0)
1217 obj = pyclock(&info); 1092 obj = pyclock(&info);
1218 #endif 1093 #endif
1219 #ifdef PYMONOTONIC
1220 else if (strcmp(name, "monotonic") == 0) 1094 else if (strcmp(name, "monotonic") == 0)
1221 obj = pymonotonic(&info); 1095 obj = pymonotonic(&info);
1222 #endif
1223 else if (strcmp(name, "perf_counter") == 0) 1096 else if (strcmp(name, "perf_counter") == 0)
1224 obj = perf_counter(&info); 1097 obj = perf_counter(&info);
1225 else if (strcmp(name, "process_time") == 0) 1098 else if (strcmp(name, "process_time") == 0)
1226 obj = py_process_time(&info); 1099 obj = py_process_time(&info);
1227 else { 1100 else {
1228 PyErr_SetString(PyExc_ValueError, "unknown clock"); 1101 PyErr_SetString(PyExc_ValueError, "unknown clock");
1229 return NULL; 1102 return NULL;
1230 } 1103 }
1231 if (obj == NULL) 1104 if (obj == NULL)
1232 return NULL; 1105 return NULL;
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
1404 #ifdef HAVE_MKTIME 1277 #ifdef HAVE_MKTIME
1405 {"mktime", time_mktime, METH_O, mktime_doc}, 1278 {"mktime", time_mktime, METH_O, mktime_doc},
1406 #endif 1279 #endif
1407 #ifdef HAVE_STRFTIME 1280 #ifdef HAVE_STRFTIME
1408 {"strftime", time_strftime, METH_VARARGS, strftime_doc}, 1281 {"strftime", time_strftime, METH_VARARGS, strftime_doc},
1409 #endif 1282 #endif
1410 {"strptime", time_strptime, METH_VARARGS, strptime_doc}, 1283 {"strptime", time_strptime, METH_VARARGS, strptime_doc},
1411 #ifdef HAVE_WORKING_TZSET 1284 #ifdef HAVE_WORKING_TZSET
1412 {"tzset", time_tzset, METH_NOARGS, tzset_doc}, 1285 {"tzset", time_tzset, METH_NOARGS, tzset_doc},
1413 #endif 1286 #endif
1414 #ifdef PYMONOTONIC
1415 {"monotonic", time_monotonic, METH_NOARGS, monotonic_doc}, 1287 {"monotonic", time_monotonic, METH_NOARGS, monotonic_doc},
1416 #endif
1417 {"process_time", time_process_time, METH_NOARGS, process_time_doc}, 1288 {"process_time", time_process_time, METH_NOARGS, process_time_doc},
1418 {"perf_counter", time_perf_counter, METH_NOARGS, perf_counter_doc}, 1289 {"perf_counter", time_perf_counter, METH_NOARGS, perf_counter_doc},
1419 {"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},
1420 {NULL, NULL} /* sentinel */ 1291 {NULL, NULL} /* sentinel */
1421 }; 1292 };
1422 1293
1423 1294
1424 PyDoc_STRVAR(module_doc, 1295 PyDoc_STRVAR(module_doc,
1425 "This module provides various functions to manipulate time values.\n\ 1296 "This module provides various functions to manipulate time values.\n\
1426 \n\ 1297 \n\
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
1599 } 1470 }
1600 #else 1471 #else
1601 /* XXX Can't interrupt this sleep */ 1472 /* XXX Can't interrupt this sleep */
1602 Py_BEGIN_ALLOW_THREADS 1473 Py_BEGIN_ALLOW_THREADS
1603 sleep((int)secs); 1474 sleep((int)secs);
1604 Py_END_ALLOW_THREADS 1475 Py_END_ALLOW_THREADS
1605 #endif 1476 #endif
1606 1477
1607 return 0; 1478 return 0;
1608 } 1479 }
OLDNEW
« no previous file with comments | « Modules/socketmodule.c ('k') | Python/pytime.c » ('j') | no next file with comments »

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