|
#include <benchmark/benchmark.h> |
|
#include <folly/concurrency/AtomicSharedPtr.h> |
|
|
|
#include <shared_mutex> |
|
#include <iostream> |
|
|
|
struct Data { |
|
int buffer[100]; |
|
}; |
|
|
|
int64_t g_thread_count = 1; |
|
|
|
template <class F> |
|
void run_test(const F& f) { |
|
static constexpr int64_t kInvokes = 1'000'000; |
|
const int64_t invokes_per_thread = kInvokes / g_thread_count; |
|
|
|
std::vector<std::jthread> threads; |
|
for (int64_t i = 0; i < g_thread_count; ++i) { |
|
threads.emplace_back([&] { |
|
auto ptr = std::make_shared<Data>(); |
|
for (int64_t i = 0; i < invokes_per_thread; ++i) { |
|
f(ptr); |
|
} |
|
}); |
|
} |
|
} |
|
|
|
static void ____________mutex_store(benchmark::State& state) { |
|
std::shared_ptr<Data> synced_ptr; |
|
std::mutex m; |
|
for (auto _ : state) { |
|
run_test([&](const std::shared_ptr<Data>& ptr) { |
|
std::unique_lock lock{m}; |
|
synced_ptr = ptr; |
|
}); |
|
} |
|
} |
|
BENCHMARK(____________mutex_store)->Unit(benchmark::kMillisecond); |
|
|
|
static void _____shared_mutex_store(benchmark::State& state) { |
|
std::shared_ptr<Data> synced_ptr; |
|
std::shared_mutex m; |
|
for (auto _ : state) { |
|
run_test([&](const std::shared_ptr<Data>& ptr) { |
|
std::unique_lock lock{m}; |
|
synced_ptr = ptr; |
|
}); |
|
} |
|
} |
|
BENCHMARK(_____shared_mutex_store)->Unit(benchmark::kMillisecond); |
|
|
|
static void atomic_shared_ptr_store(benchmark::State& state) { |
|
folly::atomic_shared_ptr<Data> synced_ptr; |
|
for (auto _ : state) { |
|
run_test([&](const std::shared_ptr<Data>& ptr) { synced_ptr = ptr; }); |
|
} |
|
} |
|
BENCHMARK(atomic_shared_ptr_store)->Unit(benchmark::kMillisecond); |
|
|
|
static void ___________atomic_store(benchmark::State& state) { |
|
std::shared_ptr<Data> synced_ptr; |
|
for (auto _ : state) { |
|
run_test([&](const std::shared_ptr<Data>& ptr) { std::atomic_store(&synced_ptr, ptr); }); |
|
} |
|
} |
|
BENCHMARK(___________atomic_store)->Unit(benchmark::kMillisecond); |
|
|
|
static void ____________mutex_load(benchmark::State& state) { |
|
std::shared_ptr<Data> synced_ptr; |
|
std::mutex m; |
|
for (auto _ : state) { |
|
run_test([&](std::shared_ptr<Data>& ptr) { |
|
std::unique_lock lock{m}; |
|
ptr = synced_ptr; |
|
}); |
|
} |
|
} |
|
BENCHMARK(____________mutex_load)->Unit(benchmark::kMillisecond); |
|
|
|
static void _____shared_mutex_load(benchmark::State& state) { |
|
std::shared_ptr<Data> synced_ptr; |
|
std::shared_mutex m; |
|
for (auto _ : state) { |
|
run_test([&](std::shared_ptr<Data>& ptr) { |
|
std::shared_lock lock{m}; |
|
ptr = synced_ptr; |
|
}); |
|
} |
|
} |
|
BENCHMARK(_____shared_mutex_load)->Unit(benchmark::kMillisecond); |
|
|
|
static void atomic_shared_ptr_load(benchmark::State& state) { |
|
folly::atomic_shared_ptr<Data> synced_ptr; |
|
for (auto _ : state) { |
|
run_test([&](std::shared_ptr<Data>& ptr) { ptr = synced_ptr; }); |
|
} |
|
} |
|
BENCHMARK(atomic_shared_ptr_load)->Unit(benchmark::kMillisecond); |
|
|
|
static void ___________atomic_load(benchmark::State& state) { |
|
std::shared_ptr<Data> synced_ptr; |
|
for (auto _ : state) { |
|
run_test([&](std::shared_ptr<Data>& ptr) { ptr = std::atomic_load(&synced_ptr); }); |
|
} |
|
} |
|
BENCHMARK(___________atomic_load)->Unit(benchmark::kMillisecond); |
|
|
|
namespace { |
|
|
|
class SilentReporter : public benchmark::ConsoleReporter { |
|
public: |
|
using ConsoleReporter::ConsoleReporter; |
|
bool ReportContext(const Context&) override { return true; } |
|
}; |
|
|
|
} // namespace |
|
|
|
int main(int argc, char** argv) { |
|
SilentReporter reporter; |
|
for (auto thread_count : {1, 2, 4, 8, 12, 16}) { |
|
g_thread_count = thread_count; |
|
std::cout << "Running in " << g_thread_count << " threads\n"; |
|
::benchmark::Initialize(&argc, argv); |
|
::benchmark::RunSpecifiedBenchmarks(&reporter); |
|
} |
|
} |