From f08ea48cc3a38493eab104d25b335feb5c328c64 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 24 Apr 2026 17:24:30 -0500 Subject: [PATCH] Revert "[core] Outline Scheduler::call cleanup slow path into cold combined helper" This reverts commit b110f453f88002757b7ab0b6635adfc90a526572. --- esphome/core/scheduler.cpp | 33 ++++++++------------------------- esphome/core/scheduler.h | 5 ----- 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/esphome/core/scheduler.cpp b/esphome/core/scheduler.cpp index b1c46a14bd..17f1331d18 100644 --- a/esphome/core/scheduler.cpp +++ b/esphome/core/scheduler.cpp @@ -615,16 +615,14 @@ uint32_t HOT Scheduler::call(uint32_t now) { } #endif /* ESPHOME_DEBUG_SCHEDULER */ - // Cleanup removed items before processing. Fast path: one atomic load + - // branch; when nothing is pending, skip both slow-path calls entirely. - // Previously the equivalent logic was split across cleanup_() (inline, - // loads to_remove_) and a separate to_remove_count_() check for the MAX - // threshold, which produced two memw+l32i pairs on Xtensa (GCC can't CSE - // across std::atomic's memw barriers). Folding the slow work into one - // outlined cold function keeps Scheduler::call's hot-path footprint small - // and the I-cache happy. - if (this->to_remove_count_() != 0) [[unlikely]] { - this->cleanup_slow_combined_(); + // Cleanup removed items before processing + // First try to clean items from the top of the heap (fast path) + this->cleanup_(); + + // If we still have too many cancelled items, do a full cleanup + // This only happens if cancelled items are stuck in the middle/bottom of the heap + if (this->to_remove_count_() >= MAX_LOGICALLY_DELETED_ITEMS) { + this->full_cleanup_removed_items_(); } // IMPORTANT: This loop uses index-based access (items_[0]), NOT iterators. // This is intentional — fired intervals are pushed back into items_ via @@ -777,21 +775,6 @@ bool HOT Scheduler::cleanup_slow_path_() { } return !this->items_.empty(); } -// Combined cold path for Scheduler::call. Only called when to_remove_ is -// non-zero. Noinline + cold keeps the two calls and the re-read of -// to_remove_ out of the main loop's hot path; the attribute also lets the -// compiler push this code out to a rarely-touched flash region so the -// scheduler's hot instructions stay in cache. -void Scheduler::cleanup_slow_combined_() { - // First sweep: drop cancelled items from the heap top. - this->cleanup_slow_path_(); - // Re-read to_remove_ because cleanup_slow_path_ may have decremented it. - // If cancelled items remain stuck below the top and the count crossed - // the threshold, do a full sweep. - if (this->to_remove_count_() >= MAX_LOGICALLY_DELETED_ITEMS) { - this->full_cleanup_removed_items_(); - } -} Scheduler::SchedulerItem *HOT Scheduler::pop_raw_locked_() { std::pop_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp); diff --git a/esphome/core/scheduler.h b/esphome/core/scheduler.h index 53ce87ccf2..46b19855c3 100644 --- a/esphome/core/scheduler.h +++ b/esphome/core/scheduler.h @@ -316,11 +316,6 @@ class Scheduler { } // Slow path for cleanup_() when there are items to remove - defined in scheduler.cpp bool cleanup_slow_path_(); - // Combined slow path for Scheduler::call: runs cleanup_slow_path_ then, if - // cancelled items are still stuck below the heap top, full_cleanup_removed_items_. - // Outlined (noinline, cold) so the Scheduler::call fast path stays one atomic - // load + branch — keeping the I-cache hot for the common zero-to-remove case. - void __attribute__((noinline, cold)) cleanup_slow_combined_(); // Slow path for process_to_add() when there are items to merge - defined in scheduler.cpp void process_to_add_slow_path_(); // Remove and return the front item from the heap as a raw pointer.