From 9e64e71cdf8bf769245539dc7899726a910eba09 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 8 May 2025 00:50:20 -0500 Subject: [PATCH] Require reserve_size in create_buffer to reduce realloc overhead (#8715) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- esphome/components/api/api_connection.cpp | 6 ++---- esphome/components/api/api_connection.h | 3 ++- esphome/components/api/proto.h | 12 +++++++++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index c444307bd6..ee0451f499 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -212,8 +212,7 @@ void APIConnection::loop() { msg_size += 1 + ProtoSize::varint(to_send) + to_send; ProtoSize::add_bool_field(msg_size, 1, done); - auto buffer = this->create_buffer(); - buffer.get_buffer()->reserve(msg_size); + auto buffer = this->create_buffer(msg_size); // fixed32 key = 1; buffer.encode_fixed32(1, esp32_camera::global_esp32_camera->get_object_id_hash()); // bytes data = 2; @@ -1807,8 +1806,7 @@ bool APIConnection::try_send_log_message(int level, const char *tag, const char msg_size += 1 + api::ProtoSize::varint(static_cast(line_length)) + line_length; // Create a pre-sized buffer - auto buffer = this->create_buffer(); - buffer.get_buffer()->reserve(msg_size); + auto buffer = this->create_buffer(msg_size); // Encode the message (SubscribeLogsResponse) buffer.encode_uint32(1, static_cast(level)); // LogLevel level = 1 diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 3fefe71cbb..1e47418d90 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -312,9 +312,10 @@ class APIConnection : public APIServerConnection { void on_fatal_error() override; void on_unauthenticated_access() override; void on_no_setup_connection() override; - ProtoWriteBuffer create_buffer() override { + ProtoWriteBuffer create_buffer(uint32_t reserve_size) override { // FIXME: ensure no recursive writes can happen this->proto_write_buffer_.clear(); + this->proto_write_buffer_.reserve(reserve_size); return {&this->proto_write_buffer_}; } bool send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) override; diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index bfa1a5c280..b8ee6b7920 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -311,7 +311,14 @@ class ProtoService { virtual void on_fatal_error() = 0; virtual void on_unauthenticated_access() = 0; virtual void on_no_setup_connection() = 0; - virtual ProtoWriteBuffer create_buffer() = 0; + /** + * Create a buffer with a reserved size. + * @param reserve_size The number of bytes to pre-allocate in the buffer. This is a hint + * to optimize memory usage and avoid reallocations during encoding. + * Implementations should aim to allocate at least this size. + * @return A ProtoWriteBuffer object with the reserved size. + */ + virtual ProtoWriteBuffer create_buffer(uint32_t reserve_size) = 0; virtual bool send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) = 0; virtual bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) = 0; @@ -321,8 +328,7 @@ class ProtoService { msg.calculate_size(msg_size); // Create a pre-sized buffer - auto buffer = this->create_buffer(); - buffer.get_buffer()->reserve(msg_size); + auto buffer = this->create_buffer(msg_size); // Encode message into the buffer msg.encode(buffer);