From d341ee8c767ff8b4bc75a5b16b264ba8be5c6184 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 3 Apr 2026 10:21:20 -1000 Subject: [PATCH] [esp32_ble] Skip dropped count check when queue is empty On Xtensa (dual-core ESP32), even relaxed atomic loads emit a memw barrier instruction. The dropped_count_ check in get_and_reset_dropped_count() was executing every loop() iteration even when the queue was empty. Since drops only occur when the queue is full, and only the main loop drains the queue, an empty queue guarantees no new drops since the last reset. Restructure the loop to early-return when pop() returns nullptr, skipping the unnecessary memw. Also moves advertising_->loop() before the queue drain so it runs unconditionally without duplication, and converts while to do/while since the first element is known non-null after the nullptr check. --- esphome/components/esp32_ble/ble.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index 2cd2ec67f7..68e5fffe2b 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -399,8 +399,17 @@ void ESP32BLE::loop() { return; } +#ifdef USE_ESP32_BLE_ADVERTISING + if (this->advertising_ != nullptr) { + this->advertising_->loop(); + } +#endif + BLEEvent *ble_event = this->ble_events_.pop(); - while (ble_event != nullptr) { + if (ble_event == nullptr) + return; + + do { switch (ble_event->type_) { #if defined(USE_ESP32_BLE_SERVER) && defined(ESPHOME_ESP32_BLE_GATTS_EVENT_HANDLER_COUNT) case BLEEvent::GATTS: { @@ -488,15 +497,11 @@ void ESP32BLE::loop() { } // Return the event to the pool this->ble_event_pool_.release(ble_event); - ble_event = this->ble_events_.pop(); - } -#ifdef USE_ESP32_BLE_ADVERTISING - if (this->advertising_ != nullptr) { - this->advertising_->loop(); - } -#endif + } while ((ble_event = this->ble_events_.pop()) != nullptr); - // Log dropped events periodically + // Log dropped events - only reachable when events were processed. + // Drops only occur when the queue is full, and only this loop drains it, + // so if pop() returned nullptr above we can skip this check (saves a memw). uint16_t dropped = this->ble_events_.get_and_reset_dropped_count(); if (dropped > 0) { ESP_LOGW(TAG, "Dropped %u BLE events due to buffer overflow", dropped);