mirror of
https://github.com/esphome/esphome.git
synced 2026-07-11 09:25:34 +00:00
8c058cd725
Encode messages once in setup using the real protobuf API, then decode the resulting bytes in the benchmark loop. This keeps decode benchmarks automatically in sync with the protobuf schema — hand-encoded byte arrays would silently break when fields change.
94 lines
2.9 KiB
C++
94 lines
2.9 KiB
C++
#include <benchmark/benchmark.h>
|
|
|
|
#include "esphome/components/api/api_pb2.h"
|
|
#include "esphome/components/api/api_buffer.h"
|
|
|
|
namespace esphome::api::benchmarks {
|
|
|
|
// Inner iteration count to amortize CodSpeed instrumentation overhead.
|
|
// Without this, the ~60ns per-iteration valgrind start/stop cost dominates
|
|
// 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<typename T> 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) {
|
|
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.data(), encoded.size());
|
|
}
|
|
benchmark::DoNotOptimize(msg.api_version_major);
|
|
}
|
|
state.SetItemsProcessed(state.iterations() * kInnerIterations);
|
|
}
|
|
BENCHMARK(Decode_HelloRequest);
|
|
|
|
// --- SwitchCommandRequest decode (simple command) ---
|
|
|
|
static void Decode_SwitchCommandRequest(benchmark::State &state) {
|
|
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.data(), encoded.size());
|
|
}
|
|
benchmark::DoNotOptimize(msg.state);
|
|
}
|
|
state.SetItemsProcessed(state.iterations() * kInnerIterations);
|
|
}
|
|
BENCHMARK(Decode_SwitchCommandRequest);
|
|
|
|
// --- LightCommandRequest decode (complex command with many fields) ---
|
|
|
|
static void Decode_LightCommandRequest(benchmark::State &state) {
|
|
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.data(), encoded.size());
|
|
}
|
|
benchmark::DoNotOptimize(msg.brightness);
|
|
}
|
|
state.SetItemsProcessed(state.iterations() * kInnerIterations);
|
|
}
|
|
BENCHMARK(Decode_LightCommandRequest);
|
|
|
|
} // namespace esphome::api::benchmarks
|