[api] Reduce API code size with buffer and nodelay optimizations (#14797)

This commit is contained in:
J. Nick Koston
2026-03-14 08:13:50 -10:00
committed by GitHub
parent 0043be6165
commit f2968e0449
4 changed files with 22 additions and 22 deletions

View File

@@ -44,6 +44,12 @@ class APIBuffer {
this->reserve(n);
this->size_ = n; // no zero-fill
}
/// Reserve capacity for max(reserve_size, new_size) bytes, then set size to new_size.
/// Single grow_ check regardless of argument order.
inline void reserve_and_resize(size_t reserve_size, size_t new_size) ESPHOME_ALWAYS_INLINE {
this->reserve(std::max(reserve_size, new_size));
this->size_ = new_size;
}
uint8_t *data() { return this->data_.get(); }
const uint8_t *data() const { return this->data_.get(); }
size_t size() const { return this->size_; }

View File

@@ -2025,8 +2025,7 @@ uint16_t APIConnection::encode_to_buffer(uint32_t calculated_size, MessageEncode
// Batch message second or later
// Add padding for previous message footer + this message header
size_t current_size = shared_buf.size();
shared_buf.reserve(current_size + total_calculated_size);
shared_buf.resize(current_size + footer_size + header_padding);
shared_buf.reserve_and_resize(current_size + total_calculated_size, current_size + footer_size + header_padding);
}
// Pre-resize buffer to include payload, then encode through raw pointer

View File

@@ -305,9 +305,9 @@ class APIConnection final : public APIServerConnectionBase {
// Reserve space for header padding + message + footer
// - Header padding: space for protocol headers (7 bytes for Noise, 6 for Plaintext)
// - Footer: space for MAC (16 bytes for Noise, 0 for Plaintext)
shared_buf.reserve(total_size);
// Resize to add header padding so message encoding starts at the correct position
shared_buf.resize(header_padding);
// Reserve full size but only set initial size to header padding
// so message encoding starts at the correct position
shared_buf.reserve_and_resize(total_size, header_padding);
}
// Convenience overload - computes frame overhead internally

View File

@@ -147,22 +147,18 @@ class APIFrameHelper {
//
void set_nodelay_for_message(bool is_log_message) {
if (!is_log_message) {
if (this->nodelay_state_ != NODELAY_ON) {
if (this->nodelay_counter_) {
this->set_nodelay_raw_(true);
this->nodelay_state_ = NODELAY_ON;
this->nodelay_counter_ = 0;
}
return;
}
// Log messages: state transitions -1 -> 1 -> ... -> LOG_NAGLE_COUNT -> -1 (flush)
if (this->nodelay_state_ == NODELAY_ON) {
// Log message: enable Nagle on first, flush after LOG_NAGLE_COUNT
if (!this->nodelay_counter_)
this->set_nodelay_raw_(false);
this->nodelay_state_ = 1;
} else if (this->nodelay_state_ >= LOG_NAGLE_COUNT) {
if (++this->nodelay_counter_ > LOG_NAGLE_COUNT) {
this->set_nodelay_raw_(true);
this->nodelay_state_ = NODELAY_ON;
} else {
this->nodelay_state_++;
this->nodelay_counter_ = 0;
}
}
virtual APIError write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) = 0;
@@ -258,18 +254,17 @@ class APIFrameHelper {
uint8_t tx_buf_head_{0};
uint8_t tx_buf_tail_{0};
uint8_t tx_buf_count_{0};
// Nagle batching state for log messages. NODELAY_ON (-1) means NODELAY is enabled
// (immediate send). Values 1..LOG_NAGLE_COUNT count log messages in the current Nagle batch.
// After LOG_NAGLE_COUNT logs, we switch to NODELAY to flush and reset.
// Nagle batching counter for log messages. 0 means NODELAY is enabled (immediate send).
// Values 1..LOG_NAGLE_COUNT count log messages in the current Nagle batch.
// After LOG_NAGLE_COUNT logs, we flush by re-enabling NODELAY and resetting to 0.
// ESP8266 has the tightest TCP send buffer (2×MSS) and needs conservative batching.
// ESP32 (4×MSS+), RP2040 (8×MSS), and LibreTiny (4×MSS) can coalesce more.
static constexpr int8_t NODELAY_ON = -1;
#ifdef USE_ESP8266
static constexpr int8_t LOG_NAGLE_COUNT = 2;
static constexpr uint8_t LOG_NAGLE_COUNT = 2;
#else
static constexpr int8_t LOG_NAGLE_COUNT = 3;
static constexpr uint8_t LOG_NAGLE_COUNT = 3;
#endif
int8_t nodelay_state_{NODELAY_ON};
uint8_t nodelay_counter_{0};
// Internal helper to set TCP_NODELAY socket option
void set_nodelay_raw_(bool enable) {