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 <glog/logging.h>
19 #include <folly/Benchmark.h>
20 #include <folly/Foreach.h>
21 #include <folly/String.h>
22 #include <folly/gen/Base.h>
23 #include <folly/gen/String.h>
25 using namespace folly;
26 using namespace folly::gen;
34 static std::atomic<int> testSize(1000);
35 static vector<fbstring> testStrVector
36 = seq(1, testSize.load())
39 static auto testFileContent = from(testStrVector) | unsplit('\n');
41 const char* const kLine = "The quick brown fox jumped over the lazy dog.\n";
42 const size_t kLineCount = 10000;
44 const size_t kSmallLineSize = 17;
45 std::vector<std::string> smallLines;
47 void initStringResplitterBenchmark() {
48 bigLines.reserve(kLineCount * strlen(kLine));
49 for (size_t i = 0; i < kLineCount; ++i) {
52 size_t remaining = bigLines.size();
55 size_t n = std::min(kSmallLineSize, remaining);
56 smallLines.push_back(bigLines.substr(pos, n));
62 size_t len(folly::StringPiece s) { return s.size(); }
66 BENCHMARK(StringResplitter_Big, iters) {
69 s += from({bigLines}) | resplit('\n') | map(&len) | sum;
71 folly::doNotOptimizeAway(s);
74 BENCHMARK_RELATIVE(StringResplitter_Small, iters) {
77 s += from(smallLines) | resplit('\n') | map(&len) | sum;
79 folly::doNotOptimizeAway(s);
84 BENCHMARK(StringSplit_Old, iters) {
86 std::string line(kLine);
88 std::vector<StringPiece> parts;
89 split(' ', line, parts);
92 folly::doNotOptimizeAway(s);
96 BENCHMARK_RELATIVE(StringSplit_Gen_Vector, iters) {
98 StringPiece line(kLine);
100 s += (split(line, ' ') | as<vector>()).size();
102 folly::doNotOptimizeAway(s);
105 BENCHMARK_DRAW_LINE()
107 BENCHMARK(StringSplit_Old_ReuseVector, iters) {
109 std::string line(kLine);
110 std::vector<StringPiece> parts;
113 split(' ', line, parts);
116 folly::doNotOptimizeAway(s);
119 BENCHMARK_RELATIVE(StringSplit_Gen_ReuseVector, iters) {
121 StringPiece line(kLine);
122 std::vector<StringPiece> parts;
125 split(line, ' ') | appendTo(parts);
128 folly::doNotOptimizeAway(s);
131 BENCHMARK_RELATIVE(StringSplit_Gen, iters) {
133 StringPiece line(kLine);
135 s += split(line, ' ') | count;
137 folly::doNotOptimizeAway(s);
140 BENCHMARK_RELATIVE(StringSplit_Gen_Take, iters) {
142 StringPiece line(kLine);
144 s += split(line, ' ') | take(10) | count;
146 folly::doNotOptimizeAway(s);
149 BENCHMARK_DRAW_LINE()
151 BENCHMARK(StringUnsplit_Old, iters) {
155 join(',', testStrVector, joined);
158 folly::doNotOptimizeAway(s);
161 BENCHMARK_RELATIVE(StringUnsplit_Old_ReusedBuffer, iters) {
166 join(',', testStrVector, joined);
169 folly::doNotOptimizeAway(s);
172 BENCHMARK_RELATIVE(StringUnsplit_Gen, iters) {
174 StringPiece line(kLine);
176 fbstring joined = from(testStrVector) | unsplit(',');
179 folly::doNotOptimizeAway(s);
182 BENCHMARK_RELATIVE(StringUnsplit_Gen_ReusedBuffer, iters) {
187 from(testStrVector) | unsplit(',', &buffer);
190 folly::doNotOptimizeAway(s);
193 BENCHMARK_DRAW_LINE()
195 void StringUnsplit_Gen(size_t iters, size_t joinSize) {
196 std::vector<fbstring> v;
198 FOR_EACH_RANGE(i, 0, joinSize) {
199 v.push_back(to<fbstring>(rand()));
206 from(v) | unsplit(',', &buffer);
209 folly::doNotOptimizeAway(s);
212 BENCHMARK_PARAM(StringUnsplit_Gen, 1000)
213 BENCHMARK_RELATIVE_PARAM(StringUnsplit_Gen, 2000)
214 BENCHMARK_RELATIVE_PARAM(StringUnsplit_Gen, 4000)
215 BENCHMARK_RELATIVE_PARAM(StringUnsplit_Gen, 8000)
217 BENCHMARK_DRAW_LINE()
218 void Lines_Gen(size_t iters, int joinSize) {
220 StringPiece content = testFileContent;
221 for (size_t i = 0; i < iters; ++i) {
222 s += lines(content.subpiece(0, joinSize)) | take(100) | count;
224 folly::doNotOptimizeAway(s);
227 BENCHMARK_PARAM(Lines_Gen, 1e3)
228 BENCHMARK_RELATIVE_PARAM(Lines_Gen, 2e3)
229 BENCHMARK_RELATIVE_PARAM(Lines_Gen, 3e3)
231 BENCHMARK_DRAW_LINE()
234 = seq<size_t>(1, 1000)
235 | mapped([](size_t i) {
236 return folly::to<fbstring>(i, ' ', i * i, ' ', i * i * i);
240 BENCHMARK(Records_EachToTuple, iters) {
242 for (size_t i = 0; i < iters; i += 1000) {
243 s += split(records, '\n')
244 | eachToTuple<int, size_t, StringPiece>(' ')
248 folly::doNotOptimizeAway(s);
251 BENCHMARK_RELATIVE(Records_VectorStringPieceReused, iters) {
253 std::vector<StringPiece> fields;
254 for (size_t i = 0; i < iters; i += 1000) {
255 s += split(records, '\n')
256 | mapped([&](StringPiece line) {
258 folly::split(' ', line, fields);
259 CHECK(fields.size() == 3);
260 return std::make_tuple(
261 folly::to<int>(fields[0]),
262 folly::to<size_t>(fields[1]),
263 StringPiece(fields[2]));
268 folly::doNotOptimizeAway(s);
271 BENCHMARK_RELATIVE(Records_VectorStringPiece, iters) {
273 for (size_t i = 0; i < iters; i += 1000) {
274 s += split(records, '\n')
275 | mapped([](StringPiece line) {
276 std::vector<StringPiece> fields;
277 folly::split(' ', line, fields);
278 CHECK(fields.size() == 3);
279 return std::make_tuple(
280 folly::to<int>(fields[0]),
281 folly::to<size_t>(fields[1]),
282 StringPiece(fields[2]));
287 folly::doNotOptimizeAway(s);
290 BENCHMARK_RELATIVE(Records_VectorString, iters) {
292 for (size_t i = 0; i < iters; i += 1000) {
293 s += split(records, '\n')
294 | mapped([](StringPiece line) {
295 std::vector<std::string> fields;
296 folly::split(' ', line, fields);
297 CHECK(fields.size() == 3);
298 return std::make_tuple(
299 folly::to<int>(fields[0]),
300 folly::to<size_t>(fields[1]),
301 StringPiece(fields[2]));
306 folly::doNotOptimizeAway(s);
309 // Results from an Intel(R) Xeon(R) CPU E5-2660 0 @ 2.20GHz
310 // ============================================================================
311 // folly/gen/test/StringBenchmark.cpp relative time/iter iters/s
312 // ============================================================================
313 // StringResplitter_Big 108.58us 9.21K
314 // StringResplitter_Small 10.60% 1.02ms 976.48
315 // ----------------------------------------------------------------------------
316 // StringSplit_Old 357.82ns 2.79M
317 // StringSplit_Gen_Vector 105.10% 340.46ns 2.94M
318 // ----------------------------------------------------------------------------
319 // StringSplit_Old_ReuseVector 96.45ns 10.37M
320 // StringSplit_Gen_ReuseVector 124.01% 77.78ns 12.86M
321 // StringSplit_Gen 140.10% 68.85ns 14.52M
322 // StringSplit_Gen_Take 122.97% 78.44ns 12.75M
323 // ----------------------------------------------------------------------------
324 // StringUnsplit_Old 42.99us 23.26K
325 // StringUnsplit_Old_ReusedBuffer 100.48% 42.79us 23.37K
326 // StringUnsplit_Gen 96.37% 44.61us 22.42K
327 // StringUnsplit_Gen_ReusedBuffer 116.96% 36.76us 27.20K
328 // ----------------------------------------------------------------------------
329 // StringUnsplit_Gen(1000) 44.71us 22.37K
330 // StringUnsplit_Gen(2000) 49.28% 90.72us 11.02K
331 // StringUnsplit_Gen(4000) 24.05% 185.91us 5.38K
332 // StringUnsplit_Gen(8000) 12.23% 365.42us 2.74K
333 // ----------------------------------------------------------------------------
334 // Records_EachToTuple 101.43us 9.86K
335 // Records_VectorStringPieceReused 93.72% 108.22us 9.24K
336 // Records_VectorStringPiece 37.14% 273.11us 3.66K
337 // Records_VectorString 16.70% 607.47us 1.65K
338 // ============================================================================
340 int main(int argc, char *argv[]) {
341 gflags::ParseCommandLineFlags(&argc, &argv, true);
342 initStringResplitterBenchmark();