optimize frame-per-second calculations (#6887)

* optimize frame-per-second calculations

FPS is never calculated over differing periods for even given
counter. By only storing timestamps within the period that is
used, we avoid having to iterate 1000 entries every time it's
re-calculated (multiple times per second). 1000 entries would
normally only be needed if something is running at 100fps. A
more common speed - anywhere from 5 to 30fps, only needs 50
to 300 entries.

This isn't a huge improvement in the grand scheme, but when motion
detection is disabled, it takes nearly as much time in a flamegraph
as actually transferring the video frame.

* fix python checks
This commit is contained in:
Cody Cutrer 2023-06-28 04:55:53 -06:00 committed by GitHub
parent ee4a133655
commit ef14a43930
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -650,34 +650,42 @@ def restart_frigate():
class EventsPerSecond:
def __init__(self, max_events=1000):
def __init__(self, max_events=1000, last_n_seconds=10):
self._start = None
self._max_events = max_events
self._last_n_seconds = last_n_seconds
self._timestamps = []
def start(self):
self._start = datetime.datetime.now().timestamp()
def update(self):
now = datetime.datetime.now().timestamp()
if self._start is None:
self.start()
self._timestamps.append(datetime.datetime.now().timestamp())
self._start = now
self._timestamps.append(now)
# truncate the list when it goes 100 over the max_size
if len(self._timestamps) > self._max_events + 100:
self._timestamps = self._timestamps[(1 - self._max_events) :]
self.expire_timestamps(now)
def eps(self, last_n_seconds=10):
if self._start is None:
self.start()
# compute the (approximate) events in the last n seconds
def eps(self):
now = datetime.datetime.now().timestamp()
seconds = min(now - self._start, last_n_seconds)
if self._start is None:
self._start = now
# compute the (approximate) events in the last n seconds
self.expire_timestamps(now)
seconds = min(now - self._start, self._last_n_seconds)
# avoid divide by zero
if seconds == 0:
seconds = 1
return (
len([t for t in self._timestamps if t > (now - last_n_seconds)]) / seconds
)
return len(self._timestamps) / seconds
# remove aged out timestamps
def expire_timestamps(self, now):
threshold = now - self._last_n_seconds
while self._timestamps and self._timestamps[0] < threshold:
del self._timestamps[0]
def print_stack(sig, frame):