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 (auto i = 0u; i < iters; i++) {
72 for (auto& t : threads) {
77 BENCHMARK_RELATIVE(ParkingLotNoWaitersWake, iters) {
78 BenchmarkSuspender susp;
79 SimpleBarrier b(FLAGS_threads + 1);
81 std::vector<std::thread> threads{FLAGS_threads};
82 for (auto& t : threads) {
83 t = std::thread([&]() {
85 for (auto i = 0u; i < iters; i++) {
86 lot.unpark(&lot, [](Unit) { return UnparkControl::RetainContinue; });
93 for (auto& t : threads) {
98 BENCHMARK(FutexWakeOne, iters) {
99 BenchmarkSuspender susp;
100 folly::detail::Futex<> fu;
101 SimpleBarrier b(FLAGS_threads + 1);
103 std::vector<std::thread> threads{FLAGS_threads};
104 for (auto& t : threads) {
105 t = std::thread([&]() {
109 if (fu.load(std::memory_order_relaxed)) {
117 for (auto i = 0u; i < iters; i++) {
121 fu.futexWake(threads.size());
123 for (auto& t : threads) {
128 BENCHMARK_RELATIVE(ParkingLotWakeOne, iters) {
129 BenchmarkSuspender susp;
130 std::atomic<bool> done{false};
131 SimpleBarrier b(FLAGS_threads + 1);
133 std::vector<std::thread> threads{FLAGS_threads};
134 for (auto& t : threads) {
135 t = std::thread([&]() {
142 [&] { return done.load(std::memory_order_relaxed) == 0; },
144 if (done.load(std::memory_order_relaxed)) {
152 for (auto i = 0u; i < iters; i++) {
153 lot.unpark(&done, [](Unit) { return UnparkControl::RemoveBreak; });
156 lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });
158 for (auto& t : threads) {
163 BENCHMARK(FutexWakeAll, iters) {
164 BenchmarkSuspender susp;
165 SimpleBarrier b(FLAGS_threads + 1);
166 folly::detail::Futex<> fu;
167 std::atomic<bool> done{false};
169 std::vector<std::thread> threads{FLAGS_threads};
170 for (auto& t : threads) {
171 t = std::thread([&]() {
175 if (done.load(std::memory_order_relaxed)) {
183 for (auto i = 0u; i < iters; i++) {
184 fu.futexWake(threads.size());
188 fu.futexWake(threads.size());
190 for (auto& t : threads) {
195 BENCHMARK_RELATIVE(ParkingLotWakeAll, iters) {
196 BenchmarkSuspender susp;
197 SimpleBarrier b(FLAGS_threads + 1);
198 std::atomic<bool> done{false};
200 std::vector<std::thread> threads{FLAGS_threads};
201 for (auto& t : threads) {
202 t = std::thread([&]() {
209 [&] { return done.load(std::memory_order_relaxed) == 0; },
211 if (done.load(std::memory_order_relaxed)) {
219 for (auto i = 0u; i < iters; i++) {
220 lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });
223 lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });
225 for (auto& t : threads) {
230 int main(int argc, char** argv) {
231 gflags::ParseCommandLineFlags(&argc, &argv, true);
233 folly::runBenchmarks();
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 ============================================================================
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 ============================================================================ */