From 1020f68188c8219f744e945bc663e3901edaaa46 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 1 Apr 2026 00:29:18 -1000 Subject: [PATCH 1/3] Add nullptr guard in record_runtime_stats_ for scheduler items --- esphome/core/component.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index 955596ce95..c7d0e15a3a 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -521,6 +521,8 @@ WarnIfComponentBlockingGuard::warn_blocking(Component *component, uint32_t block #ifdef USE_RUNTIME_STATS void WarnIfComponentBlockingGuard::record_runtime_stats_() { + if (this->component_ == nullptr) + return; uint32_t duration_us = micros() - this->started_us_; this->component_->runtime_stats_.record_time(duration_us); } From 9f92df69f84c414f5ba755b63e4f0e0f7b23fd5a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 1 Apr 2026 00:29:54 -1000 Subject: [PATCH 2/3] Fix clang-tidy: single-pass collection, add NOLINT for global --- .../runtime_stats/runtime_stats.cpp | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/esphome/components/runtime_stats/runtime_stats.cpp b/esphome/components/runtime_stats/runtime_stats.cpp index 34aa31ec65..06714b5a44 100644 --- a/esphome/components/runtime_stats/runtime_stats.cpp +++ b/esphome/components/runtime_stats/runtime_stats.cpp @@ -17,11 +17,13 @@ RuntimeStatsCollector::RuntimeStatsCollector() : log_interval_(60000), next_log_ void RuntimeStatsCollector::log_stats_() { auto &components = App.components_; - // First pass: count active components + // Single pass: collect active components into stack buffer + SmallBufferWithHeapFallback<256, Component *> buffer(components.size()); + Component **sorted = buffer.get(); size_t count = 0; for (auto *component : components) { if (component->runtime_stats_.period_count > 0) { - count++; + sorted[count++] = component; } } @@ -34,18 +36,6 @@ void RuntimeStatsCollector::log_stats_() { return; } - // Stack buffer sized to actual active count (up to 256 components), heap fallback for larger - SmallBufferWithHeapFallback<256, Component *> buffer(count); - Component **sorted = buffer.get(); - - // Second pass: fill buffer with active components - size_t idx = 0; - for (auto *component : components) { - if (component->runtime_stats_.period_count > 0) { - sorted[idx++] = component; - } - } - // Sort by period runtime (descending) std::sort(sorted, sorted + count, compare_period_time); @@ -95,8 +85,9 @@ void RuntimeStatsCollector::process_pending_stats(uint32_t current_time) { } // namespace runtime_stats -runtime_stats::RuntimeStatsCollector *global_runtime_stats = - nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +runtime_stats::RuntimeStatsCollector + *global_runtime_stats = // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + nullptr; } // namespace esphome From a9e81e6c42d75602a77b2dee7b3fb0a0c26c3221 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 1 Apr 2026 00:31:31 -1000 Subject: [PATCH 3/3] =?UTF-8?q?Remove=20unnecessary=20nullptr=20guard=20?= =?UTF-8?q?=E2=80=94=20component=20is=20never=20null?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- esphome/core/component.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index c7d0e15a3a..955596ce95 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -521,8 +521,6 @@ WarnIfComponentBlockingGuard::warn_blocking(Component *component, uint32_t block #ifdef USE_RUNTIME_STATS void WarnIfComponentBlockingGuard::record_runtime_stats_() { - if (this->component_ == nullptr) - return; uint32_t duration_us = micros() - this->started_us_; this->component_->runtime_stats_.record_time(duration_us); }