Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include <cstdint>
00016 #include <mutex>
00017 #include <vector>
00018
00019 #include "absl/base/internal/cycleclock.h"
00020 #include "absl/base/internal/spinlock.h"
00021 #include "absl/synchronization/blocking_counter.h"
00022 #include "absl/synchronization/internal/thread_pool.h"
00023 #include "absl/synchronization/mutex.h"
00024 #include "benchmark/benchmark.h"
00025
00026 namespace {
00027
00028 void BM_Mutex(benchmark::State& state) {
00029 static absl::Mutex* mu = new absl::Mutex;
00030 for (auto _ : state) {
00031 absl::MutexLock lock(mu);
00032 }
00033 }
00034 BENCHMARK(BM_Mutex)->UseRealTime()->Threads(1)->ThreadPerCpu();
00035
00036 static void DelayNs(int64_t ns, int* data) {
00037 int64_t end = absl::base_internal::CycleClock::Now() +
00038 ns * absl::base_internal::CycleClock::Frequency() / 1e9;
00039 while (absl::base_internal::CycleClock::Now() < end) {
00040 ++(*data);
00041 benchmark::DoNotOptimize(*data);
00042 }
00043 }
00044
00045 template <typename MutexType>
00046 class RaiiLocker {
00047 public:
00048 explicit RaiiLocker(MutexType* mu) : mu_(mu) { mu_->Lock(); }
00049 ~RaiiLocker() { mu_->Unlock(); }
00050 private:
00051 MutexType* mu_;
00052 };
00053
00054 template <>
00055 class RaiiLocker<std::mutex> {
00056 public:
00057 explicit RaiiLocker(std::mutex* mu) : mu_(mu) { mu_->lock(); }
00058 ~RaiiLocker() { mu_->unlock(); }
00059 private:
00060 std::mutex* mu_;
00061 };
00062
00063 template <typename MutexType>
00064 void BM_Contended(benchmark::State& state) {
00065 struct Shared {
00066 MutexType mu;
00067 int data = 0;
00068 };
00069 static auto* shared = new Shared;
00070 int local = 0;
00071 for (auto _ : state) {
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082 DelayNs(100 * state.threads, &local);
00083 RaiiLocker<MutexType> locker(&shared->mu);
00084 DelayNs(state.range(0), &shared->data);
00085 }
00086 }
00087
00088 BENCHMARK_TEMPLATE(BM_Contended, absl::Mutex)
00089 ->UseRealTime()
00090
00091 ->Threads(1)
00092 ->Threads(2)
00093 ->Threads(4)
00094 ->Threads(6)
00095 ->Threads(8)
00096 ->Threads(12)
00097 ->Threads(16)
00098 ->Threads(24)
00099 ->Threads(32)
00100 ->Threads(48)
00101 ->Threads(64)
00102 ->Threads(96)
00103 ->Threads(128)
00104 ->Threads(192)
00105 ->Threads(256)
00106
00107
00108 ->Arg(1)
00109 ->Arg(20)
00110 ->Arg(50)
00111 ->Arg(200);
00112
00113 BENCHMARK_TEMPLATE(BM_Contended, absl::base_internal::SpinLock)
00114 ->UseRealTime()
00115
00116 ->Threads(1)
00117 ->Threads(2)
00118 ->Threads(4)
00119 ->Threads(6)
00120 ->Threads(8)
00121 ->Threads(12)
00122 ->Threads(16)
00123 ->Threads(24)
00124 ->Threads(32)
00125 ->Threads(48)
00126 ->Threads(64)
00127 ->Threads(96)
00128 ->Threads(128)
00129 ->Threads(192)
00130 ->Threads(256)
00131
00132
00133 ->Arg(1)
00134 ->Arg(20)
00135 ->Arg(50)
00136 ->Arg(200);
00137
00138 BENCHMARK_TEMPLATE(BM_Contended, std::mutex)
00139 ->UseRealTime()
00140
00141 ->Threads(1)
00142 ->Threads(2)
00143 ->Threads(4)
00144 ->Threads(6)
00145 ->Threads(8)
00146 ->Threads(12)
00147 ->Threads(16)
00148 ->Threads(24)
00149 ->Threads(32)
00150 ->Threads(48)
00151 ->Threads(64)
00152 ->Threads(96)
00153 ->Threads(128)
00154 ->Threads(192)
00155 ->Threads(256)
00156
00157
00158 ->Arg(1)
00159 ->Arg(20)
00160 ->Arg(50)
00161 ->Arg(200);
00162
00163
00164
00165
00166
00167
00168
00169 void BM_ConditionWaiters(benchmark::State& state) {
00170 int num_classes = state.range(0);
00171 int num_waiters = state.range(1);
00172
00173 struct Helper {
00174 static void Waiter(absl::BlockingCounter* init, absl::Mutex* m, int* p) {
00175 init->DecrementCount();
00176 m->LockWhen(absl::Condition(
00177 static_cast<bool (*)(int*)>([](int* v) { return *v == 0; }), p));
00178 m->Unlock();
00179 }
00180 };
00181
00182 if (num_classes == 0) {
00183
00184 num_classes = num_waiters;
00185 }
00186
00187 absl::BlockingCounter init(num_waiters);
00188 absl::Mutex mu;
00189 std::vector<int> equivalence_classes(num_classes, 1);
00190
00191
00192 absl::synchronization_internal::ThreadPool pool(num_waiters);
00193
00194 for (int i = 0; i < num_waiters; i++) {
00195
00196
00197 pool.Schedule([&, i] {
00198 Helper::Waiter(&init, &mu, &equivalence_classes[i % num_classes]);
00199 });
00200 }
00201 init.Wait();
00202
00203 for (auto _ : state) {
00204 mu.Lock();
00205 mu.Unlock();
00206 }
00207
00208 mu.Lock();
00209 for (int i = 0; i < num_classes; i++) {
00210 equivalence_classes[i] = 0;
00211 }
00212 mu.Unlock();
00213 }
00214
00215
00216 #if defined(__linux__) && !defined(THREAD_SANITIZER)
00217 constexpr int kMaxConditionWaiters = 8192;
00218 #else
00219 constexpr int kMaxConditionWaiters = 1024;
00220 #endif
00221 BENCHMARK(BM_ConditionWaiters)->RangePair(0, 2, 1, kMaxConditionWaiters);
00222
00223 }