mirror of
https://github.com/esphome/esphome.git
synced 2026-09-20 19:48:39 +00:00
[core] fast_select stats: log details on load-bearing hit
Adds a non-inline helper note_fast_select_load_bearing_() invoked only when the scan found data and the task notification counter was 0. Logs: hit sequence number, lwip_sock pointer, index in monitored_sockets_, raw rcvevent value, delay_ms, and how many other sockets also had data at that instant. Hot path is unchanged — the helper is out-of-line so yield_with_select_ still inlines to the same code as before for the zero-hit path.
This commit is contained in:
@@ -462,6 +462,34 @@ void Application::log_fast_select_scan_stats_() {
|
||||
load_bearing);
|
||||
}
|
||||
|
||||
void Application::note_fast_select_load_bearing_(struct lwip_sock *sock, uint32_t delay_ms) {
|
||||
uint32_t load_bearing = fast_select_scan_load_bearing_.fetch_add(1, std::memory_order_relaxed) + 1;
|
||||
// Find the socket's index in monitored_sockets_ for easier correlation with registration order.
|
||||
int index = -1;
|
||||
for (size_t i = 0; i < this->monitored_sockets_.size(); i++) {
|
||||
if (this->monitored_sockets_[i] == sock) {
|
||||
index = static_cast<int>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Read the rcvevent value directly. This is the same offset-based read used by
|
||||
// esphome_lwip_socket_has_data(); value > 0 means unread data is queued.
|
||||
int16_t rcvevent =
|
||||
*reinterpret_cast<volatile int16_t *>(reinterpret_cast<char *>(sock) + ESPHOME_LWIP_SOCK_RCVEVENT_OFFSET);
|
||||
// Count how many other sockets also had data at this scan (could reveal whether it's always
|
||||
// the same socket or a burst across multiple).
|
||||
size_t sockets_with_data = 0;
|
||||
for (struct lwip_sock *s : this->monitored_sockets_) {
|
||||
if (esphome_lwip_socket_has_data(s))
|
||||
sockets_with_data++;
|
||||
}
|
||||
ESP_LOGW(TAG,
|
||||
"fast_select LOAD-BEARING hit #%" PRIu32 ": sock=%p idx=%d/%u rcvevent=%d delay_ms=%" PRIu32
|
||||
" sockets_with_data=%u",
|
||||
load_bearing, sock, index, static_cast<unsigned>(this->monitored_sockets_.size()), rcvevent, delay_ms,
|
||||
static_cast<unsigned>(sockets_with_data));
|
||||
}
|
||||
|
||||
bool Application::register_socket(struct lwip_sock *sock) {
|
||||
// It modifies monitored_sockets_ without locking — must only be called from the main loop.
|
||||
if (sock == nullptr)
|
||||
|
||||
@@ -664,6 +664,8 @@ class Application {
|
||||
static std::atomic<uint32_t> fast_select_scan_load_bearing_;
|
||||
uint32_t fast_select_scan_stats_last_log_{0};
|
||||
void log_fast_select_scan_stats_();
|
||||
// Non-inline, called only on the rare load-bearing event so the hot path stays unchanged.
|
||||
void note_fast_select_load_bearing_(struct lwip_sock *sock, uint32_t delay_ms);
|
||||
#elif defined(USE_HOST)
|
||||
std::vector<int> socket_fds_; // Vector of all monitored socket file descriptors
|
||||
#endif
|
||||
@@ -947,7 +949,8 @@ inline void ESPHOME_ALWAYS_INLINE Application::yield_with_select_(uint32_t delay
|
||||
fast_select_scan_found_data_.fetch_add(1, std::memory_order_relaxed);
|
||||
if (fast_select_notify_value_before_scan == 0) {
|
||||
// Scan was load-bearing: no notification pending, so Take would have stalled.
|
||||
fast_select_scan_load_bearing_.fetch_add(1, std::memory_order_relaxed);
|
||||
// Delegate to a non-inline helper so the hot path stays the same size.
|
||||
this->note_fast_select_load_bearing_(sock, delay_ms);
|
||||
}
|
||||
yield();
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user