mirror of
https://github.com/esphome/esphome.git
synced 2026-07-10 17:05:36 +00:00
483d294ef6
Splitting these out from bench_proto_encode.cpp and bench_proto_decode.cpp moves them to the end of the linker's static-init order. CodSpeed's callgrind runner has been segfaulting immediately after measuring the last existing decode benchmark (Decode_SwitchCommandRequest), and isolating the new code into its own translation unit lets us see whether the crash is triggered by one of the new benchmarks or by something about the new USE_*_PROXY/USE_INFRARED/USE_RADIO_FREQUENCY defines changing how api_pb2.cpp compiles.
114 lines
3.4 KiB
C++
114 lines
3.4 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 an APIBuffer for reuse in decode benchmarks.
|
|
// Optimization barriers are applied to the decode target objects via
|
|
// DoNotOptimize/ClobberMemory, not to this buffer.
|
|
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;
|
|
}
|
|
|
|
/// Force a pointer through an asm barrier so the compiler cannot
|
|
/// prove its contents are unchanged across iterations.
|
|
/// benchmark::DoNotOptimize/ClobberMemory are insufficient under
|
|
/// CodSpeed's valgrind-based instrumentation.
|
|
static void escape(void *p) { asm volatile("" : : "g"(p) : "memory"); }
|
|
|
|
// --- 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);
|
|
auto *data = encoded.data();
|
|
auto size = encoded.size();
|
|
benchmark::DoNotOptimize(data);
|
|
benchmark::DoNotOptimize(size);
|
|
|
|
for (auto _ : state) {
|
|
for (int i = 0; i < kInnerIterations; i++) {
|
|
HelloRequest msg;
|
|
escape(&msg);
|
|
msg.decode(data, size);
|
|
escape(&msg);
|
|
}
|
|
}
|
|
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);
|
|
auto *data = encoded.data();
|
|
auto size = encoded.size();
|
|
benchmark::DoNotOptimize(data);
|
|
benchmark::DoNotOptimize(size);
|
|
|
|
for (auto _ : state) {
|
|
for (int i = 0; i < kInnerIterations; i++) {
|
|
SwitchCommandRequest msg;
|
|
escape(&msg);
|
|
msg.decode(data, size);
|
|
escape(&msg);
|
|
}
|
|
}
|
|
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);
|
|
auto *data = encoded.data();
|
|
auto size = encoded.size();
|
|
benchmark::DoNotOptimize(data);
|
|
benchmark::DoNotOptimize(size);
|
|
|
|
for (auto _ : state) {
|
|
for (int i = 0; i < kInnerIterations; i++) {
|
|
LightCommandRequest msg;
|
|
escape(&msg);
|
|
msg.decode(data, size);
|
|
escape(&msg);
|
|
}
|
|
}
|
|
state.SetItemsProcessed(state.iterations() * kInnerIterations);
|
|
}
|
|
BENCHMARK(Decode_LightCommandRequest);
|
|
|
|
} // namespace esphome::api::benchmarks
|