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.
17 #include <folly/Foreach.h>
19 #include <folly/Benchmark.h>
20 #include <folly/portability/GTest.h>
24 using namespace folly;
25 using namespace folly::detail;
28 // 1. Benchmark iterating through the man with FOR_EACH, and also assign
29 // iter->first and iter->second to local vars inside the FOR_EACH loop.
30 // 2. Benchmark iterating through the man with FOR_EACH, but use iter->first and
31 // iter->second as is, without assigning to local variables.
32 // 3. Use FOR_EACH_KV loop to iterate through the map.
34 std::map<int, std::string> bmMap; // For use in benchmarks below.
35 std::vector<int> vec_one;
36 std::vector<int> vec_two;
38 void setupBenchmark(size_t iters) {
40 for (size_t i = 0; i < iters; ++i) {
41 bmMap[i] = "teststring";
46 vec_one.resize(iters);
47 vec_two.resize(iters);
50 BENCHMARK(ForEachFunctionNoAssign, iters) {
51 BenchmarkSuspender suspender;
54 std::string sumValues;
55 setupBenchmark(iters);
57 suspender.dismissing([&]() {
58 folly::for_each(bmMap, [&](auto& key_val_pair) {
59 sumKeys += key_val_pair.first;
60 sumValues += key_val_pair.second;
62 doNotOptimizeAway(sumKeys);
66 BENCHMARK(StdForEachFunctionNoAssign, iters) {
67 BenchmarkSuspender suspender;
70 std::string sumValues;
71 setupBenchmark(iters);
73 suspender.dismissing([&]() {
74 std::for_each(bmMap.begin(), bmMap.end(), [&](auto& key_val_pair) {
75 sumKeys += key_val_pair.first;
76 sumValues += key_val_pair.second;
78 doNotOptimizeAway(sumKeys);
82 BENCHMARK(RangeBasedForLoopNoAssign, iters) {
83 BenchmarkSuspender suspender;
85 std::string sumValues;
86 setupBenchmark(iters);
88 suspender.dismissing([&]() {
89 for (auto& key_val_pair : bmMap) {
90 sumKeys += key_val_pair.first;
91 sumValues += key_val_pair.second;
93 doNotOptimizeAway(sumKeys);
97 BENCHMARK(ManualLoopNoAssign, iters) {
98 BenchmarkSuspender suspender;
101 std::string sumValues;
102 setupBenchmark(iters);
104 suspender.dismissing([&]() {
105 for (auto iter = bmMap.begin(); iter != bmMap.end(); ++iter) {
106 sumKeys += iter->first;
107 sumValues += iter->second;
109 doNotOptimizeAway(sumKeys);
113 BENCHMARK(ForEachFunctionAssign, iters) {
114 BenchmarkSuspender suspender;
117 std::string sumValues;
118 setupBenchmark(iters);
120 suspender.dismissing([&]() {
121 folly::for_each(bmMap, [&](auto& key_val_pair) {
122 const int k = key_val_pair.first;
123 const std::string v = key_val_pair.second;
130 BENCHMARK(StdForEachFunctionAssign, iters) {
131 BenchmarkSuspender suspender;
134 std::string sumValues;
135 setupBenchmark(iters);
137 suspender.dismissing([&]() {
138 std::for_each(bmMap.begin(), bmMap.end(), [&](auto& key_val_pair) {
139 const int k = key_val_pair.first;
140 const std::string v = key_val_pair.second;
147 BENCHMARK(RangeBasedForLoopAssign, iters) {
148 BenchmarkSuspender suspender;
151 std::string sumValues;
152 setupBenchmark(iters);
154 suspender.dismissing([&]() {
155 for (auto& key_val_pair : bmMap) {
156 const int k = key_val_pair.first;
157 const std::string v = key_val_pair.second;
164 BENCHMARK(ManualLoopAssign, iters) {
165 BenchmarkSuspender suspender;
168 std::string sumValues;
169 setupBenchmark(iters);
171 suspender.dismissing([&]() {
172 for (auto iter = bmMap.begin(); iter != bmMap.end(); ++iter) {
173 const int k = iter->first;
174 const std::string v = iter->second;
181 BENCHMARK(ForEachFunctionNoAssignWithIndexManipulation, iters) {
182 BenchmarkSuspender suspender;
185 std::string sumValues;
186 setupBenchmark(iters);
188 suspender.dismissing([&]() {
189 folly::for_each(bmMap, [&](auto& key_val_pair, auto index) {
190 sumKeys += key_val_pair.first;
191 sumValues += key_val_pair.second;
197 BENCHMARK(StdForEachFunctionNoAssignWithIndexManipulation, iters) {
198 BenchmarkSuspender suspender;
201 std::string sumValues;
202 setupBenchmark(iters);
204 suspender.dismissing([&]() {
205 auto index = std::size_t{0};
206 std::for_each(bmMap.begin(), bmMap.end(), [&](auto& key_val_pair) {
207 sumKeys += key_val_pair.first;
208 sumValues += key_val_pair.second;
215 BENCHMARK(RangeBasedForLoopNoAssignWithIndexManipulation, iters) {
216 BenchmarkSuspender suspender;
219 std::string sumValues;
220 setupBenchmark(iters);
222 suspender.dismissing([&]() {
223 auto index = std::size_t{0};
224 for (auto& key_val_pair : bmMap) {
225 sumKeys += key_val_pair.first;
226 sumValues += key_val_pair.second;
232 BENCHMARK(ForEachFunctionFetch, iters) {
233 BenchmarkSuspender suspender;
234 setupBenchmark(iters);
236 suspender.dismissing([&]() {
237 folly::for_each(bmMap, [&](auto& key_val_pair, auto index) {
238 folly::fetch(vec_one, index) = key_val_pair.first;
243 BENCHMARK(StdForEachFunctionFetch, iters) {
244 BenchmarkSuspender suspender;
245 setupBenchmark(iters);
247 suspender.dismissing([&]() {
248 auto index = std::size_t{0};
249 std::for_each(bmMap.begin(), bmMap.end(), [&](auto& key_val_pair) {
250 *(vec_one.begin() + index++) = key_val_pair.first;
255 BENCHMARK(ForLoopFetch, iters) {
256 BenchmarkSuspender suspender;
257 setupBenchmark(iters);
259 suspender.dismissing([&]() {
260 auto index = std::size_t{0};
261 for (auto& key_val_pair : bmMap) {
262 *(vec_one.begin() + index++) = key_val_pair.first;
267 BENCHMARK(ForEachKVNoMacroAssign, iters) {
269 std::string sumValues;
271 BENCHMARK_SUSPEND { setupBenchmark(iters); }
273 FOR_EACH(iter, bmMap) {
274 const int k = iter->first;
275 const std::string v = iter->second;
281 BENCHMARK(ForEachKVNoMacroNoAssign, iters) {
283 std::string sumValues;
285 BENCHMARK_SUSPEND { setupBenchmark(iters); }
287 FOR_EACH(iter, bmMap) {
288 sumKeys += iter->first;
289 sumValues += iter->second;
293 BENCHMARK(ForEachKVMacro, iters) {
295 std::string sumValues;
297 BENCHMARK_SUSPEND { setupBenchmark(iters); }
299 FOR_EACH_KV(k, v, bmMap) {
305 BENCHMARK(ForEachManual, iters) {
307 for (size_t i = 1; i < iters; ++i) {
310 doNotOptimizeAway(sum);
313 BENCHMARK(ForEachRange, iters) {
315 FOR_EACH_RANGE(i, 1, iters) { sum *= i; }
316 doNotOptimizeAway(sum);
319 BENCHMARK(ForEachDescendingManual, iters) {
321 for (size_t i = iters; i-- > 1;) {
324 doNotOptimizeAway(sum);
327 BENCHMARK(ForEachRangeR, iters) {
329 FOR_EACH_RANGE_R(i, 1U, iters) { sum *= i; }
330 doNotOptimizeAway(sum);
333 int main(int argc, char** argv) {
334 testing::InitGoogleTest(&argc, argv);
335 gflags::ParseCommandLineFlags(&argc, &argv, true);
336 auto r = RUN_ALL_TESTS();