Skip to content
This repository was archived by the owner on Oct 13, 2021. It is now read-only.

Commit 153d004

Browse files
authored
[internal] Vendor monotonic package (#1026)
1 parent 7ccf106 commit 153d004

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed

ddtrace/vendor/__init__.py

+13
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,17 @@
5959
`dogstatsd/__init__.py` was updated to include a copy of the `datadogpy` license: https://github.com/DataDog/datadogpy/blob/master/LICENSE
6060
Only `datadog.dogstatsd` module was vendored to avoid unnecessary dependencies
6161
`datadog/util/compat.py` was copied to `dogstatsd/compat.py`
62+
63+
monotonic
64+
---------
65+
66+
Website: https://pypi.org/project/monotonic/
67+
Source: https://github.com/atdt/monotonic
68+
Version: 1.5
69+
License: Apache License 2.0
70+
71+
Notes:
72+
The source `monotonic.py` was added as `monotonic/__init__.py`
73+
74+
No other changes were made
6275
"""

ddtrace/vendor/monotonic/__init__.py

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
monotonic
4+
~~~~~~~~~
5+
6+
This module provides a ``monotonic()`` function which returns the
7+
value (in fractional seconds) of a clock which never goes backwards.
8+
9+
On Python 3.3 or newer, ``monotonic`` will be an alias of
10+
``time.monotonic`` from the standard library. On older versions,
11+
it will fall back to an equivalent implementation:
12+
13+
+-------------+----------------------------------------+
14+
| Linux, BSD | ``clock_gettime(3)`` |
15+
+-------------+----------------------------------------+
16+
| Windows | ``GetTickCount`` or ``GetTickCount64`` |
17+
+-------------+----------------------------------------+
18+
| OS X | ``mach_absolute_time`` |
19+
+-------------+----------------------------------------+
20+
21+
If no suitable implementation exists for the current platform,
22+
attempting to import this module (or to import from it) will
23+
cause a ``RuntimeError`` exception to be raised.
24+
25+
26+
Copyright 2014, 2015, 2016 Ori Livneh <[email protected]>
27+
28+
Licensed under the Apache License, Version 2.0 (the "License");
29+
you may not use this file except in compliance with the License.
30+
You may obtain a copy of the License at
31+
32+
http://www.apache.org/licenses/LICENSE-2.0
33+
34+
Unless required by applicable law or agreed to in writing, software
35+
distributed under the License is distributed on an "AS IS" BASIS,
36+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
37+
See the License for the specific language governing permissions and
38+
limitations under the License.
39+
40+
"""
41+
import time
42+
43+
44+
__all__ = ('monotonic',)
45+
46+
47+
try:
48+
monotonic = time.monotonic
49+
except AttributeError:
50+
import ctypes
51+
import ctypes.util
52+
import os
53+
import sys
54+
import threading
55+
try:
56+
if sys.platform == 'darwin': # OS X, iOS
57+
# See Technical Q&A QA1398 of the Mac Developer Library:
58+
# <https://developer.apple.com/library/mac/qa/qa1398/>
59+
libc = ctypes.CDLL('/usr/lib/libc.dylib', use_errno=True)
60+
61+
class mach_timebase_info_data_t(ctypes.Structure):
62+
"""System timebase info. Defined in <mach/mach_time.h>."""
63+
_fields_ = (('numer', ctypes.c_uint32),
64+
('denom', ctypes.c_uint32))
65+
66+
mach_absolute_time = libc.mach_absolute_time
67+
mach_absolute_time.restype = ctypes.c_uint64
68+
69+
timebase = mach_timebase_info_data_t()
70+
libc.mach_timebase_info(ctypes.byref(timebase))
71+
ticks_per_second = timebase.numer / timebase.denom * 1.0e9
72+
73+
def monotonic():
74+
"""Monotonic clock, cannot go backward."""
75+
return mach_absolute_time() / ticks_per_second
76+
77+
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
78+
if sys.platform.startswith('cygwin'):
79+
# Note: cygwin implements clock_gettime (CLOCK_MONOTONIC = 4) since
80+
# version 1.7.6. Using raw WinAPI for maximum version compatibility.
81+
82+
# Ugly hack using the wrong calling convention (in 32-bit mode)
83+
# because ctypes has no windll under cygwin (and it also seems that
84+
# the code letting you select stdcall in _ctypes doesn't exist under
85+
# the preprocessor definitions relevant to cygwin).
86+
# This is 'safe' because:
87+
# 1. The ABI of GetTickCount and GetTickCount64 is identical for
88+
# both calling conventions because they both have no parameters.
89+
# 2. libffi masks the problem because after making the call it doesn't
90+
# touch anything through esp and epilogue code restores a correct
91+
# esp from ebp afterwards.
92+
try:
93+
kernel32 = ctypes.cdll.kernel32
94+
except OSError: # 'No such file or directory'
95+
kernel32 = ctypes.cdll.LoadLibrary('kernel32.dll')
96+
else:
97+
kernel32 = ctypes.windll.kernel32
98+
99+
GetTickCount64 = getattr(kernel32, 'GetTickCount64', None)
100+
if GetTickCount64:
101+
# Windows Vista / Windows Server 2008 or newer.
102+
GetTickCount64.restype = ctypes.c_ulonglong
103+
104+
def monotonic():
105+
"""Monotonic clock, cannot go backward."""
106+
return GetTickCount64() / 1000.0
107+
108+
else:
109+
# Before Windows Vista.
110+
GetTickCount = kernel32.GetTickCount
111+
GetTickCount.restype = ctypes.c_uint32
112+
113+
get_tick_count_lock = threading.Lock()
114+
get_tick_count_last_sample = 0
115+
get_tick_count_wraparounds = 0
116+
117+
def monotonic():
118+
"""Monotonic clock, cannot go backward."""
119+
global get_tick_count_last_sample
120+
global get_tick_count_wraparounds
121+
122+
with get_tick_count_lock:
123+
current_sample = GetTickCount()
124+
if current_sample < get_tick_count_last_sample:
125+
get_tick_count_wraparounds += 1
126+
get_tick_count_last_sample = current_sample
127+
128+
final_milliseconds = get_tick_count_wraparounds << 32
129+
final_milliseconds += get_tick_count_last_sample
130+
return final_milliseconds / 1000.0
131+
132+
else:
133+
try:
134+
clock_gettime = ctypes.CDLL(ctypes.util.find_library('c'),
135+
use_errno=True).clock_gettime
136+
except Exception:
137+
clock_gettime = ctypes.CDLL(ctypes.util.find_library('rt'),
138+
use_errno=True).clock_gettime
139+
140+
class timespec(ctypes.Structure):
141+
"""Time specification, as described in clock_gettime(3)."""
142+
_fields_ = (('tv_sec', ctypes.c_long),
143+
('tv_nsec', ctypes.c_long))
144+
145+
if sys.platform.startswith('linux'):
146+
CLOCK_MONOTONIC = 1
147+
elif sys.platform.startswith('freebsd'):
148+
CLOCK_MONOTONIC = 4
149+
elif sys.platform.startswith('sunos5'):
150+
CLOCK_MONOTONIC = 4
151+
elif 'bsd' in sys.platform:
152+
CLOCK_MONOTONIC = 3
153+
elif sys.platform.startswith('aix'):
154+
CLOCK_MONOTONIC = ctypes.c_longlong(10)
155+
156+
def monotonic():
157+
"""Monotonic clock, cannot go backward."""
158+
ts = timespec()
159+
if clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(ts)):
160+
errno = ctypes.get_errno()
161+
raise OSError(errno, os.strerror(errno))
162+
return ts.tv_sec + ts.tv_nsec / 1.0e9
163+
164+
# Perform a sanity-check.
165+
if monotonic() - monotonic() > 0:
166+
raise ValueError('monotonic() is not monotonic!')
167+
168+
except Exception as e:
169+
raise RuntimeError('no suitable implementation for this system: ' + repr(e))

0 commit comments

Comments
 (0)