From 4f69c3b850ebb7943b1599881f13c0255f078da7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 12 Apr 2026 21:03:53 -1000 Subject: [PATCH] [benchmark] Add SubscribeLogsResponse encode benchmarks (#15696) --- .../components/api/bench_log_response.cpp | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 tests/benchmarks/components/api/bench_log_response.cpp diff --git a/tests/benchmarks/components/api/bench_log_response.cpp b/tests/benchmarks/components/api/bench_log_response.cpp new file mode 100644 index 0000000000..4ef57987be --- /dev/null +++ b/tests/benchmarks/components/api/bench_log_response.cpp @@ -0,0 +1,118 @@ +#include + +#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. +static constexpr int kInnerIterations = 2000; + +// Typical log line: "[12:34:56][D][sensor:094]: 'Temperature': Sending state 23.50000 with 1 decimals of accuracy" +static constexpr const char *kTypicalLogLine = + "[12:34:56][D][sensor:094]: 'Temperature': Sending state 23.50000 with 1 decimals of accuracy"; + +// Short log line: "[12:34:56][I][app:029]: Running..." +static constexpr const char *kShortLogLine = "[12:34:56][I][app:029]: Running..."; + +// --- Encode --- + +static void Encode_LogResponse_Typical(benchmark::State &state) { + APIBuffer buffer; + SubscribeLogsResponse msg; + msg.level = enums::LOG_LEVEL_DEBUG; + msg.set_message(reinterpret_cast(kTypicalLogLine), strlen(kTypicalLogLine)); + uint32_t size = msg.calculate_size(); + buffer.resize(size); + + for (auto _ : state) { + for (int i = 0; i < kInnerIterations; i++) { + ProtoWriteBuffer writer(&buffer, 0); + msg.encode(writer); + } + benchmark::DoNotOptimize(buffer.data()); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(Encode_LogResponse_Typical); + +static void Encode_LogResponse_Short(benchmark::State &state) { + APIBuffer buffer; + SubscribeLogsResponse msg; + msg.level = enums::LOG_LEVEL_INFO; + msg.set_message(reinterpret_cast(kShortLogLine), strlen(kShortLogLine)); + uint32_t size = msg.calculate_size(); + buffer.resize(size); + + for (auto _ : state) { + for (int i = 0; i < kInnerIterations; i++) { + ProtoWriteBuffer writer(&buffer, 0); + msg.encode(writer); + } + benchmark::DoNotOptimize(buffer.data()); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(Encode_LogResponse_Short); + +// --- Calculate Size --- + +static void CalculateSize_LogResponse_Typical(benchmark::State &state) { + SubscribeLogsResponse msg; + msg.level = enums::LOG_LEVEL_DEBUG; + msg.set_message(reinterpret_cast(kTypicalLogLine), strlen(kTypicalLogLine)); + + for (auto _ : state) { + uint32_t result = 0; + for (int i = 0; i < kInnerIterations; i++) { + result += msg.calculate_size(); + } + benchmark::DoNotOptimize(result); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(CalculateSize_LogResponse_Typical); + +// --- Calc + Encode (steady state) --- + +static void CalcAndEncode_LogResponse_Typical(benchmark::State &state) { + APIBuffer buffer; + SubscribeLogsResponse msg; + msg.level = enums::LOG_LEVEL_DEBUG; + msg.set_message(reinterpret_cast(kTypicalLogLine), strlen(kTypicalLogLine)); + + for (auto _ : state) { + for (int i = 0; i < kInnerIterations; i++) { + uint32_t size = msg.calculate_size(); + buffer.resize(size); + ProtoWriteBuffer writer(&buffer, 0); + msg.encode(writer); + } + benchmark::DoNotOptimize(buffer.data()); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(CalcAndEncode_LogResponse_Typical); + +// --- Calc + Encode (fresh allocation each time) --- + +static void CalcAndEncode_LogResponse_Typical_Fresh(benchmark::State &state) { + SubscribeLogsResponse msg; + msg.level = enums::LOG_LEVEL_DEBUG; + msg.set_message(reinterpret_cast(kTypicalLogLine), strlen(kTypicalLogLine)); + + for (auto _ : state) { + for (int i = 0; i < kInnerIterations; i++) { + APIBuffer buffer; + uint32_t size = msg.calculate_size(); + buffer.resize(size); + ProtoWriteBuffer writer(&buffer, 0); + msg.encode(writer); + benchmark::DoNotOptimize(buffer.data()); + } + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(CalcAndEncode_LogResponse_Typical_Fresh); + +} // namespace esphome::api::benchmarks