From 12137741682c80964ab8423192bba56469db1741 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 9 Feb 2026 19:43:25 -0600 Subject: [PATCH] [core] Extract dump_config from Application::loop() hot path Extract the dump_config block (version/chip info logging + per-component dump_config iteration) into a separate noinline process_dump_config_() method. This code runs once at startup and once on API reconnect, but was inlined into loop() which runs ~7000 times/minute. On ESP32 the dump_config block compiled to ~140 bytes (38% of loop's 368 bytes), including esp_chip_info(), integer division for revision formatting, and multiple ESP_LOG calls. Extracting it frees ~2 icache lines for the hot path. --- esphome/core/application.cpp | 46 ++++++++++++++++++++---------------- esphome/core/application.h | 4 ++++ 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index 0daabc0282..7b5435185d 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -204,36 +204,40 @@ void Application::loop() { this->last_loop_ = last_op_end_time; if (this->dump_config_at_ < this->components_.size()) { - if (this->dump_config_at_ == 0) { - char build_time_str[Application::BUILD_TIME_STR_SIZE]; - this->get_build_time_string(build_time_str); - ESP_LOGI(TAG, "ESPHome version " ESPHOME_VERSION " compiled on %s", build_time_str); + this->process_dump_config_(); + } +} + +void Application::process_dump_config_() { + if (this->dump_config_at_ == 0) { + char build_time_str[Application::BUILD_TIME_STR_SIZE]; + this->get_build_time_string(build_time_str); + ESP_LOGI(TAG, "ESPHome version " ESPHOME_VERSION " compiled on %s", build_time_str); #ifdef ESPHOME_PROJECT_NAME - ESP_LOGI(TAG, "Project " ESPHOME_PROJECT_NAME " version " ESPHOME_PROJECT_VERSION); + ESP_LOGI(TAG, "Project " ESPHOME_PROJECT_NAME " version " ESPHOME_PROJECT_VERSION); #endif #ifdef USE_ESP32 - esp_chip_info_t chip_info; - esp_chip_info(&chip_info); - ESP_LOGI(TAG, "ESP32 Chip: %s rev%d.%d, %d core(s)", ESPHOME_VARIANT, chip_info.revision / 100, - chip_info.revision % 100, chip_info.cores); + esp_chip_info_t chip_info; + esp_chip_info(&chip_info); + ESP_LOGI(TAG, "ESP32 Chip: %s rev%d.%d, %d core(s)", ESPHOME_VARIANT, chip_info.revision / 100, + chip_info.revision % 100, chip_info.cores); #if defined(USE_ESP32_VARIANT_ESP32) && !defined(USE_ESP32_MIN_CHIP_REVISION_SET) - // Suggest optimization for chips that don't need the PSRAM cache workaround - if (chip_info.revision >= 300) { + // Suggest optimization for chips that don't need the PSRAM cache workaround + if (chip_info.revision >= 300) { #ifdef USE_PSRAM - ESP_LOGW(TAG, "Set minimum_chip_revision: \"%d.%d\" to save ~10KB IRAM", chip_info.revision / 100, - chip_info.revision % 100); + ESP_LOGW(TAG, "Set minimum_chip_revision: \"%d.%d\" to save ~10KB IRAM", chip_info.revision / 100, + chip_info.revision % 100); #else - ESP_LOGW(TAG, "Set minimum_chip_revision: \"%d.%d\" to reduce binary size", chip_info.revision / 100, - chip_info.revision % 100); -#endif - } -#endif + ESP_LOGW(TAG, "Set minimum_chip_revision: \"%d.%d\" to reduce binary size", chip_info.revision / 100, + chip_info.revision % 100); #endif } - - this->components_[this->dump_config_at_]->call_dump_config(); - this->dump_config_at_++; +#endif +#endif } + + this->components_[this->dump_config_at_]->call_dump_config(); + this->dump_config_at_++; } void IRAM_ATTR HOT Application::feed_wdt(uint32_t time) { diff --git a/esphome/core/application.h b/esphome/core/application.h index 592bf809f1..46cf6ebcda 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -519,6 +519,10 @@ class Application { void before_loop_tasks_(uint32_t loop_start_time); void after_loop_tasks_(); + /// Process dump_config output one component per loop iteration. + /// Extracted from loop() to keep cold startup/reconnect logging out of the hot path. + void __attribute__((noinline)) process_dump_config_(); + void feed_wdt_arch_(); /// Perform a delay while also monitoring socket file descriptors for readiness