gflags now likes namespace gflags, not google
[folly.git] / folly / gen / test / StringBenchmark.cpp
1 /*
2  * Copyright 2014 Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 #include <atomic>
17 #include <glog/logging.h>
18
19 #include <folly/Benchmark.h>
20 #include <folly/String.h>
21 #include <folly/gen/Base.h>
22 #include <folly/gen/String.h>
23
24 using namespace folly;
25 using namespace folly::gen;
26 using std::pair;
27 using std::set;
28 using std::vector;
29 using std::tuple;
30
31 namespace {
32
33 static std::atomic<int> testSize(1000);
34 static vector<fbstring> testStrVector
35   = seq(1, testSize.load())
36   | eachTo<fbstring>()
37   | as<vector>();
38
39 const char* const kLine = "The quick brown fox jumped over the lazy dog.\n";
40 const size_t kLineCount = 10000;
41 std::string bigLines;
42 const size_t kSmallLineSize = 17;
43 std::vector<std::string> smallLines;
44
45 void initStringResplitterBenchmark() {
46   bigLines.reserve(kLineCount * strlen(kLine));
47   for (size_t i = 0; i < kLineCount; ++i) {
48     bigLines += kLine;
49   }
50   size_t remaining = bigLines.size();
51   size_t pos = 0;
52   while (remaining) {
53     size_t n = std::min(kSmallLineSize, remaining);
54     smallLines.push_back(bigLines.substr(pos, n));
55     pos += n;
56     remaining -= n;
57   }
58 }
59
60 size_t len(folly::StringPiece s) { return s.size(); }
61
62 }  // namespace
63
64 BENCHMARK(StringResplitter_Big, iters) {
65   size_t s = 0;
66   while (iters--) {
67     s += from({bigLines}) | resplit('\n') | map(&len) | sum;
68   }
69   folly::doNotOptimizeAway(s);
70 }
71
72 BENCHMARK_RELATIVE(StringResplitter_Small, iters) {
73   size_t s = 0;
74   while (iters--) {
75     s += from(smallLines) | resplit('\n') | map(&len) | sum;
76   }
77   folly::doNotOptimizeAway(s);
78 }
79
80 BENCHMARK_DRAW_LINE()
81
82 BENCHMARK(StringSplit_Old, iters) {
83   size_t s = 0;
84   std::string line(kLine);
85   while (iters--) {
86     std::vector<StringPiece> parts;
87     split(' ', line, parts);
88     s += parts.size();
89   }
90   folly::doNotOptimizeAway(s);
91 }
92
93
94 BENCHMARK_RELATIVE(StringSplit_Gen_Vector, iters) {
95   size_t s = 0;
96   StringPiece line(kLine);
97   while (iters--) {
98     s += (split(line, ' ') | as<vector>()).size();
99   }
100   folly::doNotOptimizeAway(s);
101 }
102
103 BENCHMARK_DRAW_LINE()
104
105 BENCHMARK(StringSplit_Old_ReuseVector, iters) {
106   size_t s = 0;
107   std::string line(kLine);
108   std::vector<StringPiece> parts;
109   while (iters--) {
110     parts.clear();
111     split(' ', line, parts);
112     s += parts.size();
113   }
114   folly::doNotOptimizeAway(s);
115 }
116
117 BENCHMARK_RELATIVE(StringSplit_Gen_ReuseVector, iters) {
118   size_t s = 0;
119   StringPiece line(kLine);
120   std::vector<StringPiece> parts;
121   while (iters--) {
122     parts.clear();
123     split(line, ' ') | appendTo(parts);
124     s += parts.size();
125   }
126   folly::doNotOptimizeAway(s);
127 }
128
129 BENCHMARK_RELATIVE(StringSplit_Gen, iters) {
130   size_t s = 0;
131   StringPiece line(kLine);
132   while (iters--) {
133     s += split(line, ' ') | count;
134   }
135   folly::doNotOptimizeAway(s);
136 }
137
138 BENCHMARK_RELATIVE(StringSplit_Gen_Take, iters) {
139   size_t s = 0;
140   StringPiece line(kLine);
141   while (iters--) {
142     s += split(line, ' ') | take(10) | count;
143   }
144   folly::doNotOptimizeAway(s);
145 }
146
147 BENCHMARK_DRAW_LINE()
148
149 BENCHMARK(StringUnsplit_Old, iters) {
150   size_t s = 0;
151   while (iters--) {
152     fbstring joined;
153     join(',', testStrVector, joined);
154     s += joined.size();
155   }
156   folly::doNotOptimizeAway(s);
157 }
158
159 BENCHMARK_RELATIVE(StringUnsplit_Old_ReusedBuffer, iters) {
160   size_t s = 0;
161   fbstring joined;
162   while (iters--) {
163     joined.clear();
164     join(',', testStrVector, joined);
165     s += joined.size();
166   }
167   folly::doNotOptimizeAway(s);
168 }
169
170 BENCHMARK_RELATIVE(StringUnsplit_Gen, iters) {
171   size_t s = 0;
172   StringPiece line(kLine);
173   while (iters--) {
174     fbstring joined = from(testStrVector) | unsplit(',');
175     s += joined.size();
176   }
177   folly::doNotOptimizeAway(s);
178 }
179
180 BENCHMARK_RELATIVE(StringUnsplit_Gen_ReusedBuffer, iters) {
181   size_t s = 0;
182   fbstring buffer;
183   while (iters--) {
184     buffer.clear();
185     from(testStrVector) | unsplit(',', &buffer);
186     s += buffer.size();
187   }
188   folly::doNotOptimizeAway(s);
189 }
190
191 BENCHMARK_DRAW_LINE()
192
193 void StringUnsplit_Gen(size_t iters, size_t joinSize) {
194   std::vector<fbstring> v;
195   BENCHMARK_SUSPEND {
196     FOR_EACH_RANGE(i, 0, joinSize) {
197       v.push_back(to<fbstring>(rand()));
198     }
199   }
200   size_t s = 0;
201   fbstring buffer;
202   while (iters--) {
203     buffer.clear();
204     from(v) | unsplit(',', &buffer);
205     s += buffer.size();
206   }
207   folly::doNotOptimizeAway(s);
208 }
209
210 BENCHMARK_PARAM(StringUnsplit_Gen, 1000)
211 BENCHMARK_RELATIVE_PARAM(StringUnsplit_Gen, 2000)
212 BENCHMARK_RELATIVE_PARAM(StringUnsplit_Gen, 4000)
213 BENCHMARK_RELATIVE_PARAM(StringUnsplit_Gen, 8000)
214
215 BENCHMARK_DRAW_LINE()
216
217 fbstring records
218 = seq<size_t>(1, 1000)
219   | mapped([](size_t i) {
220       return folly::to<fbstring>(i, ' ', i * i, ' ', i * i * i);
221     })
222   | unsplit('\n');
223
224 BENCHMARK(Records_EachToTuple, iters) {
225   size_t s = 0;
226   for (size_t i = 0; i < iters; i += 1000) {
227     s += split(records, '\n')
228        | eachToTuple<int, size_t, StringPiece>(' ')
229        | get<1>()
230        | sum;
231   }
232   folly::doNotOptimizeAway(s);
233 }
234
235 BENCHMARK_RELATIVE(Records_VectorStringPieceReused, iters) {
236   size_t s = 0;
237   std::vector<StringPiece> fields;
238   for (size_t i = 0; i < iters; i += 1000) {
239     s += split(records, '\n')
240        | mapped([&](StringPiece line) {
241            fields.clear();
242            folly::split(' ', line, fields);
243            CHECK(fields.size() == 3);
244            return std::make_tuple(
245              folly::to<int>(fields[0]),
246              folly::to<size_t>(fields[1]),
247              StringPiece(fields[2]));
248          })
249        | get<1>()
250        | sum;
251   }
252   folly::doNotOptimizeAway(s);
253 }
254
255 BENCHMARK_RELATIVE(Records_VectorStringPiece, iters) {
256   size_t s = 0;
257   for (size_t i = 0; i < iters; i += 1000) {
258     s += split(records, '\n')
259        | mapped([](StringPiece line) {
260            std::vector<StringPiece> fields;
261            folly::split(' ', line, fields);
262            CHECK(fields.size() == 3);
263            return std::make_tuple(
264              folly::to<int>(fields[0]),
265              folly::to<size_t>(fields[1]),
266              StringPiece(fields[2]));
267          })
268        | get<1>()
269        | sum;
270   }
271   folly::doNotOptimizeAway(s);
272 }
273
274 BENCHMARK_RELATIVE(Records_VectorString, iters) {
275   size_t s = 0;
276   for (size_t i = 0; i < iters; i += 1000) {
277     s += split(records, '\n')
278        | mapped([](StringPiece line) {
279            std::vector<std::string> fields;
280            folly::split(' ', line, fields);
281            CHECK(fields.size() == 3);
282            return std::make_tuple(
283              folly::to<int>(fields[0]),
284              folly::to<size_t>(fields[1]),
285              StringPiece(fields[2]));
286          })
287        | get<1>()
288        | sum;
289   }
290   folly::doNotOptimizeAway(s);
291 }
292
293 // Results from an Intel(R) Xeon(R) CPU E5-2660 0 @ 2.20GHz
294 // ============================================================================
295 // folly/gen/test/StringBenchmark.cpp              relative  time/iter  iters/s
296 // ============================================================================
297 // StringResplitter_Big                                       108.58us    9.21K
298 // StringResplitter_Small                            10.60%     1.02ms   976.48
299 // ----------------------------------------------------------------------------
300 // StringSplit_Old                                            357.82ns    2.79M
301 // StringSplit_Gen_Vector                           105.10%   340.46ns    2.94M
302 // ----------------------------------------------------------------------------
303 // StringSplit_Old_ReuseVector                                 96.45ns   10.37M
304 // StringSplit_Gen_ReuseVector                      124.01%    77.78ns   12.86M
305 // StringSplit_Gen                                  140.10%    68.85ns   14.52M
306 // StringSplit_Gen_Take                             122.97%    78.44ns   12.75M
307 // ----------------------------------------------------------------------------
308 // StringUnsplit_Old                                           42.99us   23.26K
309 // StringUnsplit_Old_ReusedBuffer                   100.48%    42.79us   23.37K
310 // StringUnsplit_Gen                                 96.37%    44.61us   22.42K
311 // StringUnsplit_Gen_ReusedBuffer                   116.96%    36.76us   27.20K
312 // ----------------------------------------------------------------------------
313 // StringUnsplit_Gen(1000)                                     44.71us   22.37K
314 // StringUnsplit_Gen(2000)                           49.28%    90.72us   11.02K
315 // StringUnsplit_Gen(4000)                           24.05%   185.91us    5.38K
316 // StringUnsplit_Gen(8000)                           12.23%   365.42us    2.74K
317 // ----------------------------------------------------------------------------
318 // Records_EachToTuple                                        101.43us    9.86K
319 // Records_VectorStringPieceReused                   93.72%   108.22us    9.24K
320 // Records_VectorStringPiece                         37.14%   273.11us    3.66K
321 // Records_VectorString                              16.70%   607.47us    1.65K
322 // ============================================================================
323
324 int main(int argc, char *argv[]) {
325   gflags::ParseCommandLineFlags(&argc, &argv, true);
326   initStringResplitterBenchmark();
327   runBenchmarks();
328   return 0;
329 }