@cryptotaxi247 / netdata-1 / commits / c1be3331a

python plugin monotonic fix (#4156)

* python plugin monotonic fix * python monotonic lib: add SPD header

Ilya Mashchenko committed Sep 15, 2018 at 04:48 UTC c1be3331aa7acc209d5c3232ddb13c10900d50c0
5 files changed +181 -39
REDISTRIBUTED.md
+5
@@ -203,3 +203,8 @@ connectivity is not available.
203 Copyright (C) 2015 Barnaby Gale
204 [MIT License](https://raw.githubusercontent.com/barneygale/MCRcon/master/COPYING.txt)
205
206 +- [monotonic](https://github.com/atdt/monotonic)
207 +
208 + Copyright 2014, 2015, 2016 Ori Livneh <ori@wikimedia.org>
209 + [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0)
210 +
python.d/Makefile.am
+1 -1
@@ -86,7 +86,6 @@ dist_bases_DATA = \
86 python_modules/bases/collection.py \
87 python_modules/bases/loaders.py \
88 python_modules/bases/loggers.py \
89 - python_modules/bases/monotonic.py \
89 $(NULL)
90
91 bases_framework_servicesdir=$(basesdir)/FrameworkServices
@@ -107,6 +106,7 @@ dist_third_party_DATA = \
106 python_modules/third_party/lm_sensors.py \
107 python_modules/third_party/mcrcon.py \
108 python_modules/third_party/boinc_client.py \
109 + python_modules/third_party/monotonic.py \
110 $(NULL)
111
112 pythonyaml2dir=$(pythonmodulesdir)/pyyaml2
python.d/python_modules/bases/FrameworkServices/SimpleService.py
+4 -9
@@ -7,12 +7,7 @@
7 from threading import Thread
8 from time import sleep
9
10 -try:
11 - from time import monotonic as time
12 -except ImportError:
13 - from bases.monotonic import AVAILABLE, time
14 - if not AVAILABLE:
15 - from time import time
10 +from third_party.monotonic import monotonic
11
12 from bases.charts import Charts, ChartError, create_runtime_chart
13 from bases.collection import OldVersionCompatibility, safe_print
@@ -172,7 +167,7 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
167 'retries: {retries}'.format(freq=job.FREQ, retries=job.RETRIES_MAX - job.RETRIES))
168
169 while True:
175 - job.START_RUN = time()
170 + job.START_RUN = monotonic()
171
172 job.NEXT_RUN = job.START_RUN - (job.START_RUN % job.FREQ) + job.FREQ + job.PENALTY
173
@@ -193,7 +188,7 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
188 if not self.manage_retries():
189 return
190 else:
196 - job.ELAPSED = int((time() - job.START_RUN) * 1e3)
191 + job.ELAPSED = int((monotonic() - job.START_RUN) * 1e3)
192 job.PREV_UPDATE = job.START_RUN
193 job.RETRIES, job.PENALTY = 0, 0
194 safe_print(RUNTIME_CHART_UPDATE.format(job_name=self.name,
@@ -257,7 +252,7 @@ class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, objec
252 self.debug('sleeping for {sleep_time} to reach frequency of {freq} sec'.format(sleep_time=sleep_time,
253 freq=job.FREQ + job.PENALTY))
254 sleep(sleep_time)
260 - job.START_RUN = time()
255 + job.START_RUN = monotonic()
256
257 def get_data(self):
258 return self._get_data()
python.d/python_modules/bases/monotonic.py deleted
-29
@@ -1,29 +0,0 @@
1 -# thx to https://stackoverflow.com/a/1205762
2 -import ctypes
3 -# import os
4 -
5 -CLOCK_MONOTONIC = 1 # see <linux/time.h>
6 -
7 -
8 -class _Timespec(ctypes.Structure):
9 - _fields_ = [
10 - ('tv_sec', ctypes.c_long),
11 - ('tv_nsec', ctypes.c_long)
12 - ]
13 -
14 -
15 -_librt = ctypes.CDLL('librt.so.1', use_errno=True)
16 -_clock_gettime = _librt.clock_gettime
17 -_clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(_Timespec)]
18 -
19 -
20 -def time():
21 - t = _Timespec()
22 - if _clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(t)) != 0:
23 - # errno_ = ctypes.get_errno()
24 - # raise OSError(errno_, os.strerror(errno_))
25 - return None
26 - return t.tv_sec + t.tv_nsec * 1e-9
27 -
28 -
29 -AVAILABLE = bool(time())
python.d/python_modules/third_party/monotonic.py new
+171
@@ -0,0 +1,171 @@
1 +# -*- coding: utf-8 -*-
2 +#
3 +# SPDX-License-Identifier: Apache-2.0
4 +"""
5 + monotonic
6 + ~~~~~~~~~
7 +
8 + This module provides a ``monotonic()`` function which returns the
9 + value (in fractional seconds) of a clock which never goes backwards.
10 +
11 + On Python 3.3 or newer, ``monotonic`` will be an alias of
12 + ``time.monotonic`` from the standard library. On older versions,
13 + it will fall back to an equivalent implementation:
14 +
15 + +-------------+----------------------------------------+
16 + | Linux, BSD | ``clock_gettime(3)`` |
17 + +-------------+----------------------------------------+
18 + | Windows | ``GetTickCount`` or ``GetTickCount64`` |
19 + +-------------+----------------------------------------+
20 + | OS X | ``mach_absolute_time`` |
21 + +-------------+----------------------------------------+
22 +
23 + If no suitable implementation exists for the current platform,
24 + attempting to import this module (or to import from it) will
25 + cause a ``RuntimeError`` exception to be raised.
26 +
27 +
28 + Copyright 2014, 2015, 2016 Ori Livneh <ori@wikimedia.org>
29 +
30 + Licensed under the Apache License, Version 2.0 (the "License");
31 + you may not use this file except in compliance with the License.
32 + You may obtain a copy of the License at
33 +
34 + http://www.apache.org/licenses/LICENSE-2.0
35 +
36 + Unless required by applicable law or agreed to in writing, software
37 + distributed under the License is distributed on an "AS IS" BASIS,
38 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
39 + See the License for the specific language governing permissions and
40 + limitations under the License.
41 +
42 +"""
43 +import time
44 +
45 +
46 +__all__ = ('monotonic',)
47 +
48 +
49 +try:
50 + monotonic = time.monotonic
51 +except AttributeError:
52 + import ctypes
53 + import ctypes.util
54 + import os
55 + import sys
56 + import threading
57 + try:
58 + if sys.platform == 'darwin': # OS X, iOS
59 + # See Technical Q&A QA1398 of the Mac Developer Library:
60 + # <https://developer.apple.com/library/mac/qa/qa1398/>
61 + libc = ctypes.CDLL('/usr/lib/libc.dylib', use_errno=True)
62 +
63 + class mach_timebase_info_data_t(ctypes.Structure):
64 + """System timebase info. Defined in <mach/mach_time.h>."""
65 + _fields_ = (('numer', ctypes.c_uint32),
66 + ('denom', ctypes.c_uint32))
67 +
68 + mach_absolute_time = libc.mach_absolute_time
69 + mach_absolute_time.restype = ctypes.c_uint64
70 +
71 + timebase = mach_timebase_info_data_t()
72 + libc.mach_timebase_info(ctypes.byref(timebase))
73 + ticks_per_second = timebase.numer / timebase.denom * 1.0e9
74 +
75 + def monotonic():
76 + """Monotonic clock, cannot go backward."""
77 + return mach_absolute_time() / ticks_per_second
78 +
79 + elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
80 + if sys.platform.startswith('cygwin'):
81 + # Note: cygwin implements clock_gettime (CLOCK_MONOTONIC = 4) since
82 + # version 1.7.6. Using raw WinAPI for maximum version compatibility.
83 +
84 + # Ugly hack using the wrong calling convention (in 32-bit mode)
85 + # because ctypes has no windll under cygwin (and it also seems that
86 + # the code letting you select stdcall in _ctypes doesn't exist under
87 + # the preprocessor definitions relevant to cygwin).
88 + # This is 'safe' because:
89 + # 1. The ABI of GetTickCount and GetTickCount64 is identical for
90 + # both calling conventions because they both have no parameters.
91 + # 2. libffi masks the problem because after making the call it doesn't
92 + # touch anything through esp and epilogue code restores a correct
93 + # esp from ebp afterwards.
94 + try:
95 + kernel32 = ctypes.cdll.kernel32
96 + except OSError: # 'No such file or directory'
97 + kernel32 = ctypes.cdll.LoadLibrary('kernel32.dll')
98 + else:
99 + kernel32 = ctypes.windll.kernel32
100 +
101 + GetTickCount64 = getattr(kernel32, 'GetTickCount64', None)
102 + if GetTickCount64:
103 + # Windows Vista / Windows Server 2008 or newer.
104 + GetTickCount64.restype = ctypes.c_ulonglong
105 +
106 + def monotonic():
107 + """Monotonic clock, cannot go backward."""
108 + return GetTickCount64() / 1000.0
109 +
110 + else:
111 + # Before Windows Vista.
112 + GetTickCount = kernel32.GetTickCount
113 + GetTickCount.restype = ctypes.c_uint32
114 +
115 + get_tick_count_lock = threading.Lock()
116 + get_tick_count_last_sample = 0
117 + get_tick_count_wraparounds = 0
118 +
119 + def monotonic():
120 + """Monotonic clock, cannot go backward."""
121 + global get_tick_count_last_sample
122 + global get_tick_count_wraparounds
123 +
124 + with get_tick_count_lock:
125 + current_sample = GetTickCount()
126 + if current_sample < get_tick_count_last_sample:
127 + get_tick_count_wraparounds += 1
128 + get_tick_count_last_sample = current_sample
129 +
130 + final_milliseconds = get_tick_count_wraparounds << 32
131 + final_milliseconds += get_tick_count_last_sample
132 + return final_milliseconds / 1000.0
133 +
134 + else:
135 + try:
136 + clock_gettime = ctypes.CDLL(ctypes.util.find_library('c'),
137 + use_errno=True).clock_gettime
138 + except Exception:
139 + clock_gettime = ctypes.CDLL(ctypes.util.find_library('rt'),
140 + use_errno=True).clock_gettime
141 +
142 + class timespec(ctypes.Structure):
143 + """Time specification, as described in clock_gettime(3)."""
144 + _fields_ = (('tv_sec', ctypes.c_long),
145 + ('tv_nsec', ctypes.c_long))
146 +
147 + if sys.platform.startswith('linux'):
148 + CLOCK_MONOTONIC = 1
149 + elif sys.platform.startswith('freebsd'):
150 + CLOCK_MONOTONIC = 4
151 + elif sys.platform.startswith('sunos5'):
152 + CLOCK_MONOTONIC = 4
153 + elif 'bsd' in sys.platform:
154 + CLOCK_MONOTONIC = 3
155 + elif sys.platform.startswith('aix'):
156 + CLOCK_MONOTONIC = ctypes.c_longlong(10)
157 +
158 + def monotonic():
159 + """Monotonic clock, cannot go backward."""
160 + ts = timespec()
161 + if clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(ts)):
162 + errno = ctypes.get_errno()
163 + raise OSError(errno, os.strerror(errno))
164 + return ts.tv_sec + ts.tv_nsec / 1.0e9
165 +
166 + # Perform a sanity-check.
167 + if monotonic() - monotonic() > 0:
168 + raise ValueError('monotonic() is not monotonic!')
169 +
170 + except Exception as e:
171 + raise RuntimeError('no suitable implementation for this system: ' + repr(e))