Commit Graph
25058 Commits
Author SHA1 Message Date
J. Nick Koston f8da603339 Merge remote-tracking branch 'origin/dev' into integration 2026-03-17 12:07:30 -10:00
J. Nick Koston afb3acedeb Merge remote-tracking branch 'origin/scheduler-process-to-add-fast-path' into integration 2026-03-17 12:07:25 -10:00
J. Nick Koston 373168ccf0 Merge remote-tracking branches 'origin/ble-fix-event-pool-queue-sizing', 'origin/espnow-fix-event-pool-queue-sizing', 'origin/event-pool-document-sizing-requirement' and 'origin/mqtt-fix-event-queue-data-race' into integration 2026-03-17 12:07:12 -10:00
J. Nick Koston 8acc033873 [core] Document EventPool sizing requirement with LockFreeQueue
Add a comment to EventPool documenting that when paired with a
LockFreeQueue<T, N>, the pool should be sized to N-1 (the queue's
actual capacity) to prevent slot leaks and SPSC violations.
2026-03-17 11:58:47 -10:00
J. Nick Koston da1ee1bf66 [mqtt] Fix outbound EventPool/LockFreeQueue sizing off-by-one
Size the outbound pool to N-1 to match queue capacity, same as the
inbound pool fix in the previous commit.
2026-03-17 11:52:31 -10:00
J. Nick Koston 61513d3deb [espnow] Fix EventPool/LockFreeQueue sizing off-by-one
LockFreeQueue<T,N> is a ring buffer that holds N-1 elements (one slot
is reserved to distinguish full from empty). With the pool also sized
to N, the Nth allocate() succeeds but push() fails — permanently
leaking one pool slot since the element is never returned.

Size both receive and send pools to N-1 to match queue capacity.
2026-03-17 11:46:52 -10:00
J. Nick Koston a078d1b14d [esp32_ble] Fix EventPool/LockFreeQueue sizing off-by-one
LockFreeQueue<T,N> is a ring buffer that holds N-1 elements (one slot
is reserved to distinguish full from empty). With the pool also sized
to N, the Nth allocate() succeeds but push() fails — permanently
leaking one pool slot since the element is never returned.

Size the pool to N-1 to match queue capacity. This guarantees
allocate() returns nullptr before push() can fail.
2026-03-17 11:46:18 -10:00
J. Nick Koston 95ff70eb48 [mqtt] Fix data race on inbound event queue
The ESP-IDF MQTT client dispatches events from its own task, which
pushed to a std::queue while the main loop popped from it. std::queue
is not thread-safe; concurrent access can corrupt its internal state.

Replace with EventPool + LockFreeQueue (SPSC ring buffer) already
used elsewhere in the codebase. The pool is sized to queue capacity
(SIZE-1) so allocate() fails before push() can, which prevents both
a slot leak and an SPSC violation on the pool's free list.

