Fix copyright line in folly/synchronization/test/ParkingLotBenchmark.cpp
[folly.git] / folly / synchronization / test / ParkingLotBenchmark.cpp
1 /*
2  * Copyright 2018-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <thread>
17
18 #include <folly/synchronization/ParkingLot.h>
19
20 #include <folly/Benchmark.h>
21 #include <folly/detail/Futex.h>
22 #include <folly/synchronization/Baton.h>
23
24 DEFINE_uint64(threads, 32, "Number of threads for benchmark");
25
26 using namespace folly;
27
28 namespace {
29 struct SimpleBarrier {
30   explicit SimpleBarrier(size_t count) : lock_(), cv_(), count_(count) {}
31
32   void wait() {
33     std::unique_lock<std::mutex> lockHeld(lock_);
34     auto gen = gen_;
35     if (++num_ == count_) {
36       num_ = 0;
37       gen_++;
38       cv_.notify_all();
39     } else {
40       cv_.wait(lockHeld, [&]() { return gen == gen_; });
41     }
42   }
43
44  private:
45   std::mutex lock_;
46   std::condition_variable cv_;
47   size_t num_{0};
48   size_t count_;
49   size_t gen_{0};
50 };
51 } // namespace
52
53 ParkingLot<> lot;
54
55 BENCHMARK(FutexNoWaitersWake, iters) {
56   BenchmarkSuspender susp;
57   folly::detail::Futex<> fu;
58   SimpleBarrier b(FLAGS_threads + 1);
59
60   std::vector<std::thread> threads{FLAGS_threads};
61   for (auto& t : threads) {
62     t = std::thread([&]() {
63       b.wait();
64       for (auto i = 0u; i < iters; i++) {
65         fu.futexWake(1);
66       }
67     });
68   }
69   susp.dismiss();
70   b.wait();
71
72   for (auto& t : threads) {
73     t.join();
74   }
75 }
76
77 BENCHMARK_RELATIVE(ParkingLotNoWaitersWake, iters) {
78   BenchmarkSuspender susp;
79   SimpleBarrier b(FLAGS_threads + 1);
80
81   std::vector<std::thread> threads{FLAGS_threads};
82   for (auto& t : threads) {
83     t = std::thread([&]() {
84       b.wait();
85       for (auto i = 0u; i < iters; i++) {
86         lot.unpark(&lot, [](Unit) { return UnparkControl::RetainContinue; });
87       }
88     });
89   }
90   susp.dismiss();
91   b.wait();
92
93   for (auto& t : threads) {
94     t.join();
95   }
96 }
97
98 BENCHMARK(FutexWakeOne, iters) {
99   BenchmarkSuspender susp;
100   folly::detail::Futex<> fu;
101   SimpleBarrier b(FLAGS_threads + 1);
102
103   std::vector<std::thread> threads{FLAGS_threads};
104   for (auto& t : threads) {
105     t = std::thread([&]() {
106       b.wait();
107       while (true) {
108         fu.futexWait(0);
109         if (fu.load(std::memory_order_relaxed)) {
110           return;
111         }
112       }
113     });
114   }
115   susp.dismiss();
116   b.wait();
117   for (auto i = 0u; i < iters; i++) {
118     fu.futexWake(1);
119   }
120   fu.store(1);
121   fu.futexWake(threads.size());
122
123   for (auto& t : threads) {
124     t.join();
125   }
126 }
127
128 BENCHMARK_RELATIVE(ParkingLotWakeOne, iters) {
129   BenchmarkSuspender susp;
130   std::atomic<bool> done{false};
131   SimpleBarrier b(FLAGS_threads + 1);
132
133   std::vector<std::thread> threads{FLAGS_threads};
134   for (auto& t : threads) {
135     t = std::thread([&]() {
136       b.wait();
137       while (true) {
138         Unit f;
139         lot.park(
140             &done,
141             f,
142             [&] { return done.load(std::memory_order_relaxed) == 0; },
143             [] {});
144         if (done.load(std::memory_order_relaxed)) {
145           return;
146         }
147       }
148     });
149   }
150   susp.dismiss();
151   b.wait();
152   for (auto i = 0u; i < iters; i++) {
153     lot.unpark(&done, [](Unit) { return UnparkControl::RemoveBreak; });
154   }
155   done = true;
156   lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });
157
158   for (auto& t : threads) {
159     t.join();
160   }
161 }
162
163 BENCHMARK(FutexWakeAll, iters) {
164   BenchmarkSuspender susp;
165   SimpleBarrier b(FLAGS_threads + 1);
166   folly::detail::Futex<> fu;
167   std::atomic<bool> done{false};
168
169   std::vector<std::thread> threads{FLAGS_threads};
170   for (auto& t : threads) {
171     t = std::thread([&]() {
172       b.wait();
173       while (true) {
174         fu.futexWait(0);
175         if (done.load(std::memory_order_relaxed)) {
176           return;
177         }
178       }
179     });
180   }
181   susp.dismiss();
182   b.wait();
183   for (auto i = 0u; i < iters; i++) {
184     fu.futexWake(threads.size());
185   }
186   fu.store(1);
187   done = true;
188   fu.futexWake(threads.size());
189
190   for (auto& t : threads) {
191     t.join();
192   }
193 }
194
195 BENCHMARK_RELATIVE(ParkingLotWakeAll, iters) {
196   BenchmarkSuspender susp;
197   SimpleBarrier b(FLAGS_threads + 1);
198   std::atomic<bool> done{false};
199
200   std::vector<std::thread> threads{FLAGS_threads};
201   for (auto& t : threads) {
202     t = std::thread([&]() {
203       b.wait();
204       while (true) {
205         Unit f;
206         lot.park(
207             &done,
208             f,
209             [&] { return done.load(std::memory_order_relaxed) == 0; },
210             [] {});
211         if (done.load(std::memory_order_relaxed)) {
212           return;
213         }
214       }
215     });
216   }
217   susp.dismiss();
218   b.wait();
219   for (auto i = 0u; i < iters; i++) {
220     lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });
221   }
222   done = true;
223   lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });
224
225   for (auto& t : threads) {
226     t.join();
227   }
228 }
229
230 int main(int argc, char** argv) {
231   gflags::ParseCommandLineFlags(&argc, &argv, true);
232
233   folly::runBenchmarks();
234 }
235 /*
236
237 ./buck-out/gen/folly/synchronization/test/parking_lot_test --benchmark
238 --bm_min_iters=10000 --threads=4
239 ============================================================================
240 folly/synchronization/test/ParkingLotBenchmark.cpprelative  time/iter  iters/s
241 ============================================================================
242 FutexNoWaitersWake                                         163.43ns    6.12M
243 ParkingLotNoWaitersWake                           29.64%   551.43ns    1.81M
244 FutexWakeOne                                               156.78ns    6.38M
245 ParkingLotWakeOne                                 37.49%   418.21ns    2.39M
246 FutexWakeAll                                                 1.82us  549.52K
247 ParkingLotWakeAll                                449.63%   404.73ns    2.47M
248 ============================================================================
249
250 ./buck-out/gen/folly/synchronization/test/parking_lot_test --benchmark
251 --bm_min_iters=10000 --threads=32
252 ============================================================================
253 folly/synchronization/test/ParkingLotBenchmark.cpprelative  time/iter  iters/s
254 ============================================================================
255 FutexNoWaitersWake                                         379.59ns    2.63M
256 ParkingLotNoWaitersWake                            7.94%     4.78us  209.08K
257 FutexWakeOne                                               163.59ns    6.11M
258 ParkingLotWakeOne                                  6.41%     2.55us  392.07K
259 FutexWakeAll                                                12.46us   80.27K
260 ParkingLotWakeAll                                784.76%     1.59us  629.92K
261 ============================================================================ */