From 10c1566c6ce2914a2f217d4e857f96cf2a1a070b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D1=83=D1=80=D1=83=D0=BF=D0=BE=D0=B2=20=D0=98=D0=BB?= =?UTF-8?q?=D1=8C=D1=8F=20=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B8=D1=87?= Date: Thu, 14 May 2026 20:37:09 +0300 Subject: [PATCH] tmp --- Containers/CMakeLists.txt | 4 + Containers/tests/benchLinearRingBuffer.cpp | 214 ++++----------------- Externals/CMakeLists.txt | 1 + tools/gen_bench_image.py | 53 +++++ 4 files changed, 96 insertions(+), 176 deletions(-) create mode 100644 tools/gen_bench_image.py diff --git a/Containers/CMakeLists.txt b/Containers/CMakeLists.txt index 146ae01..dcdcff9 100644 --- a/Containers/CMakeLists.txt +++ b/Containers/CMakeLists.txt @@ -32,5 +32,9 @@ target_link_libraries(testLinearRingBuffer ${PROJECT_NAME} gtest) gtest_discover_tests(testLinearRingBuffer) +add_executable(benchLinearRingBuffer ./tests/benchLinearRingBuffer.cpp) +target_link_libraries(benchLinearRingBuffer benchmark::benchmark benchmark::benchmark_main ${PROJECT_NAME}) +# target_compile_features(benchLinearRingBuffer PRIVATE cxx_std_20) + add_executable(AVLTreeSpeedTest ./tests/AVLTreeProfiling.cpp) target_link_libraries(AVLTreeSpeedTest ${PROJECT_NAME}) diff --git a/Containers/tests/benchLinearRingBuffer.cpp b/Containers/tests/benchLinearRingBuffer.cpp index a9293f3..1c6fa43 100644 --- a/Containers/tests/benchLinearRingBuffer.cpp +++ b/Containers/tests/benchLinearRingBuffer.cpp @@ -1,188 +1,50 @@ -#include "LinearRingBuffer.hpp" +#include +#include +#include -#include - -#include -#include -#include - -static void fill(void* ptr, size_t n, uint8_t value) { std::memset(ptr, value, n); } - -static bool check(const void* ptr, size_t n, uint8_t value) { - const uint8_t* p = static_cast(ptr); - for (size_t i = 0; i < n; ++i) { - if (p[i] != value) return false; - } - return true; -} - -static bool expect_mem_eq(const void* ptr, size_t n, uint8_t value) { - const uint8_t* p = static_cast(ptr); - for (size_t i = 0; i < n; ++i) { - if (p[i] != value) return false; - } - return true; -} - -using Data = std::vector; -using DataStorage = std::vector; - -typedef ::testing::Types< - std::integral_constant, - std::integral_constant, - std::integral_constant, - std::integral_constant, - std::integral_constant> - BufferSizes; - -template -class LinearRingBufferTest : public ::testing::Test { -protected: - LinearRingBuffer rb; - - LinearRingBufferTest() : - historySize_(10), - rb(size_t(TypeParam::value), size_t(historySize_)) {} - - static constexpr auto ITERATIONS = TypeParam::value * 10; - - size_t messagesPushed_ = 0; - size_t historySize_ = 0; - - auto iterations() { return ITERATIONS; } - - auto historySize() { return historySize_; } - - size_t randomSize() { - static std::random_device rnd; - std::uniform_int_distribution dist(0, 1000); - return dist(rnd); - } - - auto write_and_advance(size_t messageSize, DataStorage* storage) { - Data pushedSample(messageSize); - - for (auto idx = 0; idx < messageSize; idx++) { - pushedSample[idx] = (idx + messagesPushed_++ * 53) % 321; +// ------------------------------------------------------------- +// Benchmark: push_back into a vector +// ------------------------------------------------------------- +static void BM_VectorPushBack(benchmark::State& state) { + for (auto _ : state) { + std::vector v; + v.reserve(state.range(0)); + for (int i = 0; i < state.range(0); i++) { + v.push_back(i); } + benchmark::DoNotOptimize(v); + } +} - std::memcpy(this->rb.write_data(), pushedSample.data(), pushedSample.size()); - this->rb.write_advance(pushedSample.size()); +BENCHMARK(BM_VectorPushBack)->Arg(1000)->Arg(100000); - if (storage) { - storage->push_back(pushedSample); +// ------------------------------------------------------------- +// Benchmark: inserting into std::map +// ------------------------------------------------------------- +static void BM_MapInsert(benchmark::State& state) { + for (auto _ : state) { + std::map m; + for (int i = 0; i < state.range(0); i++) { + m.emplace(i, i); } - }; - - auto read_and_advance(size_t messageSize, DataStorage* storage) { - Data poppedSample(messageSize); - - std::memcpy(poppedSample.data(), this->rb.read_data(), poppedSample.size()); - - this->rb.read_advance(poppedSample.size()); - - if (storage) { - storage->push_back(poppedSample); - } - }; - - auto reset_with_history() { this->rb.read_reset_with_history(); }; - - auto read_with_history(size_t messageSize, DataStorage* storage) { - Data poppedSample(messageSize); - - std::memcpy(poppedSample.data(), this->rb.read_data(), poppedSample.size()); - - if (storage) { - storage->push_back(poppedSample); - } - }; -}; - -TYPED_TEST_SUITE(LinearRingBufferTest, BufferSizes); - -TYPED_TEST(LinearRingBufferTest, LinearWriteAcrossBoundary) { - constexpr size_t N = TypeParam::value; - - if (N % 4096 != 0) { - return; - } - - auto* base = this->rb.write_data(); - - size_t half = N - 16; - fill(base, half, 0xAA); - fill(base + half, 32, 0xBB); - - EXPECT_EQ(expect_mem_eq(base, 16, 0xBB), true); - EXPECT_EQ(expect_mem_eq(base + 16, half - 16, 0xAA), true); - EXPECT_EQ(expect_mem_eq(base + half, 32, 0xBB), true); -} - -TYPED_TEST(LinearRingBufferTest, Chase) { - - DataStorage pushed; - DataStorage popped; - - static constexpr auto MSG_SIZE = 31; - - for (auto iteration = 0; iteration < this->iterations(); iteration++) { - this->write_and_advance(MSG_SIZE, &pushed); - this->read_and_advance(MSG_SIZE, &popped); - } - - ASSERT_EQ(pushed.size(), popped.size()); - - for (auto idx = 0; idx < popped.size(); idx++) { - ASSERT_EQ(pushed[idx], popped[idx]); + benchmark::DoNotOptimize(m); } } +BENCHMARK(BM_MapInsert)->Arg(1000)->Arg(100000); -Data makeMessageWithHistory(const Data& prev, const Data& current, size_t historySize) { - if (historySize > prev.size()) historySize = prev.size(); +// ------------------------------------------------------------- +// Benchmark: lookup in std::map +// ------------------------------------------------------------- +static void BM_MapLookup(benchmark::State& state) { + std::map m; + for (int i = 0; i < state.range(0); i++) + m.emplace(i, i); - std::vector result; - - result.reserve(historySize + current.size()); - - result.insert(result.end(), prev.end() - historySize, prev.end()); - result.insert(result.end(), current.begin(), current.end()); - - return result; -} - -TYPED_TEST(LinearRingBufferTest, History) { - - DataStorage pushed; - DataStorage popped; - - pushed.push_back(Data(this->historySize())); - - static constexpr auto MAX_MSG_SIZE = 111; - - for (auto iteration = 0; iteration < this->iterations(); iteration++) { - - const auto MSG_SIZE = this->historySize() + this->randomSize() % MAX_MSG_SIZE; - - auto prevPushed = pushed.back(); - pushed.clear(); - - this->reset_with_history(); - - this->write_and_advance(MSG_SIZE, &pushed); - auto currentPushed = pushed.back(); - - this->read_with_history(this->historySize() + MSG_SIZE, &popped); - auto poppedWithHistory = popped.back(); - popped.clear(); - - auto correctResult = makeMessageWithHistory(prevPushed, currentPushed, this->historySize()); - - ASSERT_EQ(correctResult, poppedWithHistory); + for (auto _ : state) { + auto it = m.find(state.range(0) / 2); + benchmark::DoNotOptimize(it); } } +BENCHMARK(BM_MapLookup)->Arg(1000)->Arg(100000); -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} +BENCHMARK_MAIN(); diff --git a/Externals/CMakeLists.txt b/Externals/CMakeLists.txt index ec85993..3cf7daa 100644 --- a/Externals/CMakeLists.txt +++ b/Externals/CMakeLists.txt @@ -56,3 +56,4 @@ target_include_directories(${PROJECT_NAME} INTERFACE ./imageIO/) add_subdirectory(lalr) add_subdirectory(googletest) +add_subdirectory(benchmark) diff --git a/tools/gen_bench_image.py b/tools/gen_bench_image.py new file mode 100644 index 0000000..cd82078 --- /dev/null +++ b/tools/gen_bench_image.py @@ -0,0 +1,53 @@ +import json +import sys +import re +import matplotlib.pyplot as plt + +def load_bench(path): + with open(path, "r") as f: + return json.load(f)["benchmarks"] + +def parse_arg_from_name(name): + # Example: "BM_VectorPushBack/1000" -> 1000 + m = re.search(r"/(\d+)$", name) + return int(m.group(1)) if m else None + +def group_by_prefix(benchmarks): + groups = {} + for b in benchmarks: + name = b["name"] + prefix = name.split("/")[0] # BM_VectorPushBack + arg = parse_arg_from_name(name) # number after slash + if arg is None: + continue + if prefix not in groups: + groups[prefix] = {"x": [], "y": []} + groups[prefix]["x"].append(arg) + groups[prefix]["y"].append(b["real_time"]) + return groups + +def main(): + if len(sys.argv) != 2: + print("Usage: python3 plot_bench.py results.json") + return + + benchmarks = load_bench(sys.argv[1]) + groups = group_by_prefix(benchmarks) + + plt.figure(figsize=(10, 6)) + + for prefix, data in groups.items(): + xs = data["x"] + ys = data["y"] + plt.plot(xs, ys, marker="o", label=prefix) + + plt.xlabel("Input size (Arg)") + plt.ylabel("Real time (ns)") + plt.title("Google Benchmark Results") + plt.grid(True) + plt.legend() + plt.tight_layout() + plt.show() + +if __name__ == "__main__": + main()