[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.
This commit is contained in:
J. Nick Koston
2026-04-29 21:46:32 -05:00
parent 483d294ef6
commit a0532d657f
@@ -13,17 +13,14 @@ namespace esphome::api::benchmarks {
static constexpr int kInnerIterations = 2000; static constexpr int kInnerIterations = 2000;
template<typename T> static APIBuffer encode_message_for_proxy(const T &msg) { // Encodes `src` into `out`. Caller owns `out` and must keep it alive across
APIBuffer buffer; // the decode loop (decoded messages may store pointers back into its bytes).
uint32_t size = msg.calculate_size(); template<typename T> static void encode_into(APIBuffer &out, const T &src) {
buffer.resize(size); out.resize(src.calculate_size());
ProtoWriteBuffer writer(&buffer, 0); ProtoWriteBuffer writer(&out, 0);
msg.encode(writer); src.encode(writer);
return buffer;
} }
static void escape_proxy(void *p) { asm volatile("" : : "g"(p) : "memory"); }
// --- ZWaveProxyFrame (Z-Wave frame, ~16 bytes payload) --- // --- ZWaveProxyFrame (Z-Wave frame, ~16 bytes payload) ---
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
@@ -53,18 +50,16 @@ static void Decode_ZWaveProxyFrame(benchmark::State &state) {
ZWaveProxyFrame source; ZWaveProxyFrame source;
source.data = kZWaveFrameData; source.data = kZWaveFrameData;
source.data_len = sizeof(kZWaveFrameData); source.data_len = sizeof(kZWaveFrameData);
auto encoded = encode_message_for_proxy(source); APIBuffer encoded;
auto *data = encoded.data(); encode_into(encoded, source);
auto size = encoded.size(); const uint8_t *data = encoded.data();
benchmark::DoNotOptimize(data); size_t size = encoded.size();
benchmark::DoNotOptimize(size);
for (auto _ : state) { for (auto _ : state) {
for (int i = 0; i < kInnerIterations; i++) { for (int i = 0; i < kInnerIterations; i++) {
ZWaveProxyFrame msg; ZWaveProxyFrame msg;
escape_proxy(&msg);
msg.decode(data, size); msg.decode(data, size);
escape_proxy(&msg); benchmark::DoNotOptimize(msg);
} }
} }
state.SetItemsProcessed(state.iterations() * kInnerIterations); 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.type = enums::ZWAVE_PROXY_REQUEST_TYPE_HOME_ID_CHANGE;
source.data = kZWaveRequestData; source.data = kZWaveRequestData;
source.data_len = sizeof(kZWaveRequestData); source.data_len = sizeof(kZWaveRequestData);
auto encoded = encode_message_for_proxy(source); APIBuffer encoded;
auto *data = encoded.data(); encode_into(encoded, source);
auto size = encoded.size(); const uint8_t *data = encoded.data();
benchmark::DoNotOptimize(data); size_t size = encoded.size();
benchmark::DoNotOptimize(size);
for (auto _ : state) { for (auto _ : state) {
for (int i = 0; i < kInnerIterations; i++) { for (int i = 0; i < kInnerIterations; i++) {
ZWaveProxyRequest msg; ZWaveProxyRequest msg;
escape_proxy(&msg);
msg.decode(data, size); msg.decode(data, size);
escape_proxy(&msg); benchmark::DoNotOptimize(msg);
} }
} }
state.SetItemsProcessed(state.iterations() * kInnerIterations); state.SetItemsProcessed(state.iterations() * kInnerIterations);
@@ -135,18 +128,16 @@ static void Decode_SerialProxyWriteRequest(benchmark::State &state) {
SerialProxyDataReceived source; SerialProxyDataReceived source;
source.instance = 0; source.instance = 0;
source.set_data(kSerialPayload, kSerialPayloadSize); source.set_data(kSerialPayload, kSerialPayloadSize);
auto encoded = encode_message_for_proxy(source); APIBuffer encoded;
auto *data = encoded.data(); encode_into(encoded, source);
auto size = encoded.size(); const uint8_t *data = encoded.data();
benchmark::DoNotOptimize(data); size_t size = encoded.size();
benchmark::DoNotOptimize(size);
for (auto _ : state) { for (auto _ : state) {
for (int i = 0; i < kInnerIterations; i++) { for (int i = 0; i < kInnerIterations; i++) {
SerialProxyWriteRequest msg; SerialProxyWriteRequest msg;
escape_proxy(&msg);
msg.decode(data, size); msg.decode(data, size);
escape_proxy(&msg); benchmark::DoNotOptimize(msg);
} }
} }
state.SetItemsProcessed(state.iterations() * kInnerIterations); state.SetItemsProcessed(state.iterations() * kInnerIterations);
@@ -265,17 +256,14 @@ static APIBuffer build_infrared_rf_transmit_wire() {
static void Decode_InfraredRFTransmitRawTimingsRequest(benchmark::State &state) { static void Decode_InfraredRFTransmitRawTimingsRequest(benchmark::State &state) {
auto encoded = build_infrared_rf_transmit_wire(); auto encoded = build_infrared_rf_transmit_wire();
auto *data = encoded.data(); const uint8_t *data = encoded.data();
auto size = encoded.size(); size_t size = encoded.size();
benchmark::DoNotOptimize(data);
benchmark::DoNotOptimize(size);
for (auto _ : state) { for (auto _ : state) {
for (int i = 0; i < kInnerIterations; i++) { for (int i = 0; i < kInnerIterations; i++) {
InfraredRFTransmitRawTimingsRequest msg; InfraredRFTransmitRawTimingsRequest msg;
escape_proxy(&msg);
msg.decode(data, size); msg.decode(data, size);
escape_proxy(&msg); benchmark::DoNotOptimize(msg);
} }
} }
state.SetItemsProcessed(state.iterations() * kInnerIterations); state.SetItemsProcessed(state.iterations() * kInnerIterations);