diff --git a/esphome/components/setup_heap_stats/__init__.py b/esphome/components/setup_heap_stats/__init__.py deleted file mode 100644 index 9422390a4f..0000000000 --- a/esphome/components/setup_heap_stats/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -import esphome.codegen as cg -import esphome.config_validation as cv - -CODEOWNERS = ["@bdraco"] - -CONFIG_SCHEMA = cv.All( - cv.Schema({}), - cv.only_on(["esp32", "esp8266", "rp2040", "bk72xx", "rtl87xx", "ln882x"]), -) - - -async def to_code(config): - cg.add_define("USE_SETUP_HEAP_STATS") diff --git a/esphome/components/setup_heap_stats/setup_heap_stats.cpp b/esphome/components/setup_heap_stats/setup_heap_stats.cpp deleted file mode 100644 index 9b46e9371a..0000000000 --- a/esphome/components/setup_heap_stats/setup_heap_stats.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "setup_heap_stats.h" - -#ifdef USE_SETUP_HEAP_STATS - -#include -#include "esphome/core/component.h" -#include "esphome/core/log.h" - -#ifdef USE_ESP32 -#include -#endif -#ifdef USE_ESP8266 -#include -#endif -#ifdef USE_RP2040 -#include -#endif - -namespace esphome { - -namespace setup_heap_stats { - -static const char *const TAG = "setup_heap_stats"; - -SetupHeapStatsCollector::SetupHeapStatsCollector(uint32_t initial_baseline) { - global_setup_heap_stats = this; - uint32_t before_alloc = get_free_internal_heap(); - // Allocate enough entries for both components and entity-only registrations - this->max_entries_ = ESPHOME_COMPONENT_COUNT * 2; - this->entries_ = new HeapEntry[this->max_entries_]; // NOLINT - uint32_t after_alloc = get_free_internal_heap(); - // Use the pre_setup() baseline but subtract our own entries allocation - // so the collector's overhead is not attributed to the first component - this->last_heap_snapshot_ = initial_baseline - (before_alloc - after_alloc); -} - -uint32_t SetupHeapStatsCollector::get_free_internal_heap() { -#ifdef USE_ESP32 - return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); -#elif defined(USE_ESP8266) - return ESP.getFreeHeap(); // NOLINT(readability-static-accessed-through-instance) -#elif defined(USE_RP2040) - return rp2040.getFreeHeap(); -#elif defined(USE_LIBRETINY) - return lt_heap_get_free(); -#else - return 0; -#endif -} - -void SetupHeapStatsCollector::record_entry_(Component *comp, const LogString *label) { - uint32_t current_heap = get_free_internal_heap(); - int32_t delta = static_cast(this->last_heap_snapshot_) - static_cast(current_heap); - this->last_heap_snapshot_ = current_heap; - - if (this->entry_count_ < this->max_entries_) { - this->entries_[this->entry_count_].component = comp; - this->entries_[this->entry_count_].entity_label = label; - this->entries_[this->entry_count_].construction_delta = delta; - this->entries_[this->entry_count_].setup_delta = 0; - this->entry_count_++; - } - - if (comp != nullptr) { - ESP_LOGI(TAG, "Constructed %s: %" PRId32 " bytes (free: %" PRIu32 ")", LOG_STR_ARG(comp->get_component_log_str()), - delta, current_heap); - } else if (label != nullptr) { - ESP_LOGI(TAG, "Constructed %s (entity): %" PRId32 " bytes (free: %" PRIu32 ")", LOG_STR_ARG(label), delta, - current_heap); - } -} - -void SetupHeapStatsCollector::record_component_registered(Component *comp) { this->record_entry_(comp, nullptr); } - -void SetupHeapStatsCollector::record_entity_registered(const LogString *label) { this->record_entry_(nullptr, label); } - -void SetupHeapStatsCollector::record_before_setup(Component *comp) { - this->setup_component_ = comp; - this->setup_before_heap_ = get_free_internal_heap(); -} - -void SetupHeapStatsCollector::record_after_setup(Component *comp) { - if (this->setup_component_ != comp) - return; - - uint32_t current_heap = get_free_internal_heap(); - int32_t delta = static_cast(this->setup_before_heap_) - static_cast(current_heap); - - // Find the entry for this component and update setup delta - for (uint16_t i = 0; i < this->entry_count_; i++) { - if (this->entries_[i].component == comp) { - this->entries_[i].setup_delta = delta; - break; - } - } - - ESP_LOGI(TAG, "Setup %s: %" PRId32 " bytes (free: %" PRIu32 ")", LOG_STR_ARG(comp->get_component_log_str()), delta, - current_heap); - - this->setup_component_ = nullptr; -} - -void SetupHeapStatsCollector::log_summary() { - if (this->entries_ == nullptr || this->entry_count_ == 0) - return; - - // Sort by total (construction + setup) descending - std::sort(this->entries_, this->entries_ + this->entry_count_, [](const HeapEntry &a, const HeapEntry &b) { - return (a.construction_delta + a.setup_delta) > (b.construction_delta + b.setup_delta); - }); - - ESP_LOGI(TAG, "Setup Heap Stats Summary (sorted by total, construction + setup):"); - for (uint16_t i = 0; i < this->entry_count_; i++) { - const auto &entry = this->entries_[i]; - int32_t total = entry.construction_delta + entry.setup_delta; - if (total == 0 && entry.construction_delta == 0 && entry.setup_delta == 0) - continue; - const char *name; - if (entry.component != nullptr) { - name = LOG_STR_ARG(entry.component->get_component_log_str()); - } else if (entry.entity_label != nullptr) { - name = LOG_STR_ARG(entry.entity_label); - } else { - name = "unknown"; - } - ESP_LOGI(TAG, " %s: %" PRId32 " bytes (construction: %" PRId32 ", setup: %" PRId32 ")", name, total, - entry.construction_delta, entry.setup_delta); - } - - // Free storage - delete[] this->entries_; // NOLINT - this->entries_ = nullptr; - this->entry_count_ = 0; -} - -} // namespace setup_heap_stats - -setup_heap_stats::SetupHeapStatsCollector *global_setup_heap_stats = - nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - -} // namespace esphome - -#endif // USE_SETUP_HEAP_STATS diff --git a/esphome/components/setup_heap_stats/setup_heap_stats.h b/esphome/components/setup_heap_stats/setup_heap_stats.h deleted file mode 100644 index 478adf92fc..0000000000 --- a/esphome/components/setup_heap_stats/setup_heap_stats.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include "esphome/core/defines.h" - -#ifdef USE_SETUP_HEAP_STATS - -#include -#include "esphome/core/log.h" - -namespace esphome { - -class Component; // Forward declaration - -namespace setup_heap_stats { - -struct HeapEntry { - Component *component; // Non-null for component entries - const LogString *entity_label; // Non-null for entity-only entries (no component) - int32_t construction_delta; - int32_t setup_delta; -}; - -class SetupHeapStatsCollector { - public: - explicit SetupHeapStatsCollector(uint32_t initial_baseline); - - /// Called from register_component_() to record heap delta since last registration - void record_component_registered(Component *comp); - - /// Called from register_sensor(), register_button(), etc. to record heap delta for entities - /// that are not registered as components. This prevents their cost from being attributed - /// to the next register_component() call. - void record_entity_registered(const LogString *label); - - /// Called before component->call_setup() - void record_before_setup(Component *comp); - - /// Called after component->call_setup() - void record_after_setup(Component *comp); - - /// Log sorted summary and free storage - void log_summary(); - - /// Get free internal heap size (platform-specific) - static uint32_t get_free_internal_heap(); - - protected: - void record_entry_(Component *comp, const LogString *label); - - HeapEntry *entries_{nullptr}; - uint16_t entry_count_{0}; - uint16_t max_entries_{0}; - uint32_t last_heap_snapshot_{0}; - // Temporary storage for before/after setup measurement - Component *setup_component_{nullptr}; - uint32_t setup_before_heap_{0}; -}; - -} // namespace setup_heap_stats - -extern setup_heap_stats::SetupHeapStatsCollector - *global_setup_heap_stats; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - -} // namespace esphome - -#endif // USE_SETUP_HEAP_STATS diff --git a/esphome/core/application.h b/esphome/core/application.h index aa7f21bb04..5659680fb1 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -122,9 +122,6 @@ void socket_delay(uint32_t ms); // NOLINT(readability-redundant-declaration) #ifdef USE_UPDATE #include "esphome/components/update/update_entity.h" #endif -#ifdef USE_SETUP_HEAP_STATS -#include "esphome/components/setup_heap_stats/setup_heap_stats.h" -#endif namespace esphome::socket { #ifdef USE_SOCKET_SELECT_SUPPORT @@ -176,9 +173,6 @@ class Application { } this->name_ = StringRef(name, name_len); this->friendly_name_ = StringRef(friendly_name, friendly_name_len); -#ifdef USE_SETUP_HEAP_STATS - this->init_setup_heap_stats_baseline_(); -#endif } #else // Called before Logger::pre_setup() — must not log (global_logger is not yet set). @@ -188,9 +182,6 @@ class Application { this->name_add_mac_suffix_ = false; this->name_ = StringRef(name, name_len); this->friendly_name_ = StringRef(friendly_name, friendly_name_len); -#ifdef USE_SETUP_HEAP_STATS - this->init_setup_heap_stats_baseline_(); -#endif } #endif @@ -207,190 +198,89 @@ class Application { #ifdef USE_BINARY_SENSOR void register_binary_sensor(binary_sensor::BinarySensor *binary_sensor) { this->binary_sensors_.push_back(binary_sensor); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("binary_sensor")); -#endif } #endif #ifdef USE_SENSOR - void register_sensor(sensor::Sensor *sensor) { - this->sensors_.push_back(sensor); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("sensor")); -#endif - } + void register_sensor(sensor::Sensor *sensor) { this->sensors_.push_back(sensor); } #endif #ifdef USE_SWITCH - void register_switch(switch_::Switch *a_switch) { - this->switches_.push_back(a_switch); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("switch")); -#endif - } + void register_switch(switch_::Switch *a_switch) { this->switches_.push_back(a_switch); } #endif #ifdef USE_BUTTON - void register_button(button::Button *button) { - this->buttons_.push_back(button); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("button")); -#endif - } + void register_button(button::Button *button) { this->buttons_.push_back(button); } #endif #ifdef USE_TEXT_SENSOR - void register_text_sensor(text_sensor::TextSensor *sensor) { - this->text_sensors_.push_back(sensor); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("text_sensor")); -#endif - } + void register_text_sensor(text_sensor::TextSensor *sensor) { this->text_sensors_.push_back(sensor); } #endif #ifdef USE_FAN - void register_fan(fan::Fan *state) { - this->fans_.push_back(state); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("fan")); -#endif - } + void register_fan(fan::Fan *state) { this->fans_.push_back(state); } #endif #ifdef USE_COVER - void register_cover(cover::Cover *cover) { - this->covers_.push_back(cover); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("cover")); -#endif - } + void register_cover(cover::Cover *cover) { this->covers_.push_back(cover); } #endif #ifdef USE_CLIMATE - void register_climate(climate::Climate *climate) { - this->climates_.push_back(climate); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("climate")); -#endif - } + void register_climate(climate::Climate *climate) { this->climates_.push_back(climate); } #endif #ifdef USE_LIGHT - void register_light(light::LightState *light) { - this->lights_.push_back(light); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("light")); -#endif - } + void register_light(light::LightState *light) { this->lights_.push_back(light); } #endif #ifdef USE_NUMBER - void register_number(number::Number *number) { - this->numbers_.push_back(number); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("number")); -#endif - } + void register_number(number::Number *number) { this->numbers_.push_back(number); } #endif #ifdef USE_DATETIME_DATE - void register_date(datetime::DateEntity *date) { - this->dates_.push_back(date); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("date")); -#endif - } + void register_date(datetime::DateEntity *date) { this->dates_.push_back(date); } #endif #ifdef USE_DATETIME_TIME - void register_time(datetime::TimeEntity *time) { - this->times_.push_back(time); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("time")); -#endif - } + void register_time(datetime::TimeEntity *time) { this->times_.push_back(time); } #endif #ifdef USE_DATETIME_DATETIME - void register_datetime(datetime::DateTimeEntity *datetime) { - this->datetimes_.push_back(datetime); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("datetime")); -#endif - } + void register_datetime(datetime::DateTimeEntity *datetime) { this->datetimes_.push_back(datetime); } #endif #ifdef USE_TEXT - void register_text(text::Text *text) { - this->texts_.push_back(text); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("text")); -#endif - } + void register_text(text::Text *text) { this->texts_.push_back(text); } #endif #ifdef USE_SELECT - void register_select(select::Select *select) { - this->selects_.push_back(select); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("select")); -#endif - } + void register_select(select::Select *select) { this->selects_.push_back(select); } #endif #ifdef USE_LOCK - void register_lock(lock::Lock *a_lock) { - this->locks_.push_back(a_lock); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("lock")); -#endif - } + void register_lock(lock::Lock *a_lock) { this->locks_.push_back(a_lock); } #endif #ifdef USE_VALVE - void register_valve(valve::Valve *valve) { - this->valves_.push_back(valve); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("valve")); -#endif - } + void register_valve(valve::Valve *valve) { this->valves_.push_back(valve); } #endif #ifdef USE_MEDIA_PLAYER - void register_media_player(media_player::MediaPlayer *media_player) { - this->media_players_.push_back(media_player); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("media_player")); -#endif - } + void register_media_player(media_player::MediaPlayer *media_player) { this->media_players_.push_back(media_player); } #endif #ifdef USE_ALARM_CONTROL_PANEL void register_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) { this->alarm_control_panels_.push_back(a_alarm_control_panel); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("alarm_control_panel")); -#endif } #endif #ifdef USE_WATER_HEATER - void register_water_heater(water_heater::WaterHeater *water_heater) { - this->water_heaters_.push_back(water_heater); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("water_heater")); -#endif - } + void register_water_heater(water_heater::WaterHeater *water_heater) { this->water_heaters_.push_back(water_heater); } #endif #ifdef USE_INFRARED - void register_infrared(infrared::Infrared *infrared) { - this->infrareds_.push_back(infrared); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("infrared")); -#endif - } + void register_infrared(infrared::Infrared *infrared) { this->infrareds_.push_back(infrared); } #endif #ifdef USE_SERIAL_PROXY @@ -401,21 +291,11 @@ class Application { #endif #ifdef USE_EVENT - void register_event(event::Event *event) { - this->events_.push_back(event); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("event")); -#endif - } + void register_event(event::Event *event) { this->events_.push_back(event); } #endif #ifdef USE_UPDATE - void register_update(update::UpdateEntity *update) { - this->updates_.push_back(update); -#ifdef USE_SETUP_HEAP_STATS - this->record_entity_heap_stats_(LOG_STR("update")); -#endif - } + void register_update(update::UpdateEntity *update) { this->updates_.push_back(update); } #endif /// Reserve space for components to avoid memory fragmentation @@ -771,15 +651,6 @@ class Application { inline void drain_wake_notifications_(); // Read pending wake notifications in main loop (hot path - inlined) #endif -#ifdef USE_SETUP_HEAP_STATS - void init_setup_heap_stats_baseline_(); - void record_entity_heap_stats_(const LogString *label) { - if (global_setup_heap_stats != nullptr) { - global_setup_heap_stats->record_entity_registered(label); - } - } -#endif - // === Member variables ordered by size to minimize padding === // Pointer-sized members first @@ -821,9 +692,6 @@ class Application { // 4-byte members uint32_t last_loop_{0}; uint32_t loop_component_start_time_{0}; -#ifdef USE_SETUP_HEAP_STATS - uint32_t setup_heap_stats_baseline_{0}; -#endif #if defined(USE_SOCKET_SELECT_SUPPORT) && !defined(USE_LWIP_FAST_SELECT) int max_fd_{-1}; // Highest file descriptor number for select() diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index 1c5dc7239b..c81e357808 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -12,9 +12,6 @@ #ifdef USE_RUNTIME_STATS #include "esphome/components/runtime_stats/runtime_stats.h" #endif -#ifdef USE_SETUP_HEAP_STATS -#include "esphome/components/setup_heap_stats/setup_heap_stats.h" -#endif namespace esphome { @@ -246,18 +243,8 @@ void Component::call() { ESP_LOGV(TAG, "Setup %s", LOG_STR_ARG(this->get_component_log_str())); #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG uint32_t start_time = millis(); -#endif -#ifdef USE_SETUP_HEAP_STATS - if (global_setup_heap_stats != nullptr) { - global_setup_heap_stats->record_before_setup(this); - } #endif this->call_setup(); -#ifdef USE_SETUP_HEAP_STATS - if (global_setup_heap_stats != nullptr) { - global_setup_heap_stats->record_after_setup(this); - } -#endif #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG uint32_t setup_time = millis() - start_time; // Only log at CONFIG level if setup took longer than the blocking threshold diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 50182f1da1..58fbc64624 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -131,7 +131,6 @@ #define USE_SAFE_MODE_CALLBACK #define USE_SELECT #define USE_SENSOR -#define USE_SETUP_HEAP_STATS #define USE_SENSOR_FILTER #define USE_SERIAL_PROXY #define USE_SETUP_PRIORITY_OVERRIDE diff --git a/tests/components/setup_heap_stats/common.yaml b/tests/components/setup_heap_stats/common.yaml deleted file mode 100644 index 2fb72f29d3..0000000000 --- a/tests/components/setup_heap_stats/common.yaml +++ /dev/null @@ -1 +0,0 @@ -setup_heap_stats: diff --git a/tests/components/setup_heap_stats/test.bk72xx-ard.yaml b/tests/components/setup_heap_stats/test.bk72xx-ard.yaml deleted file mode 100644 index 2fb72f29d3..0000000000 --- a/tests/components/setup_heap_stats/test.bk72xx-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -setup_heap_stats: diff --git a/tests/components/setup_heap_stats/test.esp32-idf.yaml b/tests/components/setup_heap_stats/test.esp32-idf.yaml deleted file mode 100644 index 2fb72f29d3..0000000000 --- a/tests/components/setup_heap_stats/test.esp32-idf.yaml +++ /dev/null @@ -1 +0,0 @@ -setup_heap_stats: diff --git a/tests/components/setup_heap_stats/test.esp8266-ard.yaml b/tests/components/setup_heap_stats/test.esp8266-ard.yaml deleted file mode 100644 index 2fb72f29d3..0000000000 --- a/tests/components/setup_heap_stats/test.esp8266-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -setup_heap_stats: diff --git a/tests/components/setup_heap_stats/test.rp2040-ard.yaml b/tests/components/setup_heap_stats/test.rp2040-ard.yaml deleted file mode 100644 index 2fb72f29d3..0000000000 --- a/tests/components/setup_heap_stats/test.rp2040-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -setup_heap_stats: diff --git a/tests/components/setup_heap_stats/test.rtl87xx-ard.yaml b/tests/components/setup_heap_stats/test.rtl87xx-ard.yaml deleted file mode 100644 index 2fb72f29d3..0000000000 --- a/tests/components/setup_heap_stats/test.rtl87xx-ard.yaml +++ /dev/null @@ -1 +0,0 @@ -setup_heap_stats: