2 * Copyright 2017-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <folly/synchronization/ParkingLot.h>
20 #include <folly/Benchmark.h>
21 #include <folly/detail/Futex.h>
22 #include <folly/synchronization/Baton.h>
24 DEFINE_uint64(threads, 32, "Number of threads for benchmark");
26 using namespace folly;
29 struct SimpleBarrier {
30 explicit SimpleBarrier(size_t count) : lock_(), cv_(), count_(count) {}
33 std::unique_lock<std::mutex> lockHeld(lock_);
35 if (++num_ == count_) {
40 cv_.wait(lockHeld, [&]() { return gen == gen_; });
46 std::condition_variable cv_;
55 BENCHMARK(FutexNoWaitersWake, iters) {
56 BenchmarkSuspender susp;
57 folly::detail::Futex<> fu;
58 SimpleBarrier b(FLAGS_threads + 1);
60 std::vector<std::thread> threads{FLAGS_threads};
61 for (auto& t : threads) {
62 t = std::thread([&]() {
64 for (int i = 0; i < iters; i++) {
72 for (auto& t : threads) {
77 BENCHMARK_RELATIVE(ParkingLotNoWaitersWake, iters) {
78 BenchmarkSuspender susp;
79 folly::detail::Futex<> fu;
80 SimpleBarrier b(FLAGS_threads + 1);
82 std::vector<std::thread> threads{FLAGS_threads};
83 for (auto& t : threads) {
84 t = std::thread([&]() {
86 for (int i = 0; i < iters; i++) {
87 lot.unpark(&lot, [](Unit) { return UnparkControl::RetainContinue; });
94 for (auto& t : threads) {
99 BENCHMARK(FutexWakeOne, iters) {
100 BenchmarkSuspender susp;
101 folly::detail::Futex<> fu;
102 SimpleBarrier b(FLAGS_threads + 1);
104 std::vector<std::thread> threads{FLAGS_threads};
105 for (auto& t : threads) {
106 t = std::thread([&]() {
110 if (fu.load(std::memory_order_relaxed)) {
118 for (int i = 0; i < iters; i++) {
122 fu.futexWake(threads.size());
124 for (auto& t : threads) {
129 BENCHMARK_RELATIVE(ParkingLotWakeOne, iters) {
130 BenchmarkSuspender susp;
131 std::atomic<bool> done{false};
132 SimpleBarrier b(FLAGS_threads + 1);
134 std::vector<std::thread> threads{FLAGS_threads};
135 for (auto& t : threads) {
136 t = std::thread([&]() {
143 [&] { return done.load(std::memory_order_relaxed) == 0; },
145 if (done.load(std::memory_order_relaxed)) {
153 for (int i = 0; i < iters; i++) {
154 lot.unpark(&done, [](Unit) { return UnparkControl::RemoveBreak; });
157 lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });
159 for (auto& t : threads) {
164 BENCHMARK(FutexWakeAll, iters) {
165 BenchmarkSuspender susp;
166 SimpleBarrier b(FLAGS_threads + 1);
167 folly::detail::Futex<> fu;
168 std::atomic<bool> done{false};
170 std::vector<std::thread> threads{FLAGS_threads};
171 for (auto& t : threads) {
172 t = std::thread([&]() {
176 if (done.load(std::memory_order_relaxed)) {
184 for (int i = 0; i < iters; i++) {
185 fu.futexWake(threads.size());
189 fu.futexWake(threads.size());
191 for (auto& t : threads) {
196 BENCHMARK_RELATIVE(ParkingLotWakeAll, iters) {
197 BenchmarkSuspender susp;
198 SimpleBarrier b(FLAGS_threads + 1);
199 std::atomic<bool> done{false};
201 std::vector<std::thread> threads{FLAGS_threads};
202 for (auto& t : threads) {
203 t = std::thread([&]() {
210 [&] { return done.load(std::memory_order_relaxed) == 0; },
212 if (done.load(std::memory_order_relaxed)) {
220 for (int i = 0; i < iters; i++) {
221 lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });
224 lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });
226 for (auto& t : threads) {
231 int main(int argc, char** argv) {
232 gflags::ParseCommandLineFlags(&argc, &argv, true);
234 folly::runBenchmarks();
238 ./buck-out/gen/folly/synchronization/test/parking_lot_test --benchmark
239 --bm_min_iters=10000 --threads=4
240 ============================================================================
241 folly/synchronization/test/ParkingLotBenchmark.cpprelative time/iter iters/s
242 ============================================================================
243 FutexNoWaitersWake 163.43ns 6.12M
244 ParkingLotNoWaitersWake 29.64% 551.43ns 1.81M
245 FutexWakeOne 156.78ns 6.38M
246 ParkingLotWakeOne 37.49% 418.21ns 2.39M
247 FutexWakeAll 1.82us 549.52K
248 ParkingLotWakeAll 449.63% 404.73ns 2.47M
249 ============================================================================
251 ./buck-out/gen/folly/synchronization/test/parking_lot_test --benchmark
252 --bm_min_iters=10000 --threads=32
253 ============================================================================
254 folly/synchronization/test/ParkingLotBenchmark.cpprelative time/iter iters/s
255 ============================================================================
256 FutexNoWaitersWake 379.59ns 2.63M
257 ParkingLotNoWaitersWake 7.94% 4.78us 209.08K
258 FutexWakeOne 163.59ns 6.11M
259 ParkingLotWakeOne 6.41% 2.55us 392.07K
260 FutexWakeAll 12.46us 80.27K
261 ParkingLotWakeAll 784.76% 1.59us 629.92K
262 ============================================================================ */