#include #include #include #include #include #include "reference.hpp" namespace { struct TestObject { int64_t data = 42; TestObject() = default; explicit TestObject(int64_t value) : data(value) {} }; // Trait helpers for templated benchmarks template struct PointerTraits; template struct PointerTraits> { using pointer_type = std::shared_ptr; using weak_type = std::weak_ptr; template static pointer_type make(Args &&...args) { return std::make_shared(std::forward(args)...); } static const char *name() { return "std::shared_ptr"; } static const char *weak_name() { return "std::weak_ptr"; } }; template struct PointerTraits> { using pointer_type = Ref; using weak_type = WeakRef; template static pointer_type make(Args &&...args) { return make_ref(std::forward(args)...); } static const char *name() { return "Ref"; } static const char *weak_name() { return "WeakRef"; } }; // Force multi-threaded mode to defeat __libc_single_threaded optimization void force_multithreaded() { std::thread t([]() {}); t.join(); } template void benchmark_creation(ankerl::nanobench::Bench &bench) { using Traits = PointerTraits; force_multithreaded(); bench.run(std::string(Traits::name()) + " creation", [&] { auto ptr = Traits::make(TestObject{123}); ankerl::nanobench::doNotOptimizeAway(ptr); }); } template void benchmark_copy(ankerl::nanobench::Bench &bench) { using Traits = PointerTraits; force_multithreaded(); auto original = Traits::make(TestObject{123}); bench.run(std::string(Traits::name()) + " copy", [&] { auto copy = original; ankerl::nanobench::doNotOptimizeAway(copy); }); } template void benchmark_move(ankerl::nanobench::Bench &bench) { using Traits = PointerTraits; auto original = Traits::make(TestObject{123}); bench.run(std::string(Traits::name()) + " move", [&] { auto moved = std::move(original); ankerl::nanobench::doNotOptimizeAway(moved); original = std::move(moved); ankerl::nanobench::doNotOptimizeAway(original); }); } template void benchmark_weak_copy(ankerl::nanobench::Bench &bench) { using Traits = PointerTraits; force_multithreaded(); auto strong_ptr = Traits::make(TestObject{123}); typename Traits::weak_type weak_original = strong_ptr; bench.run(std::string(Traits::weak_name()) + " copy", [&] { auto weak_copy = weak_original; ankerl::nanobench::doNotOptimizeAway(weak_copy); }); } template void benchmark_weak_move(ankerl::nanobench::Bench &bench) { using Traits = PointerTraits; auto strong_ptr = Traits::make(TestObject{123}); typename Traits::weak_type weak_original = strong_ptr; bench.run(std::string(Traits::weak_name()) + " move", [&] { auto weak_moved = std::move(weak_original); ankerl::nanobench::doNotOptimizeAway(weak_moved); weak_original = std::move(weak_moved); ankerl::nanobench::doNotOptimizeAway(weak_original); }); } template void benchmark_dereference(ankerl::nanobench::Bench &bench) { using Traits = PointerTraits; auto ptr = Traits::make(TestObject{456}); bench.run(std::string(Traits::name()) + " dereference", [&] { ankerl::nanobench::doNotOptimizeAway(ptr->data); }); } template void benchmark_weak_lock_success(ankerl::nanobench::Bench &bench) { using Traits = PointerTraits; auto strong_ptr = Traits::make(TestObject{789}); typename Traits::weak_type weak_ptr = strong_ptr; bench.run(std::string(Traits::weak_name()) + " lock success", [&] { auto locked = weak_ptr.lock(); ankerl::nanobench::doNotOptimizeAway(locked); }); } template void benchmark_weak_lock_failure(ankerl::nanobench::Bench &bench) { using Traits = PointerTraits; typename Traits::weak_type weak_ptr; { auto strong_ptr = Traits::make(TestObject{999}); weak_ptr = strong_ptr; } bench.run(std::string(Traits::weak_name()) + " lock failure", [&] { auto locked = weak_ptr.lock(); ankerl::nanobench::doNotOptimizeAway(locked); }); } template void benchmark_multithreaded_copy(ankerl::nanobench::Bench &bench, int num_threads) { using Traits = PointerTraits; // Create the shared object outside the benchmark auto ptr = Traits::make(TestObject{456}); // Create background threads that will create contention std::atomic keep_running{true}; std::vector background_threads; for (int i = 0; i < num_threads - 1; ++i) { background_threads.emplace_back([&]() { while (keep_running.load(std::memory_order_relaxed)) { auto copy = ptr; ankerl::nanobench::doNotOptimizeAway(copy); } }); } // Benchmark the foreground thread under contention bench.run(std::string(Traits::name()) + " copy under contention", [&] { auto copy = ptr; ankerl::nanobench::doNotOptimizeAway(copy); }); // Clean up background threads keep_running.store(false, std::memory_order_relaxed); for (auto &t : background_threads) { t.join(); } } template void benchmark_multithreaded_weak_lock(ankerl::nanobench::Bench &bench, int num_threads) { using Traits = PointerTraits; // Create the shared object and weak reference outside the benchmark auto strong_ptr = Traits::make(TestObject{789}); typename Traits::weak_type weak_ptr = strong_ptr; // Create background threads that will create contention std::atomic keep_running{true}; std::vector background_threads; for (int i = 0; i < num_threads - 1; ++i) { background_threads.emplace_back([&]() { while (keep_running.load(std::memory_order_relaxed)) { auto locked = weak_ptr.lock(); ankerl::nanobench::doNotOptimizeAway(locked); } }); } // Benchmark the foreground thread under contention bench.run(std::string(Traits::weak_name()) + " lock under contention", [&] { auto locked = weak_ptr.lock(); ankerl::nanobench::doNotOptimizeAway(locked); }); // Clean up background threads keep_running.store(false, std::memory_order_relaxed); for (auto &t : background_threads) { t.join(); } } template void benchmark_weak_copy_with_strong_contention(ankerl::nanobench::Bench &bench, int num_threads) { using Traits = PointerTraits; // Create the shared object and weak reference outside the benchmark auto strong_ptr = Traits::make(TestObject{456}); typename Traits::weak_type weak_ptr = strong_ptr; // Create background threads copying the strong pointer std::atomic keep_running{true}; std::vector background_threads; for (int i = 0; i < num_threads - 1; ++i) { background_threads.emplace_back([&]() { while (keep_running.load(std::memory_order_relaxed)) { auto copy = strong_ptr; ankerl::nanobench::doNotOptimizeAway(copy); } }); } // Benchmark weak reference copying under strong reference contention bench.run(std::string(Traits::weak_name()) + " copy with strong contention", [&] { auto weak_copy = weak_ptr; ankerl::nanobench::doNotOptimizeAway(weak_copy); }); // Clean up background threads keep_running.store(false, std::memory_order_relaxed); for (auto &t : background_threads) { t.join(); } } template void benchmark_strong_copy_with_weak_contention(ankerl::nanobench::Bench &bench, int num_threads) { using Traits = PointerTraits; // Create the shared object and weak reference outside the benchmark auto strong_ptr = Traits::make(TestObject{789}); typename Traits::weak_type weak_ptr = strong_ptr; // Create background threads copying the weak pointer std::atomic keep_running{true}; std::vector background_threads; for (int i = 0; i < num_threads - 1; ++i) { background_threads.emplace_back([&]() { while (keep_running.load(std::memory_order_relaxed)) { auto weak_copy = weak_ptr; ankerl::nanobench::doNotOptimizeAway(weak_copy); } }); } // Benchmark strong reference copying under weak reference contention bench.run(std::string(Traits::name()) + " copy with weak contention", [&] { auto strong_copy = strong_ptr; ankerl::nanobench::doNotOptimizeAway(strong_copy); }); // Clean up background threads keep_running.store(false, std::memory_order_relaxed); for (auto &t : background_threads) { t.join(); } } } // anonymous namespace TEST_CASE("Creation performance comparison") { ankerl::nanobench::Bench bench; bench.title("Creation performance comparison"); bench.relative(true); benchmark_creation>(bench); benchmark_creation>(bench); } TEST_CASE("Copy performance comparison") { ankerl::nanobench::Bench bench; bench.title("Copy performance comparison"); bench.relative(true); benchmark_copy>(bench); benchmark_copy>(bench); } TEST_CASE("Move performance comparison") { ankerl::nanobench::Bench bench; bench.title("Move performance comparison"); bench.relative(true); benchmark_move>(bench); benchmark_move>(bench); } TEST_CASE("Weak copy performance comparison") { ankerl::nanobench::Bench bench; bench.title("Weak copy performance comparison"); bench.relative(true); benchmark_weak_copy>(bench); benchmark_weak_copy>(bench); } TEST_CASE("Weak move performance comparison") { ankerl::nanobench::Bench bench; bench.title("Weak move performance comparison"); bench.relative(true); benchmark_weak_move>(bench); benchmark_weak_move>(bench); } TEST_CASE("Dereference performance comparison") { ankerl::nanobench::Bench bench; bench.title("Dereference performance comparison"); bench.relative(true); benchmark_dereference>(bench); benchmark_dereference>(bench); } TEST_CASE("Weak lock success performance comparison") { ankerl::nanobench::Bench bench; bench.title("Weak lock success performance comparison"); bench.relative(true); benchmark_weak_lock_success>(bench); benchmark_weak_lock_success>(bench); } TEST_CASE("Weak lock failure performance comparison") { ankerl::nanobench::Bench bench; bench.title("Weak lock failure performance comparison"); bench.relative(true); benchmark_weak_lock_failure>(bench); benchmark_weak_lock_failure>(bench); } TEST_CASE("Copy performance under contention") { const int num_threads = 3; ankerl::nanobench::Bench bench; bench.title("Copy performance under contention"); bench.relative(true); bench.minEpochIterations(500000); benchmark_multithreaded_copy>(bench, num_threads); benchmark_multithreaded_copy>(bench, num_threads); } TEST_CASE("Weak lock performance under contention") { const int num_threads = 3; ankerl::nanobench::Bench bench; bench.title("Weak lock performance under contention"); bench.relative(true); bench.minEpochIterations(500000); benchmark_multithreaded_weak_lock>(bench, num_threads); benchmark_multithreaded_weak_lock>(bench, num_threads); } TEST_CASE("Weak copy performance under strong reference contention") { const int num_threads = 3; ankerl::nanobench::Bench bench; bench.title("Weak copy performance under strong reference contention"); bench.relative(true); bench.minEpochIterations(500000); benchmark_weak_copy_with_strong_contention>( bench, num_threads); benchmark_weak_copy_with_strong_contention>(bench, num_threads); } TEST_CASE("Strong copy performance under weak reference contention") { const int num_threads = 3; ankerl::nanobench::Bench bench; bench.title("Strong copy performance under weak reference contention"); bench.relative(true); bench.minEpochIterations(500000); benchmark_strong_copy_with_weak_contention>( bench, num_threads); benchmark_strong_copy_with_weak_contention>(bench, num_threads); }