diff --git a/tests/benchmarks/core/bench_helpers.cpp b/tests/benchmarks/core/bench_helpers.cpp index c6e1e6930e..d9a9d158a3 100644 --- a/tests/benchmarks/core/bench_helpers.cpp +++ b/tests/benchmarks/core/bench_helpers.cpp @@ -10,7 +10,6 @@ namespace esphome::benchmarks { static constexpr int kInnerIterations = 2000; // --- random_float() --- -// Ported from ol.yaml:148 "Random Float Benchmark" static void RandomFloat(benchmark::State &state) { for (auto _ : state) { @@ -38,4 +37,274 @@ static void RandomUint32(benchmark::State &state) { } BENCHMARK(RandomUint32); +// --- format_hex_to() - 6 bytes (MAC address sized) --- + +static void FormatHexTo_6Bytes(benchmark::State &state) { + const uint8_t data[] = {0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45}; + char buffer[13]; // 6 * 2 + 1 + for (auto _ : state) { + for (int i = 0; i < kInnerIterations; i++) { + format_hex_to(buffer, data, 6); + } + benchmark::DoNotOptimize(buffer); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(FormatHexTo_6Bytes); + +// --- format_hex_to() - 16 bytes (UUID sized) --- + +static void FormatHexTo_16Bytes(benchmark::State &state) { + const uint8_t data[] = {0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}; + char buffer[33]; // 16 * 2 + 1 + for (auto _ : state) { + for (int i = 0; i < kInnerIterations; i++) { + format_hex_to(buffer, data, 16); + } + benchmark::DoNotOptimize(buffer); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(FormatHexTo_16Bytes); + +// --- format_hex_to() - 100 bytes (large payload) --- + +static void FormatHexTo_100Bytes(benchmark::State &state) { + uint8_t data[100]; + for (int i = 0; i < 100; i++) { + data[i] = static_cast(i); + } + char buffer[201]; // 100 * 2 + 1 + for (auto _ : state) { + for (int i = 0; i < kInnerIterations; i++) { + format_hex_to(buffer, data, 100); + } + benchmark::DoNotOptimize(buffer); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(FormatHexTo_100Bytes); + +// --- format_hex_pretty_to() - 6 bytes with ':' separator --- + +static void FormatHexPrettyTo_6Bytes(benchmark::State &state) { + const uint8_t data[] = {0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45}; + char buffer[18]; // 6 * 3 + for (auto _ : state) { + for (int i = 0; i < kInnerIterations; i++) { + format_hex_pretty_to(buffer, data, 6); + } + benchmark::DoNotOptimize(buffer); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(FormatHexPrettyTo_6Bytes); + +// --- format_mac_addr_upper() --- + +static void FormatMacAddrUpper(benchmark::State &state) { + const uint8_t mac[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; + char buffer[MAC_ADDRESS_PRETTY_BUFFER_SIZE]; + for (auto _ : state) { + for (int i = 0; i < kInnerIterations; i++) { + format_mac_addr_upper(mac, buffer); + } + benchmark::DoNotOptimize(buffer); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(FormatMacAddrUpper); + +// --- fnv1_hash() - short string --- + +static void Fnv1Hash_Short(benchmark::State &state) { + const char *str = "sensor.temperature"; + for (auto _ : state) { + uint32_t result = 0; + for (int i = 0; i < kInnerIterations; i++) { + result ^= fnv1_hash(str); + } + benchmark::DoNotOptimize(result); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(Fnv1Hash_Short); + +// --- fnv1_hash() - long string --- + +static void Fnv1Hash_Long(benchmark::State &state) { + const char *str = "binary_sensor.living_room_motion_sensor_occupancy_detected"; + for (auto _ : state) { + uint32_t result = 0; + for (int i = 0; i < kInnerIterations; i++) { + result ^= fnv1_hash(str); + } + benchmark::DoNotOptimize(result); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(Fnv1Hash_Long); + +// --- fnv1a_hash() - short string --- +// Use DoNotOptimize on the input pointer to prevent constexpr evaluation + +static void Fnv1aHash_Short(benchmark::State &state) { + const char *str = "sensor.temperature"; + benchmark::DoNotOptimize(str); + for (auto _ : state) { + uint32_t result = 0; + for (int i = 0; i < kInnerIterations; i++) { + result ^= fnv1a_hash(str); + benchmark::ClobberMemory(); + } + benchmark::DoNotOptimize(result); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(Fnv1aHash_Short); + +// --- fnv1a_hash() - long string --- + +static void Fnv1aHash_Long(benchmark::State &state) { + const char *str = "binary_sensor.living_room_motion_sensor_occupancy_detected"; + benchmark::DoNotOptimize(str); + for (auto _ : state) { + uint32_t result = 0; + for (int i = 0; i < kInnerIterations; i++) { + result ^= fnv1a_hash(str); + benchmark::ClobberMemory(); + } + benchmark::DoNotOptimize(result); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(Fnv1aHash_Long); + +// --- fnv1_hash_object_id() - typical entity name --- + +static void Fnv1HashObjectId(benchmark::State &state) { + char name[] = "Living Room Temperature Sensor"; + size_t len = sizeof(name) - 1; + benchmark::DoNotOptimize(name); + for (auto _ : state) { + uint32_t result = 0; + for (int i = 0; i < kInnerIterations; i++) { + result ^= fnv1_hash_object_id(name, len); + benchmark::ClobberMemory(); + } + benchmark::DoNotOptimize(result); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(Fnv1HashObjectId); + +// --- parse_hex() - 6 bytes from string --- + +static void ParseHex_6Bytes(benchmark::State &state) { + const char *hex_str = "ABCDEF012345"; + uint8_t data[6]; + for (auto _ : state) { + for (int i = 0; i < kInnerIterations; i++) { + parse_hex(hex_str, data, 6); + } + benchmark::DoNotOptimize(data); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(ParseHex_6Bytes); + +// --- parse_hex() - 16 bytes from string --- + +static void ParseHex_16Bytes(benchmark::State &state) { + const char *hex_str = "ABCDEF0123456789FEDCBA9876543210"; + uint8_t data[16]; + for (auto _ : state) { + for (int i = 0; i < kInnerIterations; i++) { + parse_hex(hex_str, data, 16); + } + benchmark::DoNotOptimize(data); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(ParseHex_16Bytes); + +// --- crc8() - 8 bytes --- + +static void CRC8_8Bytes(benchmark::State &state) { + const uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + for (auto _ : state) { + uint8_t result = 0; + for (int i = 0; i < kInnerIterations; i++) { + result ^= crc8(data, 8); + } + benchmark::DoNotOptimize(result); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(CRC8_8Bytes); + +// --- crc16() - 8 bytes --- + +static void CRC16_8Bytes(benchmark::State &state) { + const uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + for (auto _ : state) { + uint16_t result = 0; + for (int i = 0; i < kInnerIterations; i++) { + result ^= crc16(data, 8); + } + benchmark::DoNotOptimize(result); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(CRC16_8Bytes); + +// --- value_accuracy_to_buf() - typical sensor value --- + +static void ValueAccuracyToBuf(benchmark::State &state) { + char raw_buf[VALUE_ACCURACY_MAX_LEN] = {}; + std::span buf(raw_buf); + float value = 23.456f; + for (auto _ : state) { + for (int i = 0; i < kInnerIterations; i++) { + value_accuracy_to_buf(buf, value, 2); + } + benchmark::DoNotOptimize(raw_buf); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(ValueAccuracyToBuf); + +// --- int8_to_str() --- + +static void Int8ToStr(benchmark::State &state) { + char buffer[5] = {}; + for (auto _ : state) { + for (int i = 0; i < kInnerIterations; i++) { + int8_to_str(buffer, static_cast(i & 0xFF)); + benchmark::DoNotOptimize(buffer); + benchmark::ClobberMemory(); + } + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(Int8ToStr); + +// --- base64_decode() - into pre-allocated buffer --- + +static void Base64Decode_32Bytes(benchmark::State &state) { + // 32 bytes encoded = 44 base64 chars + const uint8_t encoded[] = "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGx0eHw=="; + size_t encoded_len = 44; + uint8_t output[32]; + for (auto _ : state) { + for (int i = 0; i < kInnerIterations; i++) { + base64_decode(encoded, encoded_len, output, sizeof(output)); + } + benchmark::DoNotOptimize(output); + } + state.SetItemsProcessed(state.iterations() * kInnerIterations); +} +BENCHMARK(Base64Decode_32Bytes); + } // namespace esphome::benchmarks