From 29ffeeeb193a21863aa4b80d69597039352d8dd5 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 23 Feb 2026 22:20:58 -0600 Subject: [PATCH] Add fast_select diagnostic counters logged every 10000 loops --- esphome/core/application.cpp | 16 +++++++++++++++- esphome/core/application.h | 7 +++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index 1a1dfc3233..8d0bb88c6a 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -647,6 +647,7 @@ void Application::yield_with_select_(uint32_t delay_ms) { // This scan preserves select() semantics: return immediately when any fd is ready. for (int fd : this->socket_fds_) { if (esphome_lwip_socket_has_data(fd)) { + this->fast_select_skip_count_++; yield(); return; } @@ -656,7 +657,20 @@ void Application::yield_with_select_(uint32_t delay_ms) { // Woken by: callback wrapper (socket data arrives), wake_loop_threadsafe() (other tasks), or timeout. // Without USE_WAKE_LOOP_THREADSAFE, only hooked socket callbacks wake the task — // background tasks won't call wake, so this degrades to a pure timeout (same as old select path). - ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(delay_ms)); + uint32_t notified = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(delay_ms)); + if (notified > 0) { + this->fast_select_woken_count_++; + } else { + this->fast_select_timeout_count_++; + } + if (++this->fast_select_total_count_ >= 10000) { + ESP_LOGD(TAG, "fast_select: woken=%" PRIu32 " timeout=%" PRIu32 " skip=%" PRIu32 " (of 10000 loops)", + this->fast_select_woken_count_, this->fast_select_timeout_count_, this->fast_select_skip_count_); + this->fast_select_total_count_ = 0; + this->fast_select_woken_count_ = 0; + this->fast_select_timeout_count_ = 0; + this->fast_select_skip_count_ = 0; + } #elif defined(USE_SOCKET_SELECT_SUPPORT) // Non-ESP32 select() path (LibreTiny bk72xx/rtl87xx, host platform). diff --git a/esphome/core/application.h b/esphome/core/application.h index f5df5e7bdf..98292b759d 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -592,6 +592,13 @@ class Application { #if defined(USE_SOCKET_SELECT_SUPPORT) && !defined(USE_ESP32) int max_fd_{-1}; // Highest file descriptor number for select() #endif +#if defined(USE_SOCKET_SELECT_SUPPORT) && defined(USE_ESP32) + // Diagnostic counters for fast select sleep behavior (logged every 1000 loops) + uint32_t fast_select_total_count_{0}; + uint32_t fast_select_woken_count_{0}; // Woken by notification (socket data or wake_loop_threadsafe) + uint32_t fast_select_timeout_count_{0}; // Slept full duration (no notification) + uint32_t fast_select_skip_count_{0}; // Skipped sleep (socket already had data) +#endif // 2-byte members (grouped together for alignment) uint16_t dump_config_at_{std::numeric_limits::max()}; // Index into components_ for dump_config progress