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

Side by Side Diff: Modules/timemodule.c

Issue 22043: Use a monotonic clock to compute timeouts
Patch Set: Created 5 years, 4 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
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 885 matching lines...) Expand 10 before | Expand all | Expand 10 after
896 os.environ['TZ']. The TZ environment variable should be specified in\n\ 896 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\ 897 standard Unix timezone format as documented in the tzset man page\n\
898 (eg. 'US/Eastern', 'Europe/Amsterdam'). Unknown timezones will silently\n\ 898 (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\ 899 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\ 900 timezone is set to the systems best guess of wallclock time.\n\
901 Changing the TZ environment variable without calling tzset *may* change\n\ 901 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\ 902 the local timezone used by methods such as localtime, but this behaviour\n\
903 should not be relied on."); 903 should not be relied on.");
904 #endif /* HAVE_WORKING_TZSET */ 904 #endif /* HAVE_WORKING_TZSET */
905 905
906 #if defined(MS_WINDOWS) || defined(__APPLE__) \
907 || (defined(HAVE_CLOCK_GETTIME) \
908 && (defined(CLOCK_HIGHRES) || defined(CLOCK_MONOTONIC)))
909 #define PYMONOTONIC
910 #endif
911
912 #ifdef PYMONOTONIC
913 static PyObject* 906 static PyObject*
914 pymonotonic(_Py_clock_info_t *info) 907 pymonotonic(_Py_clock_info_t *info)
915 { 908 {
916 #if defined(MS_WINDOWS) 909 _PyTime_timespec ts;
917 static ULONGLONG (*GetTickCount64) (void) = NULL;
918 static ULONGLONG (CALLBACK *Py_GetTickCount64)(void);
919 static int has_getickcount64 = -1;
920 double result;
921 910
922 if (has_getickcount64 == -1) { 911 if (_PyTime_monotonic_info(&ts, info) < 0)
923 /* GetTickCount64() was added to Windows Vista */ 912 return NULL;
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 913
935 if (has_getickcount64) { 914 return PyFloat_FromDouble(ts.tv_sec + ts.tv_nsec * 1e-9);
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 } 915 }
1023 916
1024 static PyObject * 917 static PyObject *
1025 time_monotonic(PyObject *self, PyObject *unused) 918 time_monotonic(PyObject *self, PyObject *unused)
1026 { 919 {
1027 return pymonotonic(NULL); 920 return pymonotonic(NULL);
1028 } 921 }
1029 922
1030 PyDoc_STRVAR(monotonic_doc, 923 PyDoc_STRVAR(monotonic_doc,
1031 "monotonic() -> float\n\ 924 "monotonic() -> float\n\
1032 \n\ 925 \n\
1033 Monotonic clock, cannot go backward."); 926 Monotonic clock, cannot go backward.");
1034 #endif /* PYMONOTONIC */
1035 927
1036 static PyObject* 928 static PyObject*
1037 perf_counter(_Py_clock_info_t *info) 929 perf_counter(_Py_clock_info_t *info)
1038 { 930 {
1039 #if defined(WIN32_PERF_COUNTER) || defined(PYMONOTONIC)
1040 PyObject *res; 931 PyObject *res;
1041 #endif 932 #ifdef WIN32_PERF_COUNTER
1042 #if defined(WIN32_PERF_COUNTER)
1043 static int use_perf_counter = 1; 933 static int use_perf_counter = 1;
1044 #endif 934 #endif
1045 #ifdef PYMONOTONIC
1046 static int use_monotonic = 1; 935 static int use_monotonic = 1;
1047 #endif
1048 936
1049 #ifdef WIN32_PERF_COUNTER 937 #ifdef WIN32_PERF_COUNTER
1050 if (use_perf_counter) { 938 if (use_perf_counter) {
1051 if (win_perf_counter(info, &res) == 0) 939 if (win_perf_counter(info, &res) == 0)
1052 return res; 940 return res;
1053 use_perf_counter = 0; 941 use_perf_counter = 0;
1054 } 942 }
1055 #endif 943 #endif
1056 944
1057 #ifdef PYMONOTONIC
1058 if (use_monotonic) { 945 if (use_monotonic) {
1059 res = pymonotonic(info); 946 res = pymonotonic(info);
1060 if (res != NULL) 947 if (res != NULL)
1061 return res; 948 return res;
1062 use_monotonic = 0; 949 use_monotonic = 0;
1063 PyErr_Clear(); 950 PyErr_Clear();
1064 } 951 }
1065 #endif
1066 952
1067 return floattime(info); 953 return floattime(info);
1068 } 954 }
1069 955
1070 static PyObject * 956 static PyObject *
1071 time_perf_counter(PyObject *self, PyObject *unused) 957 time_perf_counter(PyObject *self, PyObject *unused)
1072 { 958 {
1073 return perf_counter(NULL); 959 return perf_counter(NULL);
1074 } 960 }
1075 961
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
1224 info.adjustable = 0; 1110 info.adjustable = 0;
1225 info.resolution = 1.0; 1111 info.resolution = 1.0;
1226 #endif 1112 #endif
1227 1113
1228 if (strcmp(name, "time") == 0) 1114 if (strcmp(name, "time") == 0)
1229 obj = floattime(&info); 1115 obj = floattime(&info);
1230 #ifdef PYCLOCK 1116 #ifdef PYCLOCK
1231 else if (strcmp(name, "clock") == 0) 1117 else if (strcmp(name, "clock") == 0)
1232 obj = pyclock(&info); 1118 obj = pyclock(&info);
1233 #endif 1119 #endif
1234 #ifdef PYMONOTONIC
1235 else if (strcmp(name, "monotonic") == 0) 1120 else if (strcmp(name, "monotonic") == 0)
1236 obj = pymonotonic(&info); 1121 obj = pymonotonic(&info);
1237 #endif
1238 else if (strcmp(name, "perf_counter") == 0) 1122 else if (strcmp(name, "perf_counter") == 0)
1239 obj = perf_counter(&info); 1123 obj = perf_counter(&info);
1240 else if (strcmp(name, "process_time") == 0) 1124 else if (strcmp(name, "process_time") == 0)
1241 obj = py_process_time(&info); 1125 obj = py_process_time(&info);
1242 else { 1126 else {
1243 PyErr_SetString(PyExc_ValueError, "unknown clock"); 1127 PyErr_SetString(PyExc_ValueError, "unknown clock");
1244 return NULL; 1128 return NULL;
1245 } 1129 }
1246 if (obj == NULL) 1130 if (obj == NULL)
1247 return NULL; 1131 return NULL;
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
1419 #ifdef HAVE_MKTIME 1303 #ifdef HAVE_MKTIME
1420 {"mktime", time_mktime, METH_O, mktime_doc}, 1304 {"mktime", time_mktime, METH_O, mktime_doc},
1421 #endif 1305 #endif
1422 #ifdef HAVE_STRFTIME 1306 #ifdef HAVE_STRFTIME
1423 {"strftime", time_strftime, METH_VARARGS, strftime_doc}, 1307 {"strftime", time_strftime, METH_VARARGS, strftime_doc},
1424 #endif 1308 #endif
1425 {"strptime", time_strptime, METH_VARARGS, strptime_doc}, 1309 {"strptime", time_strptime, METH_VARARGS, strptime_doc},
1426 #ifdef HAVE_WORKING_TZSET 1310 #ifdef HAVE_WORKING_TZSET
1427 {"tzset", time_tzset, METH_NOARGS, tzset_doc}, 1311 {"tzset", time_tzset, METH_NOARGS, tzset_doc},
1428 #endif 1312 #endif
1429 #ifdef PYMONOTONIC
1430 {"monotonic", time_monotonic, METH_NOARGS, monotonic_doc}, 1313 {"monotonic", time_monotonic, METH_NOARGS, monotonic_doc},
1431 #endif
1432 {"process_time", time_process_time, METH_NOARGS, process_time_doc}, 1314 {"process_time", time_process_time, METH_NOARGS, process_time_doc},
1433 {"perf_counter", time_perf_counter, METH_NOARGS, perf_counter_doc}, 1315 {"perf_counter", time_perf_counter, METH_NOARGS, perf_counter_doc},
1434 {"get_clock_info", time_get_clock_info, METH_VARARGS, get_clock_info_doc}, 1316 {"get_clock_info", time_get_clock_info, METH_VARARGS, get_clock_info_doc},
1435 {NULL, NULL} /* sentinel */ 1317 {NULL, NULL} /* sentinel */
1436 }; 1318 };
1437 1319
1438 1320
1439 PyDoc_STRVAR(module_doc, 1321 PyDoc_STRVAR(module_doc,
1440 "This module provides various functions to manipulate time values.\n\ 1322 "This module provides various functions to manipulate time values.\n\
1441 \n\ 1323 \n\
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
1527 PyModule_AddIntConstant(m, "_STRUCT_TM_ITEMS", 9); 1409 PyModule_AddIntConstant(m, "_STRUCT_TM_ITEMS", 9);
1528 #endif 1410 #endif
1529 PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType); 1411 PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType);
1530 initialized = 1; 1412 initialized = 1;
1531 return m; 1413 return m;
1532 } 1414 }
1533 1415
1534 static PyObject* 1416 static PyObject*
1535 floattime(_Py_clock_info_t *info) 1417 floattime(_Py_clock_info_t *info)
1536 { 1418 {
1537 _PyTime_timeval t; 1419 _PyTime_timespec ts;
1538 #ifdef HAVE_CLOCK_GETTIME 1420 _PyTime_gettimeofday_info(&ts, info);
1539 struct timespec tp; 1421 return PyFloat_FromDouble((double)ts.tv_sec + ts.tv_nsec * 1e-9);
1540 int ret;
1541
1542 /* _PyTime_gettimeofday() does not use clock_gettime()
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 _PyTime_gettimeofday_info(&t, info);
1561 return PyFloat_FromDouble((double)t.tv_sec + t.tv_usec * 1e-6);
1562 } 1422 }
1563 1423
1564 1424
1565 /* Implement floatsleep() for various platforms. 1425 /* Implement floatsleep() for various platforms.
1566 When interrupted (or when another error occurs), return -1 and 1426 When interrupted (or when another error occurs), return -1 and
1567 set an exception; else return 0. */ 1427 set an exception; else return 0. */
1568 1428
1569 static int 1429 static int
1570 floatsleep(double secs) 1430 floatsleep(double secs)
1571 { 1431 {
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
1633 } 1493 }
1634 #else 1494 #else
1635 /* XXX Can't interrupt this sleep */ 1495 /* XXX Can't interrupt this sleep */
1636 Py_BEGIN_ALLOW_THREADS 1496 Py_BEGIN_ALLOW_THREADS
1637 sleep((int)secs); 1497 sleep((int)secs);
1638 Py_END_ALLOW_THREADS 1498 Py_END_ALLOW_THREADS
1639 #endif 1499 #endif
1640 1500
1641 return 0; 1501 return 0;
1642 } 1502 }
OLDNEW

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