Skip to content
Snippets Groups Projects
Commit 34b915ac authored by David Hammer's avatar David Hammer
Browse files

Improving, simplifying timers

parent 8b3128b5
2 merge requests!12Snapshot: field test deployed version as of end of run 202201,!3Base correction device, CalCat interaction, DSSC and AGIPD devices
...@@ -3,7 +3,7 @@ import functools ...@@ -3,7 +3,7 @@ import functools
import inspect import inspect
import threading import threading
import time import time
import timeit from timeit import default_timer
import numpy as np import numpy as np
...@@ -164,11 +164,9 @@ class RepeatingTimer: ...@@ -164,11 +164,9 @@ class RepeatingTimer:
self, self,
interval, interval,
callback, callback,
timer=timeit.default_timer,
start_now=True, start_now=True,
daemon=True, daemon=True,
): ):
self.timer = timer
self.stopped = True self.stopped = True
self.interval = interval self.interval = interval
self.callback = callback self.callback = callback
...@@ -178,19 +176,19 @@ class RepeatingTimer: ...@@ -178,19 +176,19 @@ class RepeatingTimer:
def start(self): def start(self):
self.stopped = False self.stopped = False
self.wakeup_time = self.timer() + self.interval self.wakeup_time = default_timer() + self.interval
def runner(): def runner():
while not self.stopped: while not self.stopped:
now = self.timer() now = default_timer()
while now < self.wakeup_time: while now < self.wakeup_time:
diff = self.wakeup_time - now diff = self.wakeup_time - now
time.sleep(diff) time.sleep(diff)
if self.stopped: if self.stopped:
return return
now = self.timer() now = default_timer()
self.callback() self.callback()
self.wakeup_time = self.timer() + self.interval self.wakeup_time = default_timer() + self.interval
self.thread = threading.Thread(target=runner, daemon=self.daemonize) self.thread = threading.Thread(target=runner, daemon=self.daemonize)
self.thread.start() self.thread.start()
...@@ -217,26 +215,72 @@ class ExponentialMovingAverage: ...@@ -217,26 +215,72 @@ class ExponentialMovingAverage:
class WindowRateTracker: class WindowRateTracker:
def __init__(self, buffer_size=20, time_window=20, timer=timeit.default_timer): def __init__(self, buffer_size=20, time_window=10):
self.time_window = time_window self.time_window = time_window
self.buffer_size = buffer_size self.buffer_size = buffer_size
self.deque = collections.deque(maxlen=self.buffer_size) self.deque = collections.deque(maxlen=self.buffer_size)
self.timer = timer
def update(self): def update(self):
now = self.timer() self.deque.append(default_timer())
self.deque.append(now)
def get(self): def get(self):
now = self.timer() now = default_timer()
cutoff = now - self.time_window cutoff = now - self.time_window
try: try:
while self.deque[0] < cutoff: while self.deque[0] < cutoff:
self.deque.popleft() self.deque.popleft()
except IndexError: except IndexError:
return 0 return 0
if len(self.deque) < 2:
return 0
if len(self.deque) < self.buffer_size: if len(self.deque) < self.buffer_size:
# TODO: estimator avoiding ramp-up of when starting anew
return len(self.deque) / self.time_window return len(self.deque) / self.time_window
else: else:
# if going faster than buffer size per time window, look at timestamps # if going faster than buffer size per time window, look at timestamps
return len(self.deque) / (self.deque[-1] - self.deque[0]) oldest, newest = self.deque[0], self.deque[-1]
buffer_span = newest - oldest
period = buffer_span / (self.buffer_size - 1)
if (now - newest) < period:
# no new estimate yet, expecting new event after period
return 1 / period
else:
return self.buffer_size / (now - oldest)
class Stopwatch:
"""Context manager measuring time spent in context.
Keyword arguments:
name: if not None, will appear in string representation
also, if not None, will automatically print self when done
"""
def __init__(self, name=None):
self.stop_time = None
self.name = name
def __enter__(self):
self.start_time = default_timer()
return self
def __exit__(self, t, v, tb): # type, value and traceback irrelevant
self.stop_time = default_timer()
if self.name is not None:
print(repr(self))
@property
def elapsed(self):
if self.stop_time is not None:
return self.stop_time - self.start_time
else:
return default_timer() - self.start_time
def __str__(self):
return self.__repr__()
def __repr__(self):
if self.name is None:
return f"{self.elapsed():.3f} s"
else:
return f"{self.name}: {self.elapsed():.3f} s"
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment