[sensor] Document why TimeoutFilterBase intentionally keeps Component (#16194)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
J. Nick Koston
2026-05-03 20:18:28 -05:00
committed by GitHub
parent 53c4e6f386
commit 24d4da1021

View File

@@ -413,7 +413,31 @@ class ThrottleWithPriorityNanFilter : public Filter {
uint32_t min_time_between_inputs_;
};
// Base class for timeout filters - contains common loop logic
// Base class for timeout filters - contains common loop logic.
//
// Why this intentionally inherits Component (and does NOT use the self-keyed
// `App.scheduler.set_timeout(this, ...)` pattern that the other Filter classes
// migrated to):
//
// Timeout filters re-arm on every input, so on devices with many sensors
// using timeout filters (e.g. multi-LD2450 boards) every armed filter would
// require a live SchedulerItem in RAM at the same time. A SchedulerItem is
// substantially larger than the Component bookkeeping bytes carried by this
// class, so paying the Component cost per filter (one-time, BSS) is cheaper
// than paying for a SchedulerItem per filter (live, while armed). #11922
// is the original symptom and switchover to the loop-based design; #16173
// attempted to migrate this onto the scheduler and was closed for exactly
// this reason — even if the scheduler pool were unbounded, RAM per armed
// filter would still be dominated by the SchedulerItem itself, not by
// anything we can shrink in the scheduler.
//
// The loop-based design has additional advantages on top of the RAM win:
// `enable_loop()` / `disable_loop()` partitions the cost away when no
// timeout is armed; while armed, work is a single timestamp compare per
// active filter, with no per-input scheduler cancel/insert path.
//
// Don't try to migrate this class onto the self-keyed scheduler. The math
// doesn't work — at scale, this design is the smaller one.
class TimeoutFilterBase : public Filter, public Component {
public:
void loop() override;