From b63dc719e5de2eb4b953f61a9c595ca9e61ce40b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 31 Mar 2026 23:07:52 -1000 Subject: [PATCH] Fix protected access: move ComponentRuntimeStats before Component class --- esphome/core/application.h | 9 ------ esphome/core/component.h | 60 ++++++++++++++++++++------------------ 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/esphome/core/application.h b/esphome/core/application.h index 6cc61bc954..06ff30e81f 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -130,12 +130,6 @@ bool socket_ready_fd(int fd, bool loop_monitored); // NOLINT(readability-redund #endif } // namespace esphome::socket -#ifdef USE_RUNTIME_STATS -namespace esphome::runtime_stats { -class RuntimeStatsCollector; -} // namespace esphome::runtime_stats -#endif - // Forward declarations for friend access from codegen-generated setup() void setup(); // NOLINT(readability-redundant-declaration) - may be declared in Arduino.h void original_setup(); // NOLINT(readability-redundant-declaration) - used by cpp unit tests @@ -596,9 +590,6 @@ class Application { friend Component; #if defined(USE_SOCKET_SELECT_SUPPORT) && !defined(USE_LWIP_FAST_SELECT) friend bool socket::socket_ready_fd(int fd, bool loop_monitored); -#endif -#ifdef USE_RUNTIME_STATS - friend class runtime_stats::RuntimeStatsCollector; #endif friend void ::setup(); friend void ::original_setup(); diff --git a/esphome/core/component.h b/esphome/core/component.h index f62904877a..e85f45bbf5 100644 --- a/esphome/core/component.h +++ b/esphome/core/component.h @@ -92,6 +92,37 @@ inline constexpr uint8_t WARN_IF_BLOCKING_OVER_CS = 5U; // 50ms in centiseconds /// Weak default returns "" so builds without codegen still link. const LogString *component_source_lookup(uint8_t index); +#ifdef USE_RUNTIME_STATS +/// Inline runtime statistics — eliminates std::map lookup on every loop iteration. +/// Only present when USE_RUNTIME_STATS is defined (profiling builds). +struct ComponentRuntimeStats { + // Period stats (reset each logging interval) + uint32_t period_count{0}; + uint32_t period_time_us{0}; + uint32_t period_max_time_us{0}; + // Total stats (persistent until reboot, uint64_t to avoid overflow) + uint32_t total_count{0}; + uint64_t total_time_us{0}; + uint32_t total_max_time_us{0}; + + void record_time(uint32_t duration_us) { + this->period_count++; + this->period_time_us += duration_us; + if (duration_us > this->period_max_time_us) + this->period_max_time_us = duration_us; + this->total_count++; + this->total_time_us += duration_us; + if (duration_us > this->total_max_time_us) + this->total_max_time_us = duration_us; + } + void reset_period() { + this->period_count = 0; + this->period_time_us = 0; + this->period_max_time_us = 0; + } +}; +#endif + class Component { public: /** Where the component's initialization should happen. @@ -529,35 +560,8 @@ class Component { /// Bits 6-7: Unused - reserved for future expansion uint8_t component_state_{0x00}; volatile bool pending_enable_loop_{false}; ///< ISR-safe flag for enable_loop_soon_any_context - #ifdef USE_RUNTIME_STATS - /// Inline runtime statistics — eliminates std::map lookup on every loop iteration. - struct RuntimeStats { - // Period stats (reset each logging interval) - uint32_t period_count{0}; - uint32_t period_time_us{0}; - uint32_t period_max_time_us{0}; - // Total stats (persistent until reboot, uint64_t to avoid overflow) - uint32_t total_count{0}; - uint64_t total_time_us{0}; - uint32_t total_max_time_us{0}; - - void record_time(uint32_t duration_us) { - this->period_count++; - this->period_time_us += duration_us; - if (duration_us > this->period_max_time_us) - this->period_max_time_us = duration_us; - this->total_count++; - this->total_time_us += duration_us; - if (duration_us > this->total_max_time_us) - this->total_max_time_us = duration_us; - } - void reset_period() { - this->period_count = 0; - this->period_time_us = 0; - this->period_max_time_us = 0; - } - } runtime_stats_; + ComponentRuntimeStats runtime_stats_; #endif };