mirror of
https://github.com/esphome/esphome.git
synced 2026-09-17 18:18:43 +00:00
Merge remote-tracking branch 'upstream-ssh/scheduler-pool-unbounded-freelist' into integration
This commit is contained in:
@@ -25,6 +25,10 @@ namespace esphome {
|
||||
|
||||
static const char *const TAG = "app";
|
||||
|
||||
// Delay after setup() finishes before trimming the scheduler freelist of its post-boot peak.
|
||||
// 10 s is well past the bulk of post-setup async work (Wi-Fi/MQTT connects, first-read latency).
|
||||
static constexpr uint32_t SCHEDULER_FREELIST_TRIM_DELAY_MS = 10000;
|
||||
|
||||
// Helper function for insertion sort of components by priority
|
||||
// Using insertion sort instead of std::stable_sort saves ~1.3KB of flash
|
||||
// by avoiding template instantiations (std::rotate, std::stable_sort, lambdas)
|
||||
@@ -112,6 +116,9 @@ void Application::setup() {
|
||||
|
||||
ESP_LOGI(TAG, "setup() finished successfully!");
|
||||
|
||||
// Trim the scheduler freelist of its post-boot peak once startup churn settles.
|
||||
this->scheduler.set_timeout(this, SCHEDULER_FREELIST_TRIM_DELAY_MS, [this]() { this->scheduler.trim_freelist(); });
|
||||
|
||||
#ifdef USE_SETUP_PRIORITY_OVERRIDE
|
||||
// Clear setup priority overrides to free memory
|
||||
clear_setup_priority_overrides();
|
||||
|
||||
@@ -913,6 +913,38 @@ void Scheduler::recycle_item_main_loop_(SchedulerItem *item) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void Scheduler::trim_freelist() {
|
||||
LockGuard guard{this->lock_};
|
||||
SchedulerItem *item = this->scheduler_item_pool_head_;
|
||||
size_t freed = 0;
|
||||
while (item != nullptr) {
|
||||
SchedulerItem *next = item->next_free;
|
||||
delete item;
|
||||
#ifdef ESPHOME_DEBUG_SCHEDULER
|
||||
this->debug_live_items_--;
|
||||
#endif
|
||||
item = next;
|
||||
freed++;
|
||||
}
|
||||
this->scheduler_item_pool_head_ = nullptr;
|
||||
this->scheduler_item_pool_size_ = 0;
|
||||
|
||||
// The vectors that back items_/to_add_/defer_queue_ also retain their boot-peak
|
||||
// capacity (std::vector grows by doubling). Swap each with a same-content copy to
|
||||
// reclaim the slack -- the new vector is sized exactly to its current contents.
|
||||
std::vector<SchedulerItem *>(this->items_).swap(this->items_);
|
||||
std::vector<SchedulerItem *>(this->to_add_).swap(this->to_add_);
|
||||
#ifndef ESPHOME_THREAD_SINGLE
|
||||
std::vector<SchedulerItem *>(this->defer_queue_).swap(this->defer_queue_);
|
||||
#endif
|
||||
|
||||
#ifdef ESPHOME_DEBUG_SCHEDULER
|
||||
ESP_LOGD(TAG, "Freelist trimmed (%zu items freed)", freed);
|
||||
#else
|
||||
(void) freed;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ESPHOME_DEBUG_SCHEDULER
|
||||
void Scheduler::debug_log_timer_(const SchedulerItem *item, NameType name_type, const char *static_name,
|
||||
uint32_t hash_or_id, SchedulerItem::Type type, uint32_t delay, uint64_t now) {
|
||||
|
||||
@@ -132,6 +132,12 @@ class Scheduler {
|
||||
// @return Timestamp of the last item that ran, or `now` unchanged if none ran.
|
||||
uint32_t call(uint32_t now);
|
||||
|
||||
// Reclaim memory held by the post-boot peak. Frees every SchedulerItem in the
|
||||
// recycle freelist and shrinks items_/to_add_/defer_queue_ vector capacity to
|
||||
// their current sizes (std::vector grows by doubling and otherwise retains the
|
||||
// peak). Live items in those vectors are preserved.
|
||||
void trim_freelist();
|
||||
|
||||
// Move items from to_add_ into the main heap.
|
||||
// IMPORTANT: This method should only be called from the main thread (loop task).
|
||||
// Inlined: the fast path (nothing to add) is just an atomic load / empty check.
|
||||
|
||||
Reference in New Issue
Block a user