move Iterator, Enumerate, EvictingCacheMap, Foreach, Merge, and
[folly.git] / folly / container / test / ForeachBenchmark.cpp
diff --git a/folly/container/test/ForeachBenchmark.cpp b/folly/container/test/ForeachBenchmark.cpp
new file mode 100644 (file)
index 0000000..5b741af
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/container/Foreach.h>
+
+#include <folly/Benchmark.h>
+#include <folly/portability/GTest.h>
+
+#include <map>
+
+using namespace folly;
+using namespace folly::detail;
+
+// Benchmarks:
+// 1. Benchmark iterating through the man with FOR_EACH, and also assign
+//    iter->first and iter->second to local vars inside the FOR_EACH loop.
+// 2. Benchmark iterating through the man with FOR_EACH, but use iter->first and
+//    iter->second as is, without assigning to local variables.
+// 3. Use FOR_EACH_KV loop to iterate through the map.
+
+std::map<int, std::string> bmMap; // For use in benchmarks below.
+std::vector<int> vec_one;
+std::vector<int> vec_two;
+
+void setupBenchmark(size_t iters) {
+  bmMap.clear();
+  for (size_t i = 0; i < iters; ++i) {
+    bmMap[i] = "teststring";
+  }
+
+  vec_one.clear();
+  vec_two.clear();
+  vec_one.resize(iters);
+  vec_two.resize(iters);
+}
+
+BENCHMARK(ForEachFunctionNoAssign, iters) {
+  BenchmarkSuspender suspender;
+
+  int sumKeys = 0;
+  std::string sumValues;
+  setupBenchmark(iters);
+
+  suspender.dismissing([&]() {
+    folly::for_each(bmMap, [&](auto& key_val_pair) {
+      sumKeys += key_val_pair.first;
+      sumValues += key_val_pair.second;
+    });
+    doNotOptimizeAway(sumKeys);
+  });
+}
+
+BENCHMARK(StdForEachFunctionNoAssign, iters) {
+  BenchmarkSuspender suspender;
+
+  int sumKeys = 0;
+  std::string sumValues;
+  setupBenchmark(iters);
+
+  suspender.dismissing([&]() {
+    std::for_each(bmMap.begin(), bmMap.end(), [&](auto& key_val_pair) {
+      sumKeys += key_val_pair.first;
+      sumValues += key_val_pair.second;
+    });
+    doNotOptimizeAway(sumKeys);
+  });
+}
+
+BENCHMARK(RangeBasedForLoopNoAssign, iters) {
+  BenchmarkSuspender suspender;
+  int sumKeys = 0;
+  std::string sumValues;
+  setupBenchmark(iters);
+
+  suspender.dismissing([&]() {
+    for (auto& key_val_pair : bmMap) {
+      sumKeys += key_val_pair.first;
+      sumValues += key_val_pair.second;
+    }
+    doNotOptimizeAway(sumKeys);
+  });
+}
+
+BENCHMARK(ManualLoopNoAssign, iters) {
+  BenchmarkSuspender suspender;
+
+  int sumKeys = 0;
+  std::string sumValues;
+  setupBenchmark(iters);
+
+  suspender.dismissing([&]() {
+    for (auto iter = bmMap.begin(); iter != bmMap.end(); ++iter) {
+      sumKeys += iter->first;
+      sumValues += iter->second;
+    }
+    doNotOptimizeAway(sumKeys);
+  });
+}
+
+BENCHMARK(ForEachFunctionAssign, iters) {
+  BenchmarkSuspender suspender;
+
+  int sumKeys = 0;
+  std::string sumValues;
+  setupBenchmark(iters);
+
+  suspender.dismissing([&]() {
+    folly::for_each(bmMap, [&](auto& key_val_pair) {
+      const int k = key_val_pair.first;
+      const std::string v = key_val_pair.second;
+      sumKeys += k;
+      sumValues += v;
+    });
+  });
+}
+
+BENCHMARK(StdForEachFunctionAssign, iters) {
+  BenchmarkSuspender suspender;
+
+  int sumKeys = 0;
+  std::string sumValues;
+  setupBenchmark(iters);
+
+  suspender.dismissing([&]() {
+    std::for_each(bmMap.begin(), bmMap.end(), [&](auto& key_val_pair) {
+      const int k = key_val_pair.first;
+      const std::string v = key_val_pair.second;
+      sumKeys += k;
+      sumValues += v;
+    });
+  });
+}
+
+BENCHMARK(RangeBasedForLoopAssign, iters) {
+  BenchmarkSuspender suspender;
+
+  int sumKeys = 0;
+  std::string sumValues;
+  setupBenchmark(iters);
+
+  suspender.dismissing([&]() {
+    for (auto& key_val_pair : bmMap) {
+      const int k = key_val_pair.first;
+      const std::string v = key_val_pair.second;
+      sumKeys += k;
+      sumValues += v;
+    }
+  });
+}
+
+BENCHMARK(ManualLoopAssign, iters) {
+  BenchmarkSuspender suspender;
+
+  int sumKeys = 0;
+  std::string sumValues;
+  setupBenchmark(iters);
+
+  suspender.dismissing([&]() {
+    for (auto iter = bmMap.begin(); iter != bmMap.end(); ++iter) {
+      const int k = iter->first;
+      const std::string v = iter->second;
+      sumKeys += k;
+      sumValues += v;
+    }
+  });
+}
+
+BENCHMARK(ForEachFunctionNoAssignWithIndexManipulation, iters) {
+  BenchmarkSuspender suspender;
+
+  int sumKeys = 0;
+  std::string sumValues;
+  setupBenchmark(iters);
+
+  suspender.dismissing([&]() {
+    folly::for_each(bmMap, [&](auto& key_val_pair, auto index) {
+      sumKeys += key_val_pair.first;
+      sumValues += key_val_pair.second;
+      sumValues += index;
+    });
+  });
+}
+
+BENCHMARK(StdForEachFunctionNoAssignWithIndexManipulation, iters) {
+  BenchmarkSuspender suspender;
+
+  int sumKeys = 0;
+  std::string sumValues;
+  setupBenchmark(iters);
+
+  suspender.dismissing([&]() {
+    auto index = std::size_t{0};
+    std::for_each(bmMap.begin(), bmMap.end(), [&](auto& key_val_pair) {
+      sumKeys += key_val_pair.first;
+      sumValues += key_val_pair.second;
+      sumValues += index;
+      ++index;
+    });
+  });
+}
+
+BENCHMARK(RangeBasedForLoopNoAssignWithIndexManipulation, iters) {
+  BenchmarkSuspender suspender;
+
+  int sumKeys = 0;
+  std::string sumValues;
+  setupBenchmark(iters);
+
+  suspender.dismissing([&]() {
+    auto index = std::size_t{0};
+    for (auto& key_val_pair : bmMap) {
+      sumKeys += key_val_pair.first;
+      sumValues += key_val_pair.second;
+      sumValues += index;
+    }
+  });
+}
+
+BENCHMARK(ForEachFunctionFetch, iters) {
+  BenchmarkSuspender suspender;
+  setupBenchmark(iters);
+
+  suspender.dismissing([&]() {
+    folly::for_each(bmMap, [&](auto& key_val_pair, auto index) {
+      folly::fetch(vec_one, index) = key_val_pair.first;
+    });
+  });
+}
+
+BENCHMARK(StdForEachFunctionFetch, iters) {
+  BenchmarkSuspender suspender;
+  setupBenchmark(iters);
+
+  suspender.dismissing([&]() {
+    auto index = std::size_t{0};
+    std::for_each(bmMap.begin(), bmMap.end(), [&](auto& key_val_pair) {
+      *(vec_one.begin() + index++) = key_val_pair.first;
+    });
+  });
+}
+
+BENCHMARK(ForLoopFetch, iters) {
+  BenchmarkSuspender suspender;
+  setupBenchmark(iters);
+
+  suspender.dismissing([&]() {
+    auto index = std::size_t{0};
+    for (auto& key_val_pair : bmMap) {
+      *(vec_one.begin() + index++) = key_val_pair.first;
+    }
+  });
+}
+
+BENCHMARK(ForEachKVNoMacroAssign, iters) {
+  int sumKeys = 0;
+  std::string sumValues;
+
+  BENCHMARK_SUSPEND { setupBenchmark(iters); }
+
+  FOR_EACH(iter, bmMap) {
+    const int k = iter->first;
+    const std::string v = iter->second;
+    sumKeys += k;
+    sumValues += v;
+  }
+}
+
+BENCHMARK(ForEachKVNoMacroNoAssign, iters) {
+  int sumKeys = 0;
+  std::string sumValues;
+
+  BENCHMARK_SUSPEND { setupBenchmark(iters); }
+
+  FOR_EACH(iter, bmMap) {
+    sumKeys += iter->first;
+    sumValues += iter->second;
+  }
+}
+
+BENCHMARK(ForEachKVMacro, iters) {
+  int sumKeys = 0;
+  std::string sumValues;
+
+  BENCHMARK_SUSPEND { setupBenchmark(iters); }
+
+  FOR_EACH_KV(k, v, bmMap) {
+    sumKeys += k;
+    sumValues += v;
+  }
+}
+
+BENCHMARK(ForEachManual, iters) {
+  int sum = 1;
+  for (size_t i = 1; i < iters; ++i) {
+    sum *= i;
+  }
+  doNotOptimizeAway(sum);
+}
+
+BENCHMARK(ForEachRange, iters) {
+  int sum = 1;
+  FOR_EACH_RANGE(i, 1, iters) { sum *= i; }
+  doNotOptimizeAway(sum);
+}
+
+BENCHMARK(ForEachDescendingManual, iters) {
+  int sum = 1;
+  for (size_t i = iters; i-- > 1;) {
+    sum *= i;
+  }
+  doNotOptimizeAway(sum);
+}
+
+BENCHMARK(ForEachRangeR, iters) {
+  int sum = 1;
+  FOR_EACH_RANGE_R(i, 1U, iters) { sum *= i; }
+  doNotOptimizeAway(sum);
+}
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  gflags::ParseCommandLineFlags(&argc, &argv, true);
+  auto r = RUN_ALL_TESTS();
+  if (r) {
+    return r;
+  }
+  runBenchmarks();
+  return 0;
+}