From 1d4dbf5476c56dd4740a7bb5ac405a13550968f2 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 29 Apr 2026 22:05:45 -0500 Subject: [PATCH] [api] Mark InfraredRFReceiveEvent encode/calculate_size as speed_optimized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This message is emitted on every IR/RF receive event with a packed sint32 timings array (typically ~50-200 entries). The encode walks the vector calling ProtoEncode::encode_sint32 per element; under -Os GCC does not inline those helpers, so each element pays the call overhead. Adding option (speed_optimized) = true to the proto definition causes the codegen to emit __attribute__((optimize("O2"))) on encode and calculate_size, matching what already exists on SensorStateResponse, SubscribeLogsResponse, and BluetoothLERawAdvertisementsResponse — the other high-volume server-emitted messages. The CodSpeed Encode_InfraredRFReceiveEvent / CalculateSize_InfraredRFReceiveEvent benchmarks added in the parent PR will quantify the improvement. --- esphome/components/api/api.proto | 1 + esphome/components/api/api_pb2.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 391efbd6eb..6705a30526 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -2571,6 +2571,7 @@ message InfraredRFReceiveEvent { option (source) = SOURCE_SERVER; option (ifdef) = "USE_IR_RF || USE_RADIO_FREQUENCY"; option (no_delay) = true; + option (speed_optimized) = true; uint32 device_id = 1 [(field_ifdef) = "USE_DEVICES"]; fixed32 key = 2 [(force) = true]; // Key identifying the receiver instance diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index eb25bf7461..95bdb994d3 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -3910,7 +3910,9 @@ bool InfraredRFTransmitRawTimingsRequest::decode_32bit(uint32_t field_id, Proto3 } return true; } -uint8_t *InfraredRFReceiveEvent::encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_PARAM) const { +__attribute__((optimize("O2"))) // NOLINT(clang-diagnostic-unknown-attributes) +uint8_t * +InfraredRFReceiveEvent::encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_PARAM) const { uint8_t *__restrict__ pos = buffer.get_pos(); #ifdef USE_DEVICES ProtoEncode::encode_uint32(pos PROTO_ENCODE_DEBUG_ARG, 1, this->device_id); @@ -3921,7 +3923,9 @@ uint8_t *InfraredRFReceiveEvent::encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DE } return pos; } -uint32_t InfraredRFReceiveEvent::calculate_size() const { +__attribute__((optimize("O2"))) // NOLINT(clang-diagnostic-unknown-attributes) +uint32_t +InfraredRFReceiveEvent::calculate_size() const { uint32_t size = 0; #ifdef USE_DEVICES size += ProtoSize::calc_uint32(1, this->device_id);