1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
"""
Backport of time.monotonic() of Python 3.3 (PEP 418) for Python 2.7.
Export one function: time_monotonic(). This clock may or may not be monotonic
depending on the operating system.
Support Windows, Mac OS X, Linux, FreeBSD, OpenBSD and Solaris, but requires
the ctypes module.
"""
import os
import sys
__all__ = ('time_monotonic',)
# default implementation: system clock (non monotonic!)
from time import time as time_monotonic
if os.name == "nt":
# Windows: use GetTickCount64() or GetTickCount()
try:
import ctypes
from ctypes import windll
from ctypes.wintypes import DWORD
except ImportError:
pass
# GetTickCount64() requires Windows Vista, Server 2008 or later
if hasattr(windll.kernel32, 'GetTickCount64'):
ULONGLONG = ctypes.c_uint64
GetTickCount64 = windll.kernel32.GetTickCount64
GetTickCount64.restype = ULONGLONG
GetTickCount64.argtypes = ()
def time_monotonic():
return GetTickCount64() * 1e-3
else:
GetTickCount = windll.kernel32.GetTickCount
GetTickCount.restype = DWORD
GetTickCount.argtypes = ()
# Detect GetTickCount() integer overflow (32 bits, roll-over after 49.7
# days). It increases an internal epoch (reference time) by 2^32 each
# time that an overflow is detected. The epoch is stored in the
# process-local state and so the value of time_monotonic() may be
# different in two Python processes running for more than 49 days.
def time_monotonic(use_info):
ticks = GetTickCount()
if ticks < time_monotonic.last:
# Integer overflow detected
time_monotonic.delta += 2**32
time_monotonic.last = ticks
return (ticks + time_monotonic.delta) * 1e-3
time_monotonic.last = 0
time_monotonic.delta = 0
elif sys.platform == 'darwin':
# Mac OS X: use mach_absolute_time() and mach_timebase_info()
try:
import ctypes
import ctypes.util
libc_name = ctypes.util.find_library('c')
except ImportError:
libc_name = None
if libc_name:
libc = ctypes.CDLL(libc_name, use_errno=True)
mach_absolute_time = libc.mach_absolute_time
mach_absolute_time.argtypes = ()
mach_absolute_time.restype = ctypes.c_uint64
class mach_timebase_info_data_t(ctypes.Structure):
_fields_ = (
('numer', ctypes.c_uint32),
('denom', ctypes.c_uint32),
)
mach_timebase_info_data_p = ctypes.POINTER(mach_timebase_info_data_t)
mach_timebase_info = libc.mach_timebase_info
mach_timebase_info.argtypes = (mach_timebase_info_data_p,)
mach_timebase_info.restype = ctypes.c_int
def time_monotonic():
return mach_absolute_time() * time_monotonic.factor
timebase = mach_timebase_info_data_t()
mach_timebase_info(ctypes.byref(timebase))
time_monotonic.factor = float(timebase.numer) / timebase.denom * 1e-9
del timebase
elif sys.platform.startswith(("linux", "freebsd", "openbsd", "sunos")):
# Linux, FreeBSD, OpenBSD: use clock_gettime(CLOCK_MONOTONIC)
# Solaris: use clock_gettime(CLOCK_HIGHRES)
library = None
try:
import ctypes
import ctypes.util
except ImportError:
libraries = ()
else:
if sys.platform.startswith(("freebsd", "openbsd")):
libraries = ('c',)
elif sys.platform.startswith("linux"):
# Linux: in glibc 2.17+, clock_gettime() is provided by the libc,
# on older versions, it is provided by librt
libraries = ('c', 'rt')
else:
# Solaris
libraries = ('rt',)
for name in libraries:
filename = ctypes.util.find_library(name)
if not filename:
continue
library = ctypes.CDLL(filename, use_errno=True)
if not hasattr(library, 'clock_gettime'):
library = None
if library is not None:
time_t = ctypes.c_long
clockid_t = ctypes.c_int
class timespec(ctypes.Structure):
_fields_ = (
('tv_sec', time_t),
('tv_nsec', ctypes.c_long),
)
timespec_p = ctypes.POINTER(timespec)
clock_gettime = library.clock_gettime
clock_gettime.argtypes = (clockid_t, timespec_p)
clock_gettime.restype = ctypes.c_int
def time_monotonic():
ts = timespec()
err = clock_gettime(time_monotonic.clk_id, ctypes.byref(ts))
if err:
errno = ctypes.get_errno()
message = os.strerror(errno)
return OSError(errno, message)
return ts.tv_sec + ts.tv_nsec * 1e-9
if sys.platform.startswith("linux"):
time_monotonic.clk_id = 1 # CLOCK_MONOTONIC
elif sys.platform.startswith("freebsd"):
time_monotonic.clk_id = 4 # CLOCK_MONOTONIC
elif sys.platform.startswith("openbsd"):
time_monotonic.clk_id = 3 # CLOCK_MONOTONIC
elif sys.platform.startswith("sunos"):
time_monotonic.clk_id = 4 # CLOCK_HIGHRES
|