From a0532d657f02f276ed247f2b3944fa04dcbfcd71 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 29 Apr 2026 21:46:32 -0500 Subject: [PATCH] [api] Drop escape() helper and return-by-value APIBuffer in proxy decode benchmarks Simplifies the decode benchmarks to mirror the encode pattern more closely: no per-iteration asm volatile barrier, no return-by-value of APIBuffer through encode_message_for_proxy. CodSpeed callgrind has been crashing inside Decode_ZWaveProxyFrame and the previous setup was the main thing it had that the (passing) Encode_ZWaveProxyFrame did not. --- .../components/api/bench_proto_proxy.cpp | 60 ++++++++----------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/tests/benchmarks/components/api/bench_proto_proxy.cpp b/tests/benchmarks/components/api/bench_proto_proxy.cpp index 612d8e69f3..ae7fc0722c 100644 --- a/tests/benchmarks/components/api/bench_proto_proxy.cpp +++ b/tests/benchmarks/components/api/bench_proto_proxy.cpp @@ -13,17 +13,14 @@ namespace esphome::api::benchmarks { static constexpr int kInnerIterations = 2000; -template static APIBuffer encode_message_for_proxy(const T &msg) { - APIBuffer buffer; - uint32_t size = msg.calculate_size(); - buffer.resize(size); - ProtoWriteBuffer writer(&buffer, 0); - msg.encode(writer); - return buffer; +// Encodes `src` into `out`. Caller owns `out` and must keep it alive across +// the decode loop (decoded messages may store pointers back into its bytes). +template static void encode_into(APIBuffer &out, const T &src) { + out.resize(src.calculate_size()); + ProtoWriteBuffer writer(&out, 0); + src.encode(writer); } -static void escape_proxy(void *p) { asm volatile("" : : "g"(p) : "memory"); } - // --- ZWaveProxyFrame (Z-Wave frame, ~16 bytes payload) --- #ifdef USE_ZWAVE_PROXY @@ -53,18 +50,16 @@ static void Decode_ZWaveProxyFrame(benchmark::State &state) { ZWaveProxyFrame source; source.data = kZWaveFrameData; source.data_len = sizeof(kZWaveFrameData); - auto encoded = encode_message_for_proxy(source); - auto *data = encoded.data(); - auto size = encoded.size(); - benchmark::DoNotOptimize(data); - benchmark::DoNotOptimize(size); + APIBuffer encoded; + encode_into(encoded, source); + const uint8_t *data = encoded.data(); + size_t size = encoded.size(); for (auto _ : state) { for (int i = 0; i < kInnerIterations; i++) { ZWaveProxyFrame msg; - escape_proxy(&msg); msg.decode(data, size); - escape_proxy(&msg); + benchmark::DoNotOptimize(msg); } } state.SetItemsProcessed(state.iterations() * kInnerIterations); @@ -78,18 +73,16 @@ static void Decode_ZWaveProxyRequest(benchmark::State &state) { source.type = enums::ZWAVE_PROXY_REQUEST_TYPE_HOME_ID_CHANGE; source.data = kZWaveRequestData; source.data_len = sizeof(kZWaveRequestData); - auto encoded = encode_message_for_proxy(source); - auto *data = encoded.data(); - auto size = encoded.size(); - benchmark::DoNotOptimize(data); - benchmark::DoNotOptimize(size); + APIBuffer encoded; + encode_into(encoded, source); + const uint8_t *data = encoded.data(); + size_t size = encoded.size(); for (auto _ : state) { for (int i = 0; i < kInnerIterations; i++) { ZWaveProxyRequest msg; - escape_proxy(&msg); msg.decode(data, size); - escape_proxy(&msg); + benchmark::DoNotOptimize(msg); } } state.SetItemsProcessed(state.iterations() * kInnerIterations); @@ -135,18 +128,16 @@ static void Decode_SerialProxyWriteRequest(benchmark::State &state) { SerialProxyDataReceived source; source.instance = 0; source.set_data(kSerialPayload, kSerialPayloadSize); - auto encoded = encode_message_for_proxy(source); - auto *data = encoded.data(); - auto size = encoded.size(); - benchmark::DoNotOptimize(data); - benchmark::DoNotOptimize(size); + APIBuffer encoded; + encode_into(encoded, source); + const uint8_t *data = encoded.data(); + size_t size = encoded.size(); for (auto _ : state) { for (int i = 0; i < kInnerIterations; i++) { SerialProxyWriteRequest msg; - escape_proxy(&msg); msg.decode(data, size); - escape_proxy(&msg); + benchmark::DoNotOptimize(msg); } } state.SetItemsProcessed(state.iterations() * kInnerIterations); @@ -265,17 +256,14 @@ static APIBuffer build_infrared_rf_transmit_wire() { static void Decode_InfraredRFTransmitRawTimingsRequest(benchmark::State &state) { auto encoded = build_infrared_rf_transmit_wire(); - auto *data = encoded.data(); - auto size = encoded.size(); - benchmark::DoNotOptimize(data); - benchmark::DoNotOptimize(size); + const uint8_t *data = encoded.data(); + size_t size = encoded.size(); for (auto _ : state) { for (int i = 0; i < kInnerIterations; i++) { InfraredRFTransmitRawTimingsRequest msg; - escape_proxy(&msg); msg.decode(data, size); - escape_proxy(&msg); + benchmark::DoNotOptimize(msg); } } state.SetItemsProcessed(state.iterations() * kInnerIterations);