2 * Copyright 2012 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/experimental/Gen.h"
18 #include "folly/experimental/StringGen.h"
19 #include "folly/experimental/FileGen.h"
20 #include "folly/String.h"
25 #include <glog/logging.h>
27 #include "folly/Benchmark.h"
29 using namespace folly;
30 using namespace folly::gen;
37 static std::atomic<int> testSize(1000);
38 static vector<int> testVector =
39 seq(1, testSize.load())
40 | mapped([](int) { return rand(); })
42 static vector<vector<int>> testVectorVector =
45 return seq(1, i) | as<vector>();
49 auto square = [](int x) { return x * x; };
50 auto add = [](int a, int b) { return a + b; };
51 auto multiply = [](int a, int b) { return a * b; };
53 BENCHMARK(Sum_Basic_NoGen, iters) {
54 int limit = testSize.load();
57 for (int i = 0; i < limit; ++i) {
61 folly::doNotOptimizeAway(s);
64 BENCHMARK_RELATIVE(Sum_Basic_Gen, iters) {
65 int limit = testSize.load();
68 s += range(0, limit) | sum;
70 folly::doNotOptimizeAway(s);
75 BENCHMARK(Sum_Vector_NoGen, iters) {
78 for (auto& i : testVector) {
82 folly::doNotOptimizeAway(s);
85 BENCHMARK_RELATIVE(Sum_Vector_Gen, iters) {
88 s += from(testVector) | sum;
90 folly::doNotOptimizeAway(s);
95 BENCHMARK(Count_Vector_NoGen, iters) {
98 for (auto& i : testVector) {
104 folly::doNotOptimizeAway(s);
107 BENCHMARK_RELATIVE(Count_Vector_Gen, iters) {
110 s += from(testVector)
112 return i * 2 < rand();
116 folly::doNotOptimizeAway(s);
119 BENCHMARK_DRAW_LINE()
121 BENCHMARK(Fib_Sum_NoGen, iters) {
124 auto fib = [](int limit) -> vector<int> {
128 for (int i = 0; i * 2 < limit; ++i) {
129 ret.push_back(a += b);
130 ret.push_back(b += a);
134 for (auto& v : fib(testSize.load())) {
138 folly::doNotOptimizeAway(s);
141 BENCHMARK_RELATIVE(Fib_Sum_Gen, iters) {
144 auto fib = GENERATOR(int) {
152 s += fib | take(testSize.load()) | sum;
154 folly::doNotOptimizeAway(s);
158 template<class Yield>
159 void operator()(Yield&& yield) const {
169 BENCHMARK_RELATIVE(Fib_Sum_Gen_Static, iters) {
172 auto fib = generator<int>(FibYielder());
173 s += fib | take(testSize.load()) | sum;
175 folly::doNotOptimizeAway(s);
178 BENCHMARK_DRAW_LINE()
180 BENCHMARK(VirtualGen_0Virtual, iters) {
183 auto numbers = seq(1, 10000);
184 auto squares = numbers | map(square);
185 auto quads = squares | map(square);
188 folly::doNotOptimizeAway(s);
191 BENCHMARK_RELATIVE(VirtualGen_1Virtual, iters) {
194 VirtualGen<int> numbers = seq(1, 10000);
195 auto squares = numbers | map(square);
196 auto quads = squares | map(square);
199 folly::doNotOptimizeAway(s);
202 BENCHMARK_RELATIVE(VirtualGen_2Virtual, iters) {
205 VirtualGen<int> numbers = seq(1, 10000);
206 VirtualGen<int> squares = numbers | map(square);
207 auto quads = squares | map(square);
210 folly::doNotOptimizeAway(s);
213 BENCHMARK_RELATIVE(VirtualGen_3Virtual, iters) {
216 VirtualGen<int> numbers = seq(1, 10000);
217 VirtualGen<int> squares = numbers | map(square);
218 VirtualGen<int> quads = squares | map(square);
221 folly::doNotOptimizeAway(s);
224 BENCHMARK_DRAW_LINE()
226 BENCHMARK(Concat_NoGen, iters) {
229 for (auto& v : testVectorVector) {
235 folly::doNotOptimizeAway(s);
238 BENCHMARK_RELATIVE(Concat_Gen, iters) {
241 s += from(testVectorVector) | rconcat | sum;
243 folly::doNotOptimizeAway(s);
246 BENCHMARK_DRAW_LINE()
248 BENCHMARK(Composed_NoGen, iters) {
251 for (auto& i : testVector) {
255 folly::doNotOptimizeAway(s);
258 BENCHMARK_RELATIVE(Composed_Gen, iters) {
260 auto sumSq = map(square) | sum;
262 s += from(testVector) | sumSq;
264 folly::doNotOptimizeAway(s);
267 BENCHMARK_RELATIVE(Composed_GenRegular, iters) {
270 s += from(testVector) | map(square) | sum;
272 folly::doNotOptimizeAway(s);
275 BENCHMARK_DRAW_LINE()
279 const char* const kLine = "The quick brown fox jumped over the lazy dog.\n";
280 const size_t kLineCount = 10000;
281 std::string bigLines;
282 const size_t kSmallLineSize = 17;
283 std::vector<std::string> smallLines;
285 void initStringResplitterBenchmark() {
286 bigLines.reserve(kLineCount * strlen(kLine));
287 for (size_t i = 0; i < kLineCount; ++i) {
290 size_t remaining = bigLines.size();
293 size_t n = std::min(kSmallLineSize, remaining);
294 smallLines.push_back(bigLines.substr(pos, n));
300 size_t len(folly::StringPiece s) { return s.size(); }
304 BENCHMARK(StringResplitter_Big, iters) {
307 s += from({bigLines}) | resplit('\n') | map(&len) | sum;
309 folly::doNotOptimizeAway(s);
312 BENCHMARK_RELATIVE(StringResplitter_Small, iters) {
315 s += from(smallLines) | resplit('\n') | map(&len) | sum;
317 folly::doNotOptimizeAway(s);
320 BENCHMARK_DRAW_LINE()
322 BENCHMARK(StringSplit_Old, iters) {
324 std::string line(kLine);
326 std::vector<StringPiece> parts;
327 split(' ', line, parts);
330 folly::doNotOptimizeAway(s);
334 BENCHMARK_RELATIVE(StringSplit_Gen_Vector, iters) {
336 StringPiece line(kLine);
338 s += (split(line, ' ') | as<vector>()).size();
340 folly::doNotOptimizeAway(s);
343 BENCHMARK_DRAW_LINE()
345 BENCHMARK(StringSplit_Old_ReuseVector, iters) {
347 std::string line(kLine);
348 std::vector<StringPiece> parts;
351 split(' ', line, parts);
354 folly::doNotOptimizeAway(s);
357 BENCHMARK_RELATIVE(StringSplit_Gen_ReuseVector, iters) {
359 StringPiece line(kLine);
360 std::vector<StringPiece> parts;
363 split(line, ' ') | appendTo(parts);
366 folly::doNotOptimizeAway(s);
369 BENCHMARK_RELATIVE(StringSplit_Gen, iters) {
371 StringPiece line(kLine);
373 s += split(line, ' ') | count;
375 folly::doNotOptimizeAway(s);
378 BENCHMARK_RELATIVE(StringSplit_Gen_Take, iters) {
380 StringPiece line(kLine);
382 s += split(line, ' ') | take(10) | count;
384 folly::doNotOptimizeAway(s);
387 BENCHMARK_DRAW_LINE()
389 BENCHMARK(ByLine_Pipes, iters) {
395 CHECK_ERR(::pipe(p));
398 thread = std::thread([wfd, iters] {
400 PCHECK(::write(wfd, &x, 1) == 1); // signal startup
401 FILE* f = fdopen(wfd, "w");
403 for (int i = 1; i <= iters; ++i) {
404 fprintf(f, "%d\n", i);
409 PCHECK(::read(rfd, &buf, 1) == 1); // wait for startup
412 auto s = byLine(rfd) | eachTo<int64_t>() | sum;
413 folly::doNotOptimizeAway(s);
417 CHECK_EQ(s, int64_t(iters) * (iters + 1) / 2);
422 // Results from a dual core Xeon L5520 @ 2.27GHz:
424 // ============================================================================
425 // folly/experimental/test/GenBenchmark.cpp relative time/iter iters/s
426 // ============================================================================
427 // Sum_Basic_NoGen 293.77ns 3.40M
428 // Sum_Basic_Gen 100.24% 293.08ns 3.41M
429 // ----------------------------------------------------------------------------
430 // Sum_Vector_NoGen 199.09ns 5.02M
431 // Sum_Vector_Gen 98.57% 201.98ns 4.95M
432 // ----------------------------------------------------------------------------
433 // Count_Vector_NoGen 12.40us 80.66K
434 // Count_Vector_Gen 103.07% 12.03us 83.13K
435 // ----------------------------------------------------------------------------
436 // Fib_Sum_NoGen 3.65us 274.29K
437 // Fib_Sum_Gen 41.95% 8.69us 115.06K
438 // Fib_Sum_Gen_Static 86.10% 4.23us 236.15K
439 // ----------------------------------------------------------------------------
440 // VirtualGen_0Virtual 10.10us 99.03K
441 // VirtualGen_1Virtual 29.67% 34.04us 29.38K
442 // VirtualGen_2Virtual 20.53% 49.19us 20.33K
443 // VirtualGen_3Virtual 15.22% 66.36us 15.07K
444 // ----------------------------------------------------------------------------
445 // Concat_NoGen 2.33us 428.35K
446 // Concat_Gen 85.36% 2.74us 365.62K
447 // ----------------------------------------------------------------------------
448 // Composed_NoGen 552.78ns 1.81M
449 // Composed_Gen 100.48% 550.14ns 1.82M
450 // Composed_GenRegular 100.60% 549.50ns 1.82M
451 // ----------------------------------------------------------------------------
452 // StringResplitter_Big 118.40us 8.45K
453 // StringResplitter_Small 12.96% 913.23us 1.10K
454 // ----------------------------------------------------------------------------
455 // StringSplit_Old 567.61ns 1.76M
456 // StringSplit_Gen_Vector 146.52% 387.41ns 2.58M
457 // ----------------------------------------------------------------------------
458 // StringSplit_Old_ReuseVector 74.90ns 13.35M
459 // StringSplit_Gen_ReuseVector 112.29% 66.71ns 14.99M
460 // StringSplit_Gen 122.42% 61.18ns 16.34M
461 // StringSplit_Gen_Take 134.49% 55.70ns 17.95M
462 // ----------------------------------------------------------------------------
463 // ByLine_Pipes 131.18ns 7.62M
464 // ============================================================================
466 int main(int argc, char *argv[]) {
467 google::ParseCommandLineFlags(&argc, &argv, true);
468 initStringResplitterBenchmark();