Reserve space in the frame helper when we know in advance how much we need (#8716)

This commit is contained in:
J. Nick Koston 2025-05-08 00:43:39 -05:00 committed by GitHub
parent 882273cb56
commit ef2621aa54
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -5,6 +5,7 @@
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "proto.h" #include "proto.h"
#include "api_pb2_size.h"
#include <cstring> #include <cstring>
namespace esphome { namespace esphome {
@ -574,6 +575,8 @@ APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) {
if (!tx_buf_.empty()) { if (!tx_buf_.empty()) {
// tx buf not empty, can't write now because then stream would be inconsistent // tx buf not empty, can't write now because then stream would be inconsistent
// Reserve space upfront to avoid multiple reallocations
tx_buf_.reserve(tx_buf_.size() + total_write_len);
for (int i = 0; i < iovcnt; i++) { for (int i = 0; i < iovcnt; i++) {
tx_buf_.insert(tx_buf_.end(), reinterpret_cast<uint8_t *>(iov[i].iov_base), tx_buf_.insert(tx_buf_.end(), reinterpret_cast<uint8_t *>(iov[i].iov_base),
reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].iov_len); reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].iov_len);
@ -584,6 +587,8 @@ APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) {
ssize_t sent = socket_->writev(iov, iovcnt); ssize_t sent = socket_->writev(iov, iovcnt);
if (is_would_block(sent)) { if (is_would_block(sent)) {
// operation would block, add buffer to tx_buf // operation would block, add buffer to tx_buf
// Reserve space upfront to avoid multiple reallocations
tx_buf_.reserve(tx_buf_.size() + total_write_len);
for (int i = 0; i < iovcnt; i++) { for (int i = 0; i < iovcnt; i++) {
tx_buf_.insert(tx_buf_.end(), reinterpret_cast<uint8_t *>(iov[i].iov_base), tx_buf_.insert(tx_buf_.end(), reinterpret_cast<uint8_t *>(iov[i].iov_base),
reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].iov_len); reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].iov_len);
@ -596,6 +601,10 @@ APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) {
return APIError::SOCKET_WRITE_FAILED; return APIError::SOCKET_WRITE_FAILED;
} else if ((size_t) sent != total_write_len) { } else if ((size_t) sent != total_write_len) {
// partially sent, add end to tx_buf // partially sent, add end to tx_buf
size_t remaining = total_write_len - sent;
// Reserve space upfront to avoid multiple reallocations
tx_buf_.reserve(tx_buf_.size() + remaining);
size_t to_consume = sent; size_t to_consume = sent;
for (int i = 0; i < iovcnt; i++) { for (int i = 0; i < iovcnt; i++) {
if (to_consume >= iov[i].iov_len) { if (to_consume >= iov[i].iov_len) {
@ -933,6 +942,8 @@ APIError APIPlaintextFrameHelper::write_packet(uint16_t type, const uint8_t *pay
} }
std::vector<uint8_t> header; std::vector<uint8_t> header;
header.reserve(1 + api::ProtoSize::varint(static_cast<uint32_t>(payload_len)) +
api::ProtoSize::varint(static_cast<uint32_t>(type)));
header.push_back(0x00); header.push_back(0x00);
ProtoVarInt(payload_len).encode(header); ProtoVarInt(payload_len).encode(header);
ProtoVarInt(type).encode(header); ProtoVarInt(type).encode(header);
@ -994,6 +1005,8 @@ APIError APIPlaintextFrameHelper::write_raw_(const struct iovec *iov, int iovcnt
if (!tx_buf_.empty()) { if (!tx_buf_.empty()) {
// tx buf not empty, can't write now because then stream would be inconsistent // tx buf not empty, can't write now because then stream would be inconsistent
// Reserve space upfront to avoid multiple reallocations
tx_buf_.reserve(tx_buf_.size() + total_write_len);
for (int i = 0; i < iovcnt; i++) { for (int i = 0; i < iovcnt; i++) {
tx_buf_.insert(tx_buf_.end(), reinterpret_cast<uint8_t *>(iov[i].iov_base), tx_buf_.insert(tx_buf_.end(), reinterpret_cast<uint8_t *>(iov[i].iov_base),
reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].iov_len); reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].iov_len);
@ -1004,6 +1017,8 @@ APIError APIPlaintextFrameHelper::write_raw_(const struct iovec *iov, int iovcnt
ssize_t sent = socket_->writev(iov, iovcnt); ssize_t sent = socket_->writev(iov, iovcnt);
if (is_would_block(sent)) { if (is_would_block(sent)) {
// operation would block, add buffer to tx_buf // operation would block, add buffer to tx_buf
// Reserve space upfront to avoid multiple reallocations
tx_buf_.reserve(tx_buf_.size() + total_write_len);
for (int i = 0; i < iovcnt; i++) { for (int i = 0; i < iovcnt; i++) {
tx_buf_.insert(tx_buf_.end(), reinterpret_cast<uint8_t *>(iov[i].iov_base), tx_buf_.insert(tx_buf_.end(), reinterpret_cast<uint8_t *>(iov[i].iov_base),
reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].iov_len); reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].iov_len);
@ -1016,6 +1031,10 @@ APIError APIPlaintextFrameHelper::write_raw_(const struct iovec *iov, int iovcnt
return APIError::SOCKET_WRITE_FAILED; return APIError::SOCKET_WRITE_FAILED;
} else if ((size_t) sent != total_write_len) { } else if ((size_t) sent != total_write_len) {
// partially sent, add end to tx_buf // partially sent, add end to tx_buf
size_t remaining = total_write_len - sent;
// Reserve space upfront to avoid multiple reallocations
tx_buf_.reserve(tx_buf_.size() + remaining);
size_t to_consume = sent; size_t to_consume = sent;
for (int i = 0; i < iovcnt; i++) { for (int i = 0; i < iovcnt; i++) {
if (to_consume >= iov[i].iov_len) { if (to_consume >= iov[i].iov_len) {