2 * Copyright 2017 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/Benchmark.h>
19 #include <folly/experimental/hazptr/example/SWMRList.h>
20 #include <folly/portability/GTest.h>
22 #include <glog/logging.h>
30 template <typename InitFunc, typename Func, typename EndFunc>
31 inline uint64_t run_once(
35 const EndFunc& endFn) {
36 folly::BenchmarkSuspender susp;
37 std::atomic<bool> start{false};
38 std::atomic<int> started{0};
42 std::vector<std::thread> threads(nthreads);
43 for (int tid = 0; tid < nthreads; ++tid) {
44 threads[tid] = std::thread([&, tid] {
52 while (started.load() < nthreads)
55 // begin time measurement
56 auto tbegin = std::chrono::steady_clock::now();
60 for (auto& t : threads) {
65 // end time measurement
66 auto tend = std::chrono::steady_clock::now();
68 return std::chrono::duration_cast<std::chrono::nanoseconds>(tend - tbegin)
72 template <typename RepFunc>
73 inline uint64_t bench(std::string name, int ops, const RepFunc& repFn) {
75 uint64_t min = UINTMAX_MAX;
79 repFn(); // sometimes first run is outlier
80 for (int r = 0; r < reps; ++r) {
81 uint64_t dur = repFn();
83 min = std::min(min, dur);
84 max = std::max(max, dur);
87 const std::string unit = " ns";
88 uint64_t avg = sum / reps;
91 std::cout << " " << std::setw(4) << max / ops << unit;
92 std::cout << " " << std::setw(4) << avg / ops << unit;
93 std::cout << " " << std::setw(4) << res / ops << unit;
94 std::cout << std::endl;
98 const int ops = 1000000;
100 inline uint64_t listBench(std::string name, int nthreads, int size) {
102 SWMRListSet<uint64_t> s;
104 for (int i = 0; i < size; ++i) {
108 auto fn = [&](int tid) {
109 for (int j = tid; j < ops; j += nthreads) {
114 return run_once(nthreads, init, fn, endFn);
116 return bench(name, ops, repFn);
119 inline uint64_t holderBench(std::string name, int nthreads) {
122 auto fn = [&](int tid) {
123 for (int j = tid; j < ops; j += nthreads) {
128 return run_once(nthreads, init, fn, endFn);
130 return bench(name, ops, repFn);
134 inline uint64_t arrayBench(std::string name, int nthreads) {
137 auto fn = [&](int tid) {
138 for (int j = tid; j < 10 * ops; j += nthreads) {
143 return run_once(nthreads, init, fn, endFn);
145 return bench(name, ops, repFn);
149 inline uint64_t localBench(std::string name, int nthreads) {
152 auto fn = [&](int tid) {
153 for (int j = tid; j < 10 * ops; j += nthreads) {
158 return run_once(nthreads, init, fn, endFn);
160 return bench(name, ops, repFn);
163 inline uint64_t retireBench(std::string name, int nthreads) {
164 struct Foo : hazptr_obj_base<Foo> {
169 auto fn = [&](int tid) {
170 for (int j = tid; j < ops; j += nthreads) {
176 return run_once(nthreads, init, fn, endFn);
178 return bench(name, ops, repFn);
181 const int nthr[] = {1, 10};
182 const int sizes[] = {10, 100};
184 inline void benches(std::string name) {
185 std::cout << "------------------------------------------- " << name << "\n";
187 std::cout << i << " threads -- 10x construct/destruct hazptr_holder"
189 holderBench(name + " ", i);
190 holderBench(name + " - dup ", i);
191 std::cout << i << " threads -- 10x construct/destruct hazptr_array<10>"
193 arrayBench<10>(name + " ", i);
194 arrayBench<10>(name + " - dup ", i);
195 std::cout << i << " threads -- 10x construct/destruct hazptr_array<3>"
197 arrayBench<3>(name + " ", i);
198 arrayBench<3>(name + " - dup ", i);
199 std::cout << i << " threads -- 10x construct/destruct hazptr_local<10>"
201 localBench<10>(name + " ", i);
202 localBench<10>(name + " - dup ", i);
203 std::cout << i << " threads -- 10x construct/destruct hazptr_local<1>"
205 localBench<1>(name + " ", i);
206 localBench<1>(name + " - dup ", i);
207 std::cout << i << " threads -- allocate/retire/reclaim object" << std::endl;
208 retireBench(name + " ", i);
209 retireBench(name + " - dup ", i);
210 for (int j : sizes) {
211 std::cout << i << " threads -- " << j << "-item list" << std::endl;
212 listBench(name + " ", i, j);
213 listBench(name + " - dup ", i, j);
216 std::cout << "----------------------------------------------------------\n";
219 } // namespace hazptr
223 ------------------------------------------- amb - tc
224 1 threads -- 10x construct/destruct hazptr_holder
225 amb - tc 49 ns 46 ns 44 ns
226 amb - tc - dup 47 ns 45 ns 44 ns
227 1 threads -- 10x construct/destruct hazptr_array<10>
228 amb - tc 132 ns 122 ns 117 ns
229 amb - tc - dup 130 ns 122 ns 117 ns
230 1 threads -- 10x construct/destruct hazptr_array<3>
231 amb - tc 66 ns 64 ns 63 ns
232 amb - tc - dup 64 ns 64 ns 63 ns
233 1 threads -- 10x construct/destruct hazptr_local<10>
234 amb - tc 29 ns 27 ns 27 ns
235 amb - tc - dup 28 ns 27 ns 27 ns
236 1 threads -- 10x construct/destruct hazptr_local<1>
237 amb - tc 27 ns 27 ns 27 ns
238 amb - tc - dup 28 ns 28 ns 27 ns
239 1 threads -- allocate/retire/reclaim object
240 amb - tc 65 ns 62 ns 60 ns
241 amb - tc - dup 65 ns 60 ns 59 ns
242 1 threads -- 10-item list
243 amb - tc 21 ns 21 ns 20 ns
244 amb - tc - dup 22 ns 21 ns 21 ns
245 1 threads -- 100-item list
246 amb - tc 229 ns 224 ns 220 ns
247 amb - tc - dup 223 ns 219 ns 216 ns
248 10 threads -- 10x construct/destruct hazptr_holder
249 amb - tc 9 ns 8 ns 7 ns
250 amb - tc - dup 9 ns 8 ns 8 ns
251 10 threads -- 10x construct/destruct hazptr_array<10>
252 amb - tc 27 ns 23 ns 15 ns
253 amb - tc - dup 26 ns 20 ns 13 ns
254 10 threads -- 10x construct/destruct hazptr_array<3>
255 amb - tc 11 ns 11 ns 7 ns
256 amb - tc - dup 11 ns 9 ns 7 ns
257 10 threads -- 10x construct/destruct hazptr_local<10>
258 amb - tc 5 ns 3 ns 3 ns
259 amb - tc - dup 3 ns 3 ns 3 ns
260 10 threads -- 10x construct/destruct hazptr_local<1>
261 amb - tc 3 ns 3 ns 3 ns
262 amb - tc - dup 5 ns 4 ns 3 ns
263 10 threads -- allocate/retire/reclaim object
264 amb - tc 17 ns 15 ns 14 ns
265 amb - tc - dup 17 ns 15 ns 14 ns
266 10 threads -- 10-item list
267 amb - tc 4 ns 4 ns 2 ns
268 amb - tc - dup 4 ns 4 ns 3 ns
269 10 threads -- 100-item list
270 amb - tc 33 ns 31 ns 24 ns
271 amb - tc - dup 33 ns 32 ns 30 ns
272 ----------------------------------------------------------
273 ------------------------------------------- no amb - no tc
274 1 threads -- construct/destruct 10 hazptr_holder-s
275 no amb - no tc 2518 ns 2461 ns 2431 ns
276 no amb - no tc - dup 2499 ns 2460 ns 2420 ns
277 1 threads -- allocate/retire/reclaim object
278 no amb - no tc 85 ns 83 ns 81 ns
279 no amb - no tc - dup 83 ns 82 ns 81 ns
280 1 threads -- 10-item list
281 no amb - no tc 655 ns 644 ns 639 ns
282 no amb - no tc - dup 658 ns 645 ns 641 ns
283 1 threads -- 100-item list
284 no amb - no tc 2175 ns 2142 ns 2124 ns
285 no amb - no tc - dup 2294 ns 2228 ns 2138 ns
286 10 threads -- construct/destruct 10 hazptr_holder-s
287 no amb - no tc 3893 ns 2932 ns 1391 ns
288 no amb - no tc - dup 3157 ns 2927 ns 2726 ns
289 10 threads -- allocate/retire/reclaim object
290 no amb - no tc 152 ns 134 ns 127 ns
291 no amb - no tc - dup 141 ns 133 ns 128 ns
292 10 threads -- 10-item list
293 no amb - no tc 532 ns 328 ns 269 ns
294 no amb - no tc - dup 597 ns 393 ns 271 ns
295 10 threads -- 100-item list
296 no amb - no tc 757 ns 573 ns 412 ns
297 no amb - no tc - dup 819 ns 643 ns 420 ns
298 ----------------------------------------------------------
299 ------------------------------------------- amb - no tc
300 1 threads -- construct/destruct 10 hazptr_holder-s
301 amb - no tc 2590 ns 2481 ns 2422 ns
302 amb - no tc - dup 2519 ns 2468 ns 2424 ns
303 1 threads -- allocate/retire/reclaim object
304 amb - no tc 69 ns 68 ns 67 ns
305 amb - no tc - dup 69 ns 68 ns 67 ns
306 1 threads -- 10-item list
307 amb - no tc 524 ns 510 ns 492 ns
308 amb - no tc - dup 514 ns 507 ns 496 ns
309 1 threads -- 100-item list
310 amb - no tc 761 ns 711 ns 693 ns
311 amb - no tc - dup 717 ns 694 ns 684 ns
312 10 threads -- construct/destruct 10 hazptr_holder-s
313 amb - no tc 3302 ns 2908 ns 1612 ns
314 amb - no tc - dup 3220 ns 2909 ns 1641 ns
315 10 threads -- allocate/retire/reclaim object
316 amb - no tc 129 ns 123 ns 110 ns
317 amb - no tc - dup 135 ns 127 ns 120 ns
318 10 threads -- 10-item list
319 amb - no tc 512 ns 288 ns 256 ns
320 amb - no tc - dup 275 ns 269 ns 263 ns
321 10 threads -- 100-item list
322 amb - no tc 297 ns 289 ns 284 ns
323 amb - no tc - dup 551 ns 358 ns 282 ns
324 ----------------------------------------------------------
325 ------------------------------------------- no amb - tc
326 1 threads -- construct/destruct 10 hazptr_holder-s
327 no amb - tc 56 ns 55 ns 55 ns
328 no amb - tc - dup 56 ns 54 ns 54 ns
329 1 threads -- allocate/retire/reclaim object
330 no amb - tc 63 ns 62 ns 62 ns
331 no amb - tc - dup 64 ns 63 ns 62 ns
332 1 threads -- 10-item list
333 no amb - tc 190 ns 188 ns 187 ns
334 no amb - tc - dup 193 ns 186 ns 182 ns
335 1 threads -- 100-item list
336 no amb - tc 1859 ns 1698 ns 1666 ns
337 no amb - tc - dup 1770 ns 1717 ns 1673 ns
338 10 threads -- construct/destruct 10 hazptr_holder-s
339 no amb - tc 19 ns 11 ns 7 ns
340 no amb - tc - dup 11 ns 8 ns 7 ns
341 10 threads -- allocate/retire/reclaim object
342 no amb - tc 9 ns 8 ns 8 ns
343 no amb - tc - dup 10 ns 9 ns 8 ns
344 10 threads -- 10-item list
345 no amb - tc 40 ns 25 ns 21 ns
346 no amb - tc - dup 24 ns 23 ns 21 ns
347 10 threads -- 100-item list
348 no amb - tc 215 ns 208 ns 188 ns
349 no amb - tc - dup 215 ns 209 ns 197 ns
350 ----------------------------------------------------------