Also rename the outbound pool from mqtt_event_pool_ to
mqtt_outbound_pool_ to avoid confusion with the new inbound pool.
2026-03-17 11:25:14 -10:00
Jonathan Swoboda 851e8b6c0d [gree] Fix IR checksum for YAA/YAC/YAC1FB9/GENERIC models (#14888) 2026-03-17 16:28:13 -04:00
J. Nick Koston c88a01227c Merge remote-tracking branch 'upstream/dev' into integration 2026-03-17 10:21:29 -10:00
J. Nick Koston 9a729608d5 [core] Add back deprecated set_internal() for external projects (#14887) 2026-03-17 19:58:05 +00:00
Jonathan Swoboda 53fa346ddc [speaker] Fix media playlist using announcement delay (#14889) 2026-03-17 19:18:49 +00:00
J. Nick Koston 580eb64bcf Merge branch 'codspeed-benchmarks' into scheduler-process-to-add-fast-path 2026-03-17 08:59:06 -10:00
J. Nick Koston c57c8c1784 Merge branch 'dev' into codspeed-benchmarks 2026-03-17 08:58:48 -10:00
J. Nick Koston b3210de374 [core] Extract shared C++ build helpers from cpp_unit_test.py (#14883) 2026-03-17 08:53:36 -10:00
J. Nick Koston 91dbc0f341 Merge branch 'codspeed-benchmarks' into scheduler-process-to-add-fast-path 2026-03-17 08:45:47 -10:00
J. Nick Koston f57c9d0501 Merge branch 'dev' into codspeed-benchmarks 2026-03-17 08:45:33 -10:00
J. Nick Koston 81788951da Exclude tests/benchmarks/ from clang-tidy file discovery 2026-03-17 08:44:56 -10:00
J. Nick Koston 82ccc37ba1 [ethernet] Mark EthernetComponent as final (#14842) 2026-03-17 08:14:52 -10:00
J. Nick Koston 3826e95506 [api] Fix ProtoMessage protected destructor compile error on host platform (#14882) 2026-03-17 08:14:36 -10:00
Jonathan Swoboda b083491e74 [microphone] Switch IDF test to new I2S driver (#14886) 2026-03-17 13:46:32 -04:00
Diorcet Yann 73ca0ff106 [core] Small improvements (#14884) 2026-03-17 09:22:31 -04:00
J. Nick Koston be9d8b463e Merge branch 'codspeed-benchmarks' into scheduler-process-to-add-fast-path 2026-03-17 02:11:40 -10:00
J. Nick Koston 9c9464f29f Skip to_add_count_ field on single-threaded platforms
On ESPHOME_THREAD_SINGLE there are no concurrent writers, so
to_add_empty_() checks to_add_.empty() directly. The counter
field and its increment/clear operations are compiled out.
2026-03-17 02:09:39 -10:00
J. Nick Koston 4003406f8b Remove Scheduler_NextScheduleIn benchmark — too cheap, flaps 2026-03-17 02:06:16 -10:00
J. Nick Koston 1ed30414c9 Fix duplicate comment line in to_remove_ documentation 2026-03-17 02:05:07 -10:00
J. Nick KostonandCopilot Autofix powered by AI a8bb3d8c6f Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-17 02:02:23 -10:00
pre-commit-ci-lite[bot] d0c39d95ad [pre-commit.ci lite] apply automatic fixes 2026-03-17 12:02:06 +00:00
J. Nick KostonandCopilot Autofix powered by AI 1c685a8a77 Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-17 02:00:37 -10:00
J. Nick KostonandCopilot Autofix powered by AI f2ab81a0ef Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-17 02:00:17 -10:00
J. Nick Koston 55a76fcbca Change cleanup_() to return bool instead of size_t
cleanup_() was computing items_.size() on every call even on the
fast path where nothing was removed. All callers only check if
items remain (== 0), so return bool and use items_.empty() instead.
2026-03-17 01:58:25 -10:00
J. Nick Koston f654f70c39 Merge branch 'codspeed-benchmarks' into scheduler-process-to-add-fast-path 2026-03-17 01:53:03 -10:00
J. Nick Koston a1009f7a5c Use relaxed memory ordering for all counter atomics
The mutex already provides all necessary memory ordering for the
counter operations. acquire/release fences on the fast-path reads
were causing unnecessary cache flushes, regressing
Scheduler_NextScheduleIn by ~10%.
2026-03-17 01:51:46 -10:00
J. Nick Koston e14443b9c3 Fix ProtoSize_Varint benchmarks: prevent constant folding
The compiler constant-folds ProtoSize::varint(42) to 1 and optimizes
the entire inner loop to a single addition, causing ~62ns jitter-dominated
measurements. Use varying inputs (i & 0x7F for small, 0xFFFF0000 | i for
large) so each call computes a real result.
2026-03-17 01:50:36 -10:00
J. Nick Koston 9d9ac41028 Merge branch 'codspeed-benchmarks' into scheduler-process-to-add-fast-path 2026-03-17 01:45:03 -10:00
J. Nick Koston 587179143f Rename BENCHMARK_BINARY to BUILD_BINARY for generic use 2026-03-17 01:43:58 -10:00
J. Nick Koston b87b4102e0 Fix binary path extraction and defer benchmark compile error
- Use BENCHMARK_BINARY= marker for reliable binary path extraction
  instead of fragile tail -1 (PlatformIO can print warnings after path)
- Fix Scheduler_Defer: defer() is protected on Component, use
  set_timeout(delay=0) directly on Scheduler instead
2026-03-17 01:42:37 -10:00
J. Nick Koston 602d6af350 Merge branch 'codspeed-benchmarks' into scheduler-process-to-add-fast-path 2026-03-17 01:38:58 -10:00
J. Nick Koston d5f2c93e68 Add benchmarks for set_timeout, set_interval, and defer registration
Measures the cost of registering scheduler items:
- Scheduler_SetTimeout: set_timeout with 1s delay (heap path)
- Scheduler_SetInterval: set_interval with 1s period (heap path + offset calc)
- Scheduler_Defer: Component::defer (set_timeout with delay=0)

Uses i%5 for IDs to exercise the cancel-existing-timer path that
happens when re-registering with the same ID.
2026-03-17 01:38:19 -10:00
J. Nick Koston ca73a0c2c9 Merge branch 'codspeed-benchmarks' into scheduler-process-to-add-fast-path 2026-03-17 01:38:00 -10:00
J. Nick Koston a577715d5a [scheduler] Skip lock in process_to_add/cleanup/defer when nothing to do
Add fast-path checks in process_to_add(), cleanup_(), and
process_defer_queue_() to skip mutex acquisition when there is
nothing to process.

Uses std::atomic<uint32_t> counters on platforms with atomics support
(ESP32, host), falls back to always taking the lock on platforms
without atomics (LibreTiny). Single-threaded platforms (ESP8266,
RP2040, nRF52) check directly since there are no concurrent writers.

Also migrates existing to_remove_ to the same atomic pattern and
moves the defer_queue_.size() snapshot under the lock — both were
previously plain reads without the lock while being modified
cross-thread.
2026-03-17 01:36:35 -10:00
J. Nick Koston 804e2330ec Ifdef out WarnIfComponentBlockingGuard for benchmark builds
Add USE_BENCHMARK define to benchmark build flags. Guard the
warn_blocking call in finish() with #ifndef USE_BENCHMARK so
scheduler benchmarks using fake monotonic time don't trigger
the underflow (fake now > real millis()).

Remove BenchComponent — no longer needed with the ifdef.
2026-03-17 01:16:34 -10:00
J. Nick Koston e01670eed8 Revert core changes, use intervals with fake time for scheduler benchmark
The warn_blocking underflow only happens with fake time in benchmarks,
not in production (millis() is monotonic). Accept the consistent
overhead from one warning per call — CodSpeed regression detection
works on relative changes, not absolute values.
2026-03-17 01:14:39 -10:00
J. Nick Koston 2785edaac8 [core] Clamp underflowed blocking_time in warn_blocking cold path
When millis() < started_ (e.g. scheduler passes a now value slightly
ahead of real millis()), the uint32_t subtraction in finish() wraps to
~4 billion. This caused warn_blocking to fire on every call since the
underflowed value always exceeds the uint16_t threshold max (65535).

Fix by clamping blocking_time to uint16_t max in the cold warn_blocking
path. After one warning, should_warn_of_blocking() saturates the
threshold to 65535 and subsequent clamped values (65535) don't exceed it.
Zero cost on the hot path — the clamp is in the noinline cold function.
2026-03-17 01:11:48 -10:00
J. Nick Koston 885d7c3938 [core] Fix uint32_t underflow in WarnIfComponentBlockingGuard::finish()
When curr_time (from millis()) is less than started_ (the `now` passed
to scheduler.call()), the subtraction wraps to a huge value (~4 billion).
This triggers spurious blocking warnings with nonsensical times.

This can happen when the scheduler's execute_item_() returns a millis()
value that subsequent items use as their guard start, but the next
scheduler.call() passes a `now` value from a slightly different source.

Fix by skipping the blocking check when curr_time < started_ (underflow).

Also restore the scheduler firing benchmark to use intervals with
monotonically increasing fake time, now that the guard handles underflow.
2026-03-17 01:10:57 -10:00
J. Nick Koston 1f9380ddc0 Fix scheduler firing benchmark: no inner loop, warm-up call
- Revert component.h change (no core changes for benchmarks)
- Remove -DWARN_IF_BLOCKING_OVER_MS from build flags (can't shadow constexpr)
- Drop inner loop — 5 heap pops + callbacks + pushes per call is well
  above CodSpeed's 60ns instrumentation overhead
- Add warm-up call before benchmark loop to trigger the blocking guard
  once and ramp the threshold
- interval=0 causes infinite loop, must use interval=1 with fake time
2026-03-17 01:05:04 -10:00
J. Nick Koston ec60e2c228 Fix scheduler benchmark: use fake time with guard disabled at compile time
interval=0 causes infinite loop (reschedules at same time, never breaks).
interval=1 with millis() doesn't work (real time doesn't advance fast
enough between inner iterations for intervals to re-fire).

Solution: use interval=1 with monotonically increasing fake time (now++)
and disable WarnIfComponentBlockingGuard at compile time via
-DWARN_IF_BLOCKING_OVER_MS=UINT32_MAX in benchmark build flags. This
prevents the guard's (millis() - started_) underflow when fake time
exceeds real millis().
2026-03-17 01:00:06 -10:00
J. Nick Koston d7be19703b Fix scheduler intervals not firing and warn_blocking
Use interval=0 so all 5 intervals fire unconditionally every call().
Pass real millis() to scheduler.call() so WarnIfComponentBlockingGuard
doesn't see fake time ahead of wall clock (which causes uint32_t
underflow in the blocking time calculation).
2026-03-17 00:54:29 -10:00
J. Nick Koston 4565167bec Fix scheduler benchmark triggering warn_blocking
WarnIfComponentBlockingGuard compares the `now` passed to
scheduler.call() against real millis() in finish(). Using fake time
ahead of real millis() caused uint32_t underflow in the guard, triggering
blocking warnings. Fix by reading real millis() at the start of each
outer iteration so fake time stays close to wall clock.
2026-03-17 00:53:10 -10:00
J. Nick Koston 662780bcc6 Simplify scheduler now comment 2026-03-17 00:38:48 -10:00