diff --git a/tests/benchmarks/components/api/bench_proto_decode.cpp b/tests/benchmarks/components/api/bench_proto_decode.cpp index a5ecf78cde3..113201dd8a1 100644 --- a/tests/benchmarks/components/api/bench_proto_decode.cpp +++ b/tests/benchmarks/components/api/bench_proto_decode.cpp @@ -10,24 +10,32 @@ namespace esphome::api::benchmarks { // sub-microsecond benchmarks. static constexpr int kInnerIterations = 2000; +// Helper: encode a message into a buffer and return it. +// Benchmarks encode once in setup, then decode the resulting bytes in a loop. +// This keeps decode benchmarks in sync with the actual protobuf schema — +// hand-encoded byte arrays would silently break when fields change. +template static APIBuffer encode_message(const T &msg) { + APIBuffer buffer; + uint32_t size = msg.calculate_size(); + buffer.resize(size); + ProtoWriteBuffer writer(&buffer, 0); + msg.encode(writer); + return buffer; +} + // --- HelloRequest decode (string + varint fields) --- static void Decode_HelloRequest(benchmark::State &state) { - // Manually encoded HelloRequest: - // field 1 (string): "aioesphomeapi" - // field 2 (varint): 1 (api_version_major) - // field 3 (varint): 10 (api_version_minor) - uint8_t encoded[] = { - 0x0A, 0x0D, // field 1, length 13 - 'a', 'i', 'o', 'e', 's', 'p', 'h', 'o', 'm', 'e', 'a', 'p', 'i', // "aioesphomeapi" - 0x10, 0x01, // field 2, value 1 - 0x18, 0x0A, // field 3, value 10 - }; + HelloRequest source; + source.client_info = StringRef::from_lit("aioesphomeapi"); + source.api_version_major = 1; + source.api_version_minor = 10; + auto encoded = encode_message(source); for (auto _ : state) { HelloRequest msg; for (int i = 0; i < kInnerIterations; i++) { - msg.decode(encoded, sizeof(encoded)); + msg.decode(encoded.data(), encoded.size()); } benchmark::DoNotOptimize(msg.api_version_major); } @@ -38,17 +46,15 @@ BENCHMARK(Decode_HelloRequest); // --- SwitchCommandRequest decode (simple command) --- static void Decode_SwitchCommandRequest(benchmark::State &state) { - // field 1 (fixed32): key = 0x12345678 - // field 2 (varint): state = true - uint8_t encoded[] = { - 0x0D, 0x78, 0x56, 0x34, 0x12, // field 1, fixed32 - 0x10, 0x01, // field 2, varint true - }; + SwitchCommandRequest source; + source.key = 0x12345678; + source.state = true; + auto encoded = encode_message(source); for (auto _ : state) { SwitchCommandRequest msg; for (int i = 0; i < kInnerIterations; i++) { - msg.decode(encoded, sizeof(encoded)); + msg.decode(encoded.data(), encoded.size()); } benchmark::DoNotOptimize(msg.state); } @@ -59,70 +65,24 @@ BENCHMARK(Decode_SwitchCommandRequest); // --- LightCommandRequest decode (complex command with many fields) --- static void Decode_LightCommandRequest(benchmark::State &state) { - uint8_t encoded[] = { - // field 1: key (fixed32) = 0x11223344 - 0x0D, - 0x44, - 0x33, - 0x22, - 0x11, - // field 2: has_state (varint) = true - 0x10, - 0x01, - // field 3: state (varint) = true - 0x18, - 0x01, - // field 4: has_brightness (varint) = true - 0x20, - 0x01, - // field 5: brightness (fixed32/float) = 0.8 - 0x2D, - 0xCD, - 0xCC, - 0x4C, - 0x3F, - // field 9: has_rgb (varint) = true - 0x48, - 0x01, - // field 10: red (fixed32/float) = 1.0 - 0x55, - 0x00, - 0x00, - 0x80, - 0x3F, - // field 11: green (fixed32/float) = 0.5 - 0x5D, - 0x00, - 0x00, - 0x00, - 0x3F, - // field 12: blue (fixed32/float) = 0.2 - 0x65, - 0xCD, - 0xCC, - 0x4C, - 0x3E, - // field 20: has_effect (varint) = true - 0xA0, - 0x01, - 0x01, - // field 21: effect (string) = "rainbow" - 0xAA, - 0x01, - 0x07, - 'r', - 'a', - 'i', - 'n', - 'b', - 'o', - 'w', - }; + LightCommandRequest source; + source.key = 0x11223344; + source.has_state = true; + source.state = true; + source.has_brightness = true; + source.brightness = 0.8f; + source.has_rgb = true; + source.red = 1.0f; + source.green = 0.5f; + source.blue = 0.2f; + source.has_effect = true; + source.effect = StringRef::from_lit("rainbow"); + auto encoded = encode_message(source); for (auto _ : state) { LightCommandRequest msg; for (int i = 0; i < kInnerIterations; i++) { - msg.decode(encoded, sizeof(encoded)); + msg.decode(encoded.data(), encoded.size()); } benchmark::DoNotOptimize(msg.brightness); }