2 * Copyright 2013 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(); })
43 static vector<fbstring> testStrVector =
44 seq(1, testSize.load())
48 static vector<vector<int>> testVectorVector =
51 return seq(1, i) | as<vector>();
55 auto square = [](int x) { return x * x; };
56 auto add = [](int a, int b) { return a + b; };
57 auto multiply = [](int a, int b) { return a * b; };
59 BENCHMARK(Sum_Basic_NoGen, iters) {
60 int limit = testSize.load();
63 for (int i = 0; i < limit; ++i) {
67 folly::doNotOptimizeAway(s);
70 BENCHMARK_RELATIVE(Sum_Basic_Gen, iters) {
71 int limit = testSize.load();
74 s += range(0, limit) | sum;
76 folly::doNotOptimizeAway(s);
81 BENCHMARK(Sum_Vector_NoGen, iters) {
84 for (auto& i : testVector) {
88 folly::doNotOptimizeAway(s);
91 BENCHMARK_RELATIVE(Sum_Vector_Gen, iters) {
94 s += from(testVector) | sum;
96 folly::doNotOptimizeAway(s);
101 BENCHMARK(Count_Vector_NoGen, iters) {
104 for (auto& i : testVector) {
105 if (i * 2 < rand()) {
110 folly::doNotOptimizeAway(s);
113 BENCHMARK_RELATIVE(Count_Vector_Gen, iters) {
116 s += from(testVector)
118 return i * 2 < rand();
122 folly::doNotOptimizeAway(s);
125 BENCHMARK_DRAW_LINE()
127 BENCHMARK(Fib_Sum_NoGen, iters) {
130 auto fib = [](int limit) -> vector<int> {
134 for (int i = 0; i * 2 < limit; ++i) {
135 ret.push_back(a += b);
136 ret.push_back(b += a);
140 for (auto& v : fib(testSize.load())) {
144 folly::doNotOptimizeAway(s);
147 BENCHMARK_RELATIVE(Fib_Sum_Gen, iters) {
150 auto fib = GENERATOR(int) {
158 s += fib | take(testSize.load()) | sum;
160 folly::doNotOptimizeAway(s);
164 template<class Yield>
165 void operator()(Yield&& yield) const {
175 BENCHMARK_RELATIVE(Fib_Sum_Gen_Static, iters) {
178 auto fib = generator<int>(FibYielder());
179 s += fib | take(testSize.load()) | sum;
181 folly::doNotOptimizeAway(s);
184 BENCHMARK_DRAW_LINE()
186 BENCHMARK(VirtualGen_0Virtual, iters) {
189 auto numbers = seq(1, 10000);
190 auto squares = numbers | map(square);
191 auto quads = squares | map(square);
194 folly::doNotOptimizeAway(s);
197 BENCHMARK_RELATIVE(VirtualGen_1Virtual, iters) {
200 VirtualGen<int> numbers = seq(1, 10000);
201 auto squares = numbers | map(square);
202 auto quads = squares | map(square);
205 folly::doNotOptimizeAway(s);
208 BENCHMARK_RELATIVE(VirtualGen_2Virtual, iters) {
211 VirtualGen<int> numbers = seq(1, 10000);
212 VirtualGen<int> squares = numbers | map(square);
213 auto quads = squares | map(square);
216 folly::doNotOptimizeAway(s);
219 BENCHMARK_RELATIVE(VirtualGen_3Virtual, iters) {
222 VirtualGen<int> numbers = seq(1, 10000);
223 VirtualGen<int> squares = numbers | map(square);
224 VirtualGen<int> quads = squares | map(square);
227 folly::doNotOptimizeAway(s);
230 BENCHMARK_DRAW_LINE()
232 BENCHMARK(Concat_NoGen, iters) {
235 for (auto& v : testVectorVector) {
241 folly::doNotOptimizeAway(s);
244 BENCHMARK_RELATIVE(Concat_Gen, iters) {
247 s += from(testVectorVector) | rconcat | sum;
249 folly::doNotOptimizeAway(s);
252 BENCHMARK_DRAW_LINE()
254 BENCHMARK(Composed_NoGen, iters) {
257 for (auto& i : testVector) {
261 folly::doNotOptimizeAway(s);
264 BENCHMARK_RELATIVE(Composed_Gen, iters) {
266 auto sumSq = map(square) | sum;
268 s += from(testVector) | sumSq;
270 folly::doNotOptimizeAway(s);
273 BENCHMARK_RELATIVE(Composed_GenRegular, iters) {
276 s += from(testVector) | map(square) | sum;
278 folly::doNotOptimizeAway(s);
281 BENCHMARK_DRAW_LINE()
283 BENCHMARK(Sample, iters) {
286 auto sampler = seq(1, 10 * 1000 * 1000) | sample(1000);
287 s += (sampler | sum);
289 folly::doNotOptimizeAway(s);
292 BENCHMARK_DRAW_LINE()
296 const char* const kLine = "The quick brown fox jumped over the lazy dog.\n";
297 const size_t kLineCount = 10000;
298 std::string bigLines;
299 const size_t kSmallLineSize = 17;
300 std::vector<std::string> smallLines;
302 void initStringResplitterBenchmark() {
303 bigLines.reserve(kLineCount * strlen(kLine));
304 for (size_t i = 0; i < kLineCount; ++i) {
307 size_t remaining = bigLines.size();
310 size_t n = std::min(kSmallLineSize, remaining);
311 smallLines.push_back(bigLines.substr(pos, n));
317 size_t len(folly::StringPiece s) { return s.size(); }
321 BENCHMARK(StringResplitter_Big, iters) {
324 s += from({bigLines}) | resplit('\n') | map(&len) | sum;
326 folly::doNotOptimizeAway(s);
329 BENCHMARK_RELATIVE(StringResplitter_Small, iters) {
332 s += from(smallLines) | resplit('\n') | map(&len) | sum;
334 folly::doNotOptimizeAway(s);
337 BENCHMARK_DRAW_LINE()
339 BENCHMARK(StringSplit_Old, iters) {
341 std::string line(kLine);
343 std::vector<StringPiece> parts;
344 split(' ', line, parts);
347 folly::doNotOptimizeAway(s);
351 BENCHMARK_RELATIVE(StringSplit_Gen_Vector, iters) {
353 StringPiece line(kLine);
355 s += (split(line, ' ') | as<vector>()).size();
357 folly::doNotOptimizeAway(s);
360 BENCHMARK_DRAW_LINE()
362 BENCHMARK(StringSplit_Old_ReuseVector, iters) {
364 std::string line(kLine);
365 std::vector<StringPiece> parts;
368 split(' ', line, parts);
371 folly::doNotOptimizeAway(s);
374 BENCHMARK_RELATIVE(StringSplit_Gen_ReuseVector, iters) {
376 StringPiece line(kLine);
377 std::vector<StringPiece> parts;
380 split(line, ' ') | appendTo(parts);
383 folly::doNotOptimizeAway(s);
386 BENCHMARK_RELATIVE(StringSplit_Gen, iters) {
388 StringPiece line(kLine);
390 s += split(line, ' ') | count;
392 folly::doNotOptimizeAway(s);
395 BENCHMARK_RELATIVE(StringSplit_Gen_Take, iters) {
397 StringPiece line(kLine);
399 s += split(line, ' ') | take(10) | count;
401 folly::doNotOptimizeAway(s);
404 BENCHMARK_DRAW_LINE()
406 BENCHMARK(StringUnsplit_Old, iters) {
410 join(',', testStrVector, joined);
413 folly::doNotOptimizeAway(s);
416 BENCHMARK_RELATIVE(StringUnsplit_Old_ReusedBuffer, iters) {
421 join(',', testStrVector, joined);
424 folly::doNotOptimizeAway(s);
427 BENCHMARK_RELATIVE(StringUnsplit_Gen, iters) {
429 StringPiece line(kLine);
431 fbstring joined = from(testStrVector) | unsplit(',');
434 folly::doNotOptimizeAway(s);
437 BENCHMARK_RELATIVE(StringUnsplit_Gen_ReusedBuffer, iters) {
442 from(testStrVector) | unsplit(',', &buffer);
445 folly::doNotOptimizeAway(s);
448 BENCHMARK_DRAW_LINE()
450 void StringUnsplit_Gen(size_t iters, size_t joinSize) {
451 std::vector<fbstring> v;
453 FOR_EACH_RANGE(i, 0, joinSize) {
454 v.push_back(to<fbstring>(rand()));
461 from(v) | unsplit(',', &buffer);
464 folly::doNotOptimizeAway(s);
467 BENCHMARK_DRAW_LINE()
469 BENCHMARK_PARAM(StringUnsplit_Gen, 1000)
470 BENCHMARK_RELATIVE_PARAM(StringUnsplit_Gen, 2000)
471 BENCHMARK_RELATIVE_PARAM(StringUnsplit_Gen, 4000)
472 BENCHMARK_RELATIVE_PARAM(StringUnsplit_Gen, 8000)
474 BENCHMARK_DRAW_LINE()
476 BENCHMARK(ByLine_Pipes, iters) {
482 CHECK_ERR(::pipe(p));
485 thread = std::thread([wfd, iters] {
487 PCHECK(::write(wfd, &x, 1) == 1); // signal startup
488 FILE* f = fdopen(wfd, "w");
490 for (int i = 1; i <= iters; ++i) {
491 fprintf(f, "%d\n", i);
496 PCHECK(::read(rfd, &buf, 1) == 1); // wait for startup
499 auto s = byLine(rfd) | eachTo<int64_t>() | sum;
500 folly::doNotOptimizeAway(s);
504 CHECK_EQ(s, int64_t(iters) * (iters + 1) / 2);
509 // Results from a dual core Xeon L5520 @ 2.27GHz:
511 // ============================================================================
512 // folly/experimental/test/GenBenchmark.cpp relative time/iter iters/s
513 // ============================================================================
514 // Sum_Basic_NoGen 354.70ns 2.82M
515 // Sum_Basic_Gen 95.88% 369.92ns 2.70M
516 // ----------------------------------------------------------------------------
517 // Sum_Vector_NoGen 211.89ns 4.72M
518 // Sum_Vector_Gen 97.49% 217.35ns 4.60M
519 // ----------------------------------------------------------------------------
520 // Count_Vector_NoGen 13.93us 71.78K
521 // Count_Vector_Gen 106.38% 13.10us 76.36K
522 // ----------------------------------------------------------------------------
523 // Fib_Sum_NoGen 4.54us 220.07K
524 // Fib_Sum_Gen 45.81% 9.92us 100.82K
525 // Fib_Sum_Gen_Static 100.00% 4.54us 220.05K
526 // ----------------------------------------------------------------------------
527 // VirtualGen_0Virtual 12.03us 83.14K
528 // VirtualGen_1Virtual 32.89% 36.57us 27.34K
529 // VirtualGen_2Virtual 24.98% 48.15us 20.77K
530 // VirtualGen_3Virtual 17.82% 67.49us 14.82K
531 // ----------------------------------------------------------------------------
532 // Concat_NoGen 1.92us 520.46K
533 // Concat_Gen 102.79% 1.87us 534.97K
534 // ----------------------------------------------------------------------------
535 // Composed_NoGen 545.64ns 1.83M
536 // Composed_Gen 99.65% 547.55ns 1.83M
537 // Composed_GenRegular 99.64% 547.62ns 1.83M
538 // ----------------------------------------------------------------------------
539 // StringResplitter_Big 120.88us 8.27K
540 // StringResplitter_Small 14.39% 839.94us 1.19K
541 // ----------------------------------------------------------------------------
542 // StringSplit_Old 421.09ns 2.37M
543 // StringSplit_Gen_Vector 97.73% 430.87ns 2.32M
544 // ----------------------------------------------------------------------------
545 // StringSplit_Old_ReuseVector 80.25ns 12.46M
546 // StringSplit_Gen_ReuseVector 98.99% 81.07ns 12.34M
547 // StringSplit_Gen 117.23% 68.45ns 14.61M
548 // StringSplit_Gen_Take 115.23% 69.64ns 14.36M
549 // ----------------------------------------------------------------------------
550 // StringUnsplit_Old 34.45us 29.02K
551 // StringUnsplit_Old_ReusedBuffer 100.37% 34.33us 29.13K
552 // StringUnsplit_Gen 106.27% 32.42us 30.84K
553 // StringUnsplit_Gen_ReusedBuffer 105.61% 32.62us 30.65K
554 // ----------------------------------------------------------------------------
555 // ----------------------------------------------------------------------------
556 // StringUnsplit_Gen(1000) 32.20us 31.06K
557 // StringUnsplit_Gen(2000) 49.41% 65.17us 15.34K
558 // StringUnsplit_Gen(4000) 22.75% 141.52us 7.07K
559 // StringUnsplit_Gen(8000) 11.20% 287.53us 3.48K
560 // ----------------------------------------------------------------------------
561 // ByLine_Pipes 126.58ns 7.90M
562 // ============================================================================
564 int main(int argc, char *argv[]) {
565 google::ParseCommandLineFlags(&argc, &argv, true);
566 initStringResplitterBenchmark();