mirror of
https://github.com/esphome/esphome.git
synced 2026-07-10 08:55:36 +00:00
[core] Raise ESP32 WDT feed interval to 1/5 of configured timeout
Mirrors the existing bk72xx platform override, but auto-scales to the user-configurable esp32.watchdog_timeout (CONFIG_ESP_TASK_WDT_TIMEOUT_S) instead of hard-coding a constant: the feed interval is always 1/5 of the configured task WDT timeout so the safety margin stays constant across user configurations. - default 5 s WDT -> 1000 ms feed interval (was 300 ms, -70% hits) - 10 s WDT -> 2000 ms feed interval - 60 s WDT (max) -> 12000 ms feed interval esp_task_wdt_reset() takes a spinlock and walks the WDT task list, so every call costs tens of microseconds. At the normal ~62 Hz main loop the old 300 ms cadence produced ~200 feed_wdt_slow_ hits per 60 s period; the default 5s -> 1000 ms cuts that to ~60 hits (-70%). Component-level feeds inside Component::loop() and scheduler items are unaffected; they continue to call arch_feed_wdt after every operation, so any op exceeding this rate-limit triggers a real feed naturally. The rate-limit only applies to the outer guard in Application::loop() that fires when nothing else fed recently. esp32/__init__.py already constrains watchdog_timeout to >= 5 s (range 5-60 s), and a static_assert guards against anyone who tweaks sdkconfig below that floor, ensuring the feed interval never drops below the prior hardcoded 1000 ms value. Measured on a live ESP32 IDF build (gatetrigger.yaml, default 5 s WDT) via runtime_stats: wdt bucket dropped from 2.24 us/iter to 1.56 us/iter - about 2.5 ms saved per 60 s window.
This commit is contained in:
+21
-11
@@ -17,6 +17,10 @@
|
||||
#include "esphome/core/string_ref.h"
|
||||
#include "esphome/core/version.h"
|
||||
|
||||
#ifdef USE_ESP32
|
||||
#include <sdkconfig.h> // for CONFIG_ESP_TASK_WDT_TIMEOUT_S (drives WDT_FEED_INTERVAL_MS)
|
||||
#endif
|
||||
|
||||
#ifdef USE_DEVICES
|
||||
#include "esphome/core/device.h"
|
||||
#endif
|
||||
@@ -216,24 +220,30 @@ class Application {
|
||||
/// loops and scheduler items still feed after every op, so any op exceeding
|
||||
/// this threshold triggers a real feed naturally.
|
||||
/// Safety margins vs. platform watchdog timeouts:
|
||||
/// - ESP32 task WDT default (5 s): ~5x <-- platform override below
|
||||
/// - ESP8266 soft WDT (~1.6 s): ~5x <-- floor case; any future change
|
||||
/// must keep comfortable margin here
|
||||
/// - ESP8266 HW WDT (~6 s): ~20x
|
||||
/// - BK72xx HW WDT (10 s): ~5x <-- platform override below
|
||||
/// - ESP32 task WDT (user-configurable): ~5x <-- auto-scaled below
|
||||
/// - ESP8266 soft WDT (~1.6 s): ~5x <-- floor case; any future change
|
||||
/// must keep comfortable margin here
|
||||
/// - ESP8266 HW WDT (~6 s): ~20x
|
||||
/// - BK72xx HW WDT (10 s): ~5x <-- platform override below
|
||||
#ifdef USE_BK72XX
|
||||
// BDK busy-waits 200us per WDT reload (sctrl_dpll_delay200us). LibreTiny
|
||||
// sets HW WDT to 10s; 2000ms keeps ~5x margin. See wdt_ctrl WCMD_RELOAD_PERIOD:
|
||||
// https://github.com/libretiny-eu/framework-beken-bdk/blob/44800e7451ea30fbcbd3bb6e905315de59349fee/beken378/driver/wdt/wdt.c#L75-L87
|
||||
static constexpr uint32_t WDT_FEED_INTERVAL_MS = 2000;
|
||||
#elif defined(USE_ESP32)
|
||||
// ESP32 task WDT default timeout is 5 s (CONFIG_ESP_TASK_WDT_TIMEOUT_S).
|
||||
// 1000ms keeps a comfortable ~5x margin — matching the bk72xx safety factor —
|
||||
// while cutting the per-hit feed overhead to ~1/3 of the old 300ms cadence.
|
||||
// Auto-scale to 1/5 of the configured ESP32 task WDT timeout so the safety
|
||||
// margin stays constant when the user raises esp32.watchdog_timeout (default
|
||||
// 5 s → 1000 ms feed; 10 s → 2000 ms; 60 s → 12000 ms). The esp32 component
|
||||
// writes CONFIG_ESP_TASK_WDT_TIMEOUT_S into sdkconfig (range is validated
|
||||
// to ≥ 5 s in esp32/__init__.py), giving us the value at compile time.
|
||||
// esp_task_wdt_reset() takes a spinlock and walks the WDT task list, so
|
||||
// each call costs tens of microseconds; feeding less often materially
|
||||
// reduces the main-loop's wdt bucket.
|
||||
static constexpr uint32_t WDT_FEED_INTERVAL_MS = 1000;
|
||||
// each call costs tens of microseconds; longer intervals materially reduce
|
||||
// the main-loop's wdt bucket. Component loops and scheduler items still
|
||||
// feed after every op, so any op exceeding this threshold triggers a real
|
||||
// feed naturally regardless of the rate-limit.
|
||||
static_assert(CONFIG_ESP_TASK_WDT_TIMEOUT_S >= 5,
|
||||
"CONFIG_ESP_TASK_WDT_TIMEOUT_S must be at least 5s for a safe WDT feed interval");
|
||||
static constexpr uint32_t WDT_FEED_INTERVAL_MS = (CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000U) / 5U;
|
||||
#else
|
||||
static constexpr uint32_t WDT_FEED_INTERVAL_MS = 300;
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user