diff --git a/frigate/test/test_builtin.py b/frigate/test/test_builtin.py index 7cf47de5c6..1391c0eec7 100644 --- a/frigate/test/test_builtin.py +++ b/frigate/test/test_builtin.py @@ -36,6 +36,31 @@ class TestEventsPerSecond(unittest.TestCase): clock[0] += 100.0 self.assertEqual(eps.eps(), 0.0) + def test_burst_after_start_is_not_divided_by_a_tiny_window(self) -> None: + eps = EventsPerSecond(last_n_seconds=10) + clock = [1000.0] + with patch("frigate.util.builtin.time.monotonic", side_effect=lambda: clock[0]): + eps.start() + # eleven buffered frames arrive within 100 ms of starting + for _ in range(11): + clock[0] += 0.01 + eps.update() + # 11 events over less than a second is at most 11 per second + self.assertLessEqual(eps.eps(), 11.0) + + def test_subsecond_window_keeps_its_rate(self) -> None: + eps = EventsPerSecond(last_n_seconds=0.5) + clock = [1000.0] + with patch("frigate.util.builtin.time.monotonic", side_effect=lambda: clock[0]): + eps.start() + # twenty events per second for two seconds + for _ in range(40): + clock[0] += 0.05 + eps.update() + # read between events, so none sits exactly on the window edge + clock[0] += 0.01 + self.assertAlmostEqual(eps.eps(), 20.0) + if __name__ == "__main__": unittest.main() diff --git a/frigate/util/builtin.py b/frigate/util/builtin.py index fbc53e2cd9..7b93ca8183 100644 --- a/frigate/util/builtin.py +++ b/frigate/util/builtin.py @@ -56,10 +56,13 @@ class EventsPerSecond: 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 + # rate over at least one second (or the whole window, if shorter), + # so a burst of events right after start() is not divided by a + # tiny window + seconds = max( + min(now - self._start, self._last_n_seconds), + min(1.0, self._last_n_seconds), + ) return len(self._timestamps) / seconds # remove aged out timestamps