From ccafd442a7ec4515e8c2da710f599f8b8d38089f Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 29 Mar 2026 14:32:47 -1000 Subject: [PATCH] [api] Use static constexpr HEADER_PADDING instead of loading member field The header padding is a compile-time constant per protocol (6 for plaintext, 7 for noise). Using constexpr eliminates memory loads on the hot path. The value is defined once per class with the component breakdown in the comment. --- esphome/components/api/api_frame_helper_noise.cpp | 3 +-- esphome/components/api/api_frame_helper_noise.h | 14 ++++++++------ .../components/api/api_frame_helper_plaintext.cpp | 12 +++++------- .../components/api/api_frame_helper_plaintext.h | 14 ++++++++------ 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/esphome/components/api/api_frame_helper_noise.cpp b/esphome/components/api/api_frame_helper_noise.cpp index e5ed1d8657..62073bb440 100644 --- a/esphome/components/api/api_frame_helper_noise.cpp +++ b/esphome/components/api/api_frame_helper_noise.cpp @@ -497,8 +497,7 @@ APIError APINoiseFrameHelper::write_protobuf_packet(uint8_t type, ProtoWriteBuff if (frame_footer_size_) buffer.get_buffer()->resize(buffer.get_buffer()->size() + frame_footer_size_); - MessageInfo msg{type, 0, - static_cast(buffer.get_buffer()->size() - frame_header_padding_ - frame_footer_size_)}; + MessageInfo msg{type, 0, static_cast(buffer.get_buffer()->size() - HEADER_PADDING - frame_footer_size_)}; uint8_t *buf_start = buffer.get_buffer()->data(); struct iovec iov; APIError aerr = this->encrypt_noise_message_(buf_start, msg, iov); diff --git a/esphome/components/api/api_frame_helper_noise.h b/esphome/components/api/api_frame_helper_noise.h index e56006d955..53c18431d6 100644 --- a/esphome/components/api/api_frame_helper_noise.h +++ b/esphome/components/api/api_frame_helper_noise.h @@ -9,14 +9,16 @@ namespace esphome::api { class APINoiseFrameHelper final : public APIFrameHelper { public: + // Noise header structure: + // Pos 0: indicator (0x01) + // Pos 1-2: encrypted payload size (16-bit big-endian) + // Pos 3-6: encrypted type (16-bit) + data_len (16-bit) + // Pos 7+: actual payload data + static constexpr uint8_t HEADER_PADDING = 1 + 2 + 2 + 2; // indicator + size + type + data_len + APINoiseFrameHelper(std::unique_ptr socket, APINoiseContext &ctx) : APIFrameHelper(std::move(socket)), ctx_(ctx) { - // Noise header structure: - // Pos 0: indicator (0x01) - // Pos 1-2: encrypted payload size (16-bit big-endian) - // Pos 3-6: encrypted type (16-bit) + data_len (16-bit) - // Pos 7+: actual payload data - frame_header_padding_ = 7; + frame_header_padding_ = HEADER_PADDING; } ~APINoiseFrameHelper() override; APIError init() override; diff --git a/esphome/components/api/api_frame_helper_plaintext.cpp b/esphome/components/api/api_frame_helper_plaintext.cpp index 53ee58590d..b74b215e15 100644 --- a/esphome/components/api/api_frame_helper_plaintext.cpp +++ b/esphome/components/api/api_frame_helper_plaintext.cpp @@ -287,10 +287,10 @@ APIError APIPlaintextFrameHelper::write_protobuf_packet(uint8_t type, ProtoWrite assert(this->state_ == State::DATA); #endif - MessageInfo msg{type, 0, static_cast(buffer.get_buffer()->size() - frame_header_padding_)}; + MessageInfo msg{type, 0, static_cast(buffer.get_buffer()->size() - HEADER_PADDING)}; uint8_t *buffer_data = buffer.get_buffer()->data(); - uint8_t header_len = write_plaintext_header(buffer_data, msg, frame_header_padding_); - uint8_t *msg_start = buffer_data + frame_header_padding_ - header_len; + uint8_t header_len = write_plaintext_header(buffer_data, msg, HEADER_PADDING); + uint8_t *msg_start = buffer_data + HEADER_PADDING - header_len; uint16_t msg_len = static_cast(header_len + msg.payload_size); LOG_PACKET_SENDING(msg_start, msg_len); return this->write_raw_fast_buf_(msg_start, msg_len); @@ -302,15 +302,13 @@ APIError APIPlaintextFrameHelper::write_protobuf_messages(ProtoWriteBuffer buffe assert(this->state_ == State::DATA); assert(!messages.empty()); #endif - uint8_t *buffer_data = buffer.get_buffer()->data(); StaticVector iovs; uint16_t total_write_len = 0; - const uint8_t padding = frame_header_padding_; for (const auto &msg : messages) { - uint8_t header_len = write_plaintext_header(buffer_data + msg.offset, msg, padding); - uint8_t *msg_start = buffer_data + msg.offset + padding - header_len; + uint8_t header_len = write_plaintext_header(buffer_data + msg.offset, msg, HEADER_PADDING); + uint8_t *msg_start = buffer_data + msg.offset + HEADER_PADDING - header_len; size_t msg_len = static_cast(header_len + msg.payload_size); iovs.push_back({msg_start, msg_len}); total_write_len += msg_len; diff --git a/esphome/components/api/api_frame_helper_plaintext.h b/esphome/components/api/api_frame_helper_plaintext.h index 96d47e9c7b..8314754715 100644 --- a/esphome/components/api/api_frame_helper_plaintext.h +++ b/esphome/components/api/api_frame_helper_plaintext.h @@ -7,13 +7,15 @@ namespace esphome::api { class APIPlaintextFrameHelper final : public APIFrameHelper { public: + // Plaintext header structure (worst case): + // Pos 0: indicator (0x00) + // Pos 1-3: payload size varint (up to 3 bytes) + // Pos 4-5: message type varint (up to 2 bytes) + // Pos 6+: actual payload data + static constexpr uint8_t HEADER_PADDING = 1 + 3 + 2; // indicator + size varint + type varint + explicit APIPlaintextFrameHelper(std::unique_ptr socket) : APIFrameHelper(std::move(socket)) { - // Plaintext header structure (worst case): - // Pos 0: indicator (0x00) - // Pos 1-3: payload size varint (up to 3 bytes) - // Pos 4-5: message type varint (up to 2 bytes) - // Pos 6+: actual payload data - frame_header_padding_ = 6; + frame_header_padding_ = HEADER_PADDING; } ~APIPlaintextFrameHelper() override = default; APIError init() override;