From c22b2f990e443ca14202de923112b445bcbd45a9 Mon Sep 17 00:00:00 2001 From: "codspeed-hq[bot]" <117304815+codspeed-hq[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 18:57:05 +0000 Subject: [PATCH] Add CodSpeed performance benchmarks --- .github/workflows/codspeed.yml | 48 +++++++ CMakeLists.txt | 5 + Readme.md | 1 + benchmarks/CMakeLists.txt | 31 +++++ benchmarks/bench_data.cpp | 137 ++++++++++++++++++++ benchmarks/bench_messenger.cpp | 222 +++++++++++++++++++++++++++++++++ 6 files changed, 444 insertions(+) create mode 100644 .github/workflows/codspeed.yml create mode 100644 benchmarks/CMakeLists.txt create mode 100644 benchmarks/bench_data.cpp create mode 100644 benchmarks/bench_messenger.cpp diff --git a/.github/workflows/codspeed.yml b/.github/workflows/codspeed.yml new file mode 100644 index 00000000..736cec72 --- /dev/null +++ b/.github/workflows/codspeed.yml @@ -0,0 +1,48 @@ +name: CodSpeed + +on: + push: + branches: + - main + - newdev + pull_request: + workflow_dispatch: + +permissions: + contents: read + id-token: write + +jobs: + benchmarks: + name: Run benchmarks + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Install dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y -qq \ + build-essential cmake git \ + libboost-all-dev libusb-1.0-0-dev libssl-dev \ + libprotobuf-dev protobuf-compiler + + - name: Build benchmarks + run: | + mkdir -p build && cd build + cmake \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DAASDK_TEST=OFF \ + -DAASDK_BENCHMARK=ON \ + -DCODSPEED_MODE=simulation \ + -DSKIP_BUILD_PROTOBUF=ON \ + -DSKIP_BUILD_ABSL=ON \ + .. + make -j$(nproc) aasdk_benchmarks + + - name: Run benchmarks + uses: CodSpeedHQ/action@v4 + with: + mode: simulation + run: ./build/bin/aasdk_benchmarks diff --git a/CMakeLists.txt b/CMakeLists.txt index dab97844..1b1eb749 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ option(SKIP_BUILD_PROTOBUF "Skip building protobuf, use system-installed version option(SKIP_BUILD_ABSL "Skip building Abseil, use system-installed version" OFF) option(AASDK_TEST "Build AASDK unit tests" ON) option(AASDK_CODE_COVERAGE "Enable coverage build options for AASDK tests" OFF) +option(AASDK_BENCHMARK "Build AASDK benchmarks" OFF) # Cross Compiling Architecture and Package Architecture Detection if( TARGET_ARCH STREQUAL "amd64" ) @@ -476,6 +477,10 @@ if(AASDK_TEST) endif(AASDK_CODE_COVERAGE) endif(AASDK_TEST) +if(AASDK_BENCHMARK) + add_subdirectory(benchmarks) +endif(AASDK_BENCHMARK) + # CPack Configuration for DEB packages set(CPACK_GENERATOR "DEB") diff --git a/Readme.md b/Readme.md index 3ae662a9..63e2d883 100644 --- a/Readme.md +++ b/Readme.md @@ -4,6 +4,7 @@ [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](code_of_conduct.md) [![Build Status](https://img.shields.io/badge/build-passing-brightgreen)](BUILD.md) [![Documentation](https://img.shields.io/badge/docs-comprehensive-blue)](DOCUMENTATION.md) +[![CodSpeed](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/opencardev/aasdk?utm_source=badge) ## Overview diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt new file mode 100644 index 00000000..e8bda841 --- /dev/null +++ b/benchmarks/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.16) + +include(FetchContent) + +set(BENCHMARK_DOWNLOAD_DEPENDENCIES ON) + +FetchContent_Declare( + google_benchmark + GIT_REPOSITORY https://github.com/CodSpeedHQ/codspeed-cpp + SOURCE_SUBDIR google_benchmark + GIT_TAG main +) + +FetchContent_MakeAvailable(google_benchmark) + +add_executable(aasdk_benchmarks + bench_messenger.cpp + bench_data.cpp +) + +target_link_libraries(aasdk_benchmarks + PRIVATE + benchmark::benchmark + aasdk +) + +target_include_directories(aasdk_benchmarks + PRIVATE + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_BINARY_DIR}/include +) diff --git a/benchmarks/bench_data.cpp b/benchmarks/bench_data.cpp new file mode 100644 index 00000000..5ea8607c --- /dev/null +++ b/benchmarks/bench_data.cpp @@ -0,0 +1,137 @@ +#include +#include + +#include + +using namespace aasdk::common; + +// -- DataConstBuffer construction benchmarks -- + +static void BM_DataConstBufferFromVector(benchmark::State &state) { + Data data(state.range(0), 0x42); + + for (auto _ : state) { + DataConstBuffer buffer(data); + benchmark::DoNotOptimize(buffer.cdata); + benchmark::DoNotOptimize(buffer.size); + } +} +BENCHMARK(BM_DataConstBufferFromVector)->Range(64, 65536); + +static void BM_DataConstBufferWithOffset(benchmark::State &state) { + Data data(4096, 0x42); + + for (auto _ : state) { + DataConstBuffer buffer(data, 128); + benchmark::DoNotOptimize(buffer.cdata); + benchmark::DoNotOptimize(buffer.size); + } +} +BENCHMARK(BM_DataConstBufferWithOffset); + +// -- Data copy benchmarks -- + +static void BM_DataCopySmall(benchmark::State &state) { + Data source(64, 0xAB); + DataConstBuffer buffer(source); + + for (auto _ : state) { + Data dest; + copy(dest, buffer); + benchmark::DoNotOptimize(dest); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_DataCopySmall); + +static void BM_DataCopy(benchmark::State &state) { + Data source(state.range(0), 0xAB); + DataConstBuffer buffer(source); + + for (auto _ : state) { + Data dest; + copy(dest, buffer); + benchmark::DoNotOptimize(dest); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_DataCopy)->Range(256, 1 << 20); + +static void BM_DataCopyAppend(benchmark::State &state) { + Data source(1024, 0xCD); + DataConstBuffer buffer(source); + + for (auto _ : state) { + Data dest; + dest.reserve(4096); + for (int i = 0; i < 4; ++i) { + copy(dest, buffer); + } + benchmark::DoNotOptimize(dest); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_DataCopyAppend); + +// -- createData benchmark -- + +static void BM_CreateData(benchmark::State &state) { + Data source(state.range(0), 0xEF); + DataConstBuffer buffer(source); + + for (auto _ : state) { + Data result = createData(buffer); + benchmark::DoNotOptimize(result); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_CreateData)->Range(64, 65536); + +// -- Data dump (hex encoding) benchmarks -- + +static void BM_DataDump(benchmark::State &state) { + Data data(state.range(0), 0xAB); + + for (auto _ : state) { + std::string result = dump(data); + benchmark::DoNotOptimize(result); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_DataDump)->Range(16, 4096); + +static void BM_DataDumpBuffer(benchmark::State &state) { + Data data(state.range(0), 0xCD); + DataConstBuffer buffer(data); + + for (auto _ : state) { + std::string result = dump(buffer); + benchmark::DoNotOptimize(result); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_DataDumpBuffer)->Range(16, 4096); + +// -- DataBuffer equality benchmarks -- + +static void BM_DataConstBufferEquality(benchmark::State &state) { + Data data(1024, 0x42); + DataConstBuffer buf1(data); + DataConstBuffer buf2(data); + + for (auto _ : state) { + bool result = (buf1 == buf2); + benchmark::DoNotOptimize(result); + } +} +BENCHMARK(BM_DataConstBufferEquality); + +static void BM_DataConstBufferNullCheck(benchmark::State &state) { + DataConstBuffer buffer; + + for (auto _ : state) { + bool result = (buffer == nullptr); + benchmark::DoNotOptimize(result); + } +} +BENCHMARK(BM_DataConstBufferNullCheck); diff --git a/benchmarks/bench_messenger.cpp b/benchmarks/bench_messenger.cpp new file mode 100644 index 00000000..d22b6a4d --- /dev/null +++ b/benchmarks/bench_messenger.cpp @@ -0,0 +1,222 @@ +#include +#include + +#include +#include +#include +#include +#include + +using namespace aasdk::messenger; +using namespace aasdk::common; + +// -- FrameHeader benchmarks -- + +static void BM_FrameHeaderParse(benchmark::State &state) { + // Simulate a raw 2-byte frame header: channel=CONTROL, type=BULK|PLAIN|SPECIFIC + uint8_t raw[2] = { + static_cast(ChannelId::CONTROL), + static_cast(FrameType::BULK) | + static_cast(EncryptionType::PLAIN) | + static_cast(MessageType::SPECIFIC)}; + DataConstBuffer buffer(raw, sizeof(raw)); + + for (auto _ : state) { + FrameHeader header(buffer); + benchmark::DoNotOptimize(header); + } +} +BENCHMARK(BM_FrameHeaderParse); + +static void BM_FrameHeaderSerialize(benchmark::State &state) { + FrameHeader header(ChannelId::MEDIA_SINK_VIDEO, FrameType::FIRST, + EncryptionType::ENCRYPTED, MessageType::CONTROL); + + for (auto _ : state) { + Data data = header.getData(); + benchmark::DoNotOptimize(data); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_FrameHeaderSerialize); + +static void BM_FrameHeaderRoundtrip(benchmark::State &state) { + for (auto _ : state) { + FrameHeader original(ChannelId::SENSOR, FrameType::BULK, + EncryptionType::PLAIN, MessageType::SPECIFIC); + Data serialized = original.getData(); + DataConstBuffer buf(serialized); + FrameHeader parsed(buf); + benchmark::DoNotOptimize(parsed); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_FrameHeaderRoundtrip); + +// -- FrameSize benchmarks -- + +static void BM_FrameSizeParseShort(benchmark::State &state) { + // 2-byte short frame size (big-endian 1024) + uint8_t raw[2] = {0x04, 0x00}; + DataConstBuffer buffer(raw, sizeof(raw)); + + for (auto _ : state) { + FrameSize fs(buffer); + benchmark::DoNotOptimize(fs); + } +} +BENCHMARK(BM_FrameSizeParseShort); + +static void BM_FrameSizeParseExtended(benchmark::State &state) { + // 6-byte extended frame size: 2-byte frame size + 4-byte total size + uint8_t raw[6] = {0x04, 0x00, 0x00, 0x01, 0x00, 0x00}; + DataConstBuffer buffer(raw, sizeof(raw)); + + for (auto _ : state) { + FrameSize fs(buffer); + benchmark::DoNotOptimize(fs); + } +} +BENCHMARK(BM_FrameSizeParseExtended); + +static void BM_FrameSizeSerializeShort(benchmark::State &state) { + FrameSize fs(1024); + + for (auto _ : state) { + Data data = fs.getData(); + benchmark::DoNotOptimize(data); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_FrameSizeSerializeShort); + +static void BM_FrameSizeSerializeExtended(benchmark::State &state) { + FrameSize fs(1024, 65536); + + for (auto _ : state) { + Data data = fs.getData(); + benchmark::DoNotOptimize(data); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_FrameSizeSerializeExtended); + +static void BM_FrameSizeRoundtripExtended(benchmark::State &state) { + for (auto _ : state) { + FrameSize original(4096, 131072); + Data serialized = original.getData(); + DataConstBuffer buf(serialized); + FrameSize parsed(buf); + benchmark::DoNotOptimize(parsed.getFrameSize()); + benchmark::DoNotOptimize(parsed.getTotalSize()); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_FrameSizeRoundtripExtended); + +// -- MessageId benchmarks -- + +static void BM_MessageIdEncode(benchmark::State &state) { + MessageId id(0x8001); + + for (auto _ : state) { + Data data = id.getData(); + benchmark::DoNotOptimize(data); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_MessageIdEncode); + +static void BM_MessageIdDecode(benchmark::State &state) { + // Big-endian representation of 0x8001 + Data raw = {0x80, 0x01}; + + for (auto _ : state) { + MessageId id(raw); + benchmark::DoNotOptimize(id.getId()); + } +} +BENCHMARK(BM_MessageIdDecode); + +static void BM_MessageIdRoundtrip(benchmark::State &state) { + for (auto _ : state) { + MessageId original(0x1234); + Data encoded = original.getData(); + MessageId decoded(encoded); + benchmark::DoNotOptimize(decoded.getId()); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_MessageIdRoundtrip); + +// -- Message payload benchmarks -- + +static void BM_MessageInsertPayloadSmall(benchmark::State &state) { + Data payload(64, 0xAB); + + for (auto _ : state) { + Message msg(ChannelId::CONTROL, EncryptionType::PLAIN, + MessageType::SPECIFIC); + msg.insertPayload(payload); + benchmark::DoNotOptimize(msg.getPayload()); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_MessageInsertPayloadSmall); + +static void BM_MessageInsertPayloadMedium(benchmark::State &state) { + Data payload(4096, 0xCD); + + for (auto _ : state) { + Message msg(ChannelId::MEDIA_SINK_VIDEO, EncryptionType::ENCRYPTED, + MessageType::SPECIFIC); + msg.insertPayload(payload); + benchmark::DoNotOptimize(msg.getPayload()); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_MessageInsertPayloadMedium); + +static void BM_MessageInsertPayloadLarge(benchmark::State &state) { + Data payload(65536, 0xEF); + + for (auto _ : state) { + Message msg(ChannelId::MEDIA_SINK_VIDEO, EncryptionType::ENCRYPTED, + MessageType::SPECIFIC); + msg.insertPayload(payload); + benchmark::DoNotOptimize(msg.getPayload()); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_MessageInsertPayloadLarge); + +static void BM_MessageInsertPayloadBuffer(benchmark::State &state) { + Data raw(4096, 0xAA); + DataConstBuffer buffer(raw); + + for (auto _ : state) { + Message msg(ChannelId::CONTROL, EncryptionType::PLAIN, + MessageType::SPECIFIC); + msg.insertPayload(buffer); + benchmark::DoNotOptimize(msg.getPayload()); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_MessageInsertPayloadBuffer); + +static void BM_MessageInsertMultiplePayloads(benchmark::State &state) { + Data chunk(512, 0xBB); + + for (auto _ : state) { + Message msg(ChannelId::MEDIA_SINK_MEDIA_AUDIO, EncryptionType::PLAIN, + MessageType::SPECIFIC); + for (int i = 0; i < 8; ++i) { + msg.insertPayload(chunk); + } + benchmark::DoNotOptimize(msg.getPayload()); + benchmark::ClobberMemory(); + } +} +BENCHMARK(BM_MessageInsertMultiplePayloads); + +BENCHMARK_MAIN();