mirror of
https://github.com/esphome/esphome.git
synced 2026-05-10 05:37:55 +08:00
[benchmark] Add BLE raw advertisement proto encode benchmarks (#15289)
This commit is contained in:
@@ -21,6 +21,10 @@ BENCHMARKS_DIR: Path = Path(root_path) / "tests" / "benchmarks" / "components"
|
||||
# Path to /tests/benchmarks/core (always included, not a component)
|
||||
CORE_BENCHMARKS_DIR: Path = Path(root_path) / "tests" / "benchmarks" / "core"
|
||||
|
||||
# Stub headers for ESP32-only components (e.g. bluetooth_proxy) that
|
||||
# allow benchmarks to compile on the host platform.
|
||||
STUBS_DIR: Path = Path(root_path) / "tests" / "benchmarks" / "stubs"
|
||||
|
||||
PLATFORMIO_OPTIONS = {
|
||||
"build_unflags": [
|
||||
"-Os", # remove default size-opt
|
||||
@@ -29,6 +33,7 @@ PLATFORMIO_OPTIONS = {
|
||||
"-O2", # optimize for speed (CodSpeed recommends RelWithDebInfo)
|
||||
"-g", # debug symbols for profiling
|
||||
"-DUSE_BENCHMARK", # disable WarnIfComponentBlockingGuard in finish()
|
||||
f"-I{STUBS_DIR}", # stub headers for ESP32-only components
|
||||
],
|
||||
# Use deep+ LDF mode to ensure PlatformIO detects the benchmark
|
||||
# library dependency from nested includes.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import esphome.codegen as cg
|
||||
from tests.testing_helpers import ComponentManifestOverride
|
||||
|
||||
|
||||
@@ -5,3 +6,16 @@ def override_manifest(manifest: ComponentManifestOverride) -> None:
|
||||
# api must run its to_code to define USE_API, USE_API_PLAINTEXT,
|
||||
# and add the noise-c library dependency.
|
||||
manifest.enable_codegen()
|
||||
|
||||
original_to_code = manifest.to_code
|
||||
|
||||
async def to_code(config):
|
||||
await original_to_code(config)
|
||||
# Enable BLE proto message types for benchmarks. The real
|
||||
# bluetooth_proxy component is ESP32-only; a lightweight stub
|
||||
# header in tests/benchmarks/stubs/ satisfies the include.
|
||||
cg.add_define("USE_BLUETOOTH_PROXY")
|
||||
cg.add_define("BLUETOOTH_PROXY_MAX_CONNECTIONS", 3)
|
||||
cg.add_define("BLUETOOTH_PROXY_ADVERTISEMENT_BATCH_SIZE", 16)
|
||||
|
||||
manifest.to_code = to_code
|
||||
|
||||
@@ -295,4 +295,93 @@ static void CalcAndEncode_DeviceInfoResponse_Fresh(benchmark::State &state) {
|
||||
}
|
||||
BENCHMARK(CalcAndEncode_DeviceInfoResponse_Fresh);
|
||||
|
||||
// --- BluetoothLERawAdvertisementsResponse (12 adverts, highest-volume BLE message) ---
|
||||
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
|
||||
static BluetoothLERawAdvertisementsResponse make_ble_raw_advs_12() {
|
||||
static const uint8_t fake_adv_data[] = {
|
||||
0x02, 0x01, 0x06, 0x03, 0x03, 0x9F, 0xFE, 0x17, 0x16, 0x9F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
BluetoothLERawAdvertisementsResponse msg;
|
||||
msg.advertisements_len = 12;
|
||||
for (int i = 0; i < 12; i++) {
|
||||
auto &adv = msg.advertisements[i];
|
||||
adv.address = 0xAABBCCDD0000ULL + i;
|
||||
adv.rssi = -60 - i;
|
||||
adv.address_type = 1;
|
||||
memcpy(adv.data, fake_adv_data, sizeof(fake_adv_data));
|
||||
adv.data_len = sizeof(fake_adv_data);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
static void CalculateSize_BLERawAdvs12(benchmark::State &state) {
|
||||
auto msg = make_ble_raw_advs_12();
|
||||
|
||||
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_BLERawAdvs12);
|
||||
|
||||
static void Encode_BLERawAdvs12(benchmark::State &state) {
|
||||
auto msg = make_ble_raw_advs_12();
|
||||
APIBuffer buffer;
|
||||
uint32_t total_size = msg.calculate_size();
|
||||
buffer.resize(total_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_BLERawAdvs12);
|
||||
|
||||
static void CalcAndEncode_BLERawAdvs12(benchmark::State &state) {
|
||||
auto msg = make_ble_raw_advs_12();
|
||||
APIBuffer buffer;
|
||||
|
||||
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_BLERawAdvs12);
|
||||
|
||||
static void CalcAndEncode_BLERawAdvs12_Fresh(benchmark::State &state) {
|
||||
auto msg = make_ble_raw_advs_12();
|
||||
|
||||
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_BLERawAdvs12_Fresh);
|
||||
|
||||
#endif // USE_BLUETOOTH_PROXY
|
||||
|
||||
} // namespace esphome::api::benchmarks
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// Stub for benchmark builds — provides the minimal interface that
|
||||
// api_connection.cpp needs when USE_BLUETOOTH_PROXY is defined,
|
||||
// without pulling in ESP32 BLE dependencies.
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/api/api_pb2.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
class APIConnection;
|
||||
} // namespace api
|
||||
|
||||
namespace bluetooth_proxy {
|
||||
|
||||
class BluetoothProxy {
|
||||
public:
|
||||
api::APIConnection *get_api_connection() const { return nullptr; }
|
||||
void subscribe_api_connection(api::APIConnection *conn, uint32_t flags) {}
|
||||
void unsubscribe_api_connection(api::APIConnection *conn) {}
|
||||
void bluetooth_device_request(const api::BluetoothDeviceRequest &msg) {}
|
||||
void bluetooth_gatt_read(const api::BluetoothGATTReadRequest &msg) {}
|
||||
void bluetooth_gatt_write(const api::BluetoothGATTWriteRequest &msg) {}
|
||||
void bluetooth_gatt_read_descriptor(const api::BluetoothGATTReadDescriptorRequest &msg) {}
|
||||
void bluetooth_gatt_write_descriptor(const api::BluetoothGATTWriteDescriptorRequest &msg) {}
|
||||
void bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg) {}
|
||||
void bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg) {}
|
||||
void send_connections_free(api::APIConnection *conn) {}
|
||||
void bluetooth_scanner_set_mode(bool active) {}
|
||||
void bluetooth_set_connection_params(const api::BluetoothSetConnectionParamsRequest &msg) {}
|
||||
uint32_t get_feature_flags() const { return 0; }
|
||||
void get_bluetooth_mac_address_pretty(char *buf) const { buf[0] = '\0'; }
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
extern BluetoothProxy *global_bluetooth_proxy;
|
||||
|
||||
} // namespace bluetooth_proxy
|
||||
} // namespace esphome
|
||||
Reference in New Issue
Block a user