2 * Copyright 2014 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/String.h>
21 #include <folly/gen/Base.h>
22 #include <folly/gen/String.h>
24 using namespace folly;
25 using namespace folly::gen;
33 static std::atomic<int> testSize(1000);
34 static vector<fbstring> testStrVector
35 = seq(1, testSize.load())
39 const char* const kLine = "The quick brown fox jumped over the lazy dog.\n";
40 const size_t kLineCount = 10000;
42 const size_t kSmallLineSize = 17;
43 std::vector<std::string> smallLines;
45 void initStringResplitterBenchmark() {
46 bigLines.reserve(kLineCount * strlen(kLine));
47 for (size_t i = 0; i < kLineCount; ++i) {
50 size_t remaining = bigLines.size();
53 size_t n = std::min(kSmallLineSize, remaining);
54 smallLines.push_back(bigLines.substr(pos, n));
60 size_t len(folly::StringPiece s) { return s.size(); }
64 BENCHMARK(StringResplitter_Big, iters) {
67 s += from({bigLines}) | resplit('\n') | map(&len) | sum;
69 folly::doNotOptimizeAway(s);
72 BENCHMARK_RELATIVE(StringResplitter_Small, iters) {
75 s += from(smallLines) | resplit('\n') | map(&len) | sum;
77 folly::doNotOptimizeAway(s);
82 BENCHMARK(StringSplit_Old, iters) {
84 std::string line(kLine);
86 std::vector<StringPiece> parts;
87 split(' ', line, parts);
90 folly::doNotOptimizeAway(s);
94 BENCHMARK_RELATIVE(StringSplit_Gen_Vector, iters) {
96 StringPiece line(kLine);
98 s += (split(line, ' ') | as<vector>()).size();
100 folly::doNotOptimizeAway(s);
103 BENCHMARK_DRAW_LINE()
105 BENCHMARK(StringSplit_Old_ReuseVector, iters) {
107 std::string line(kLine);
108 std::vector<StringPiece> parts;
111 split(' ', line, parts);
114 folly::doNotOptimizeAway(s);
117 BENCHMARK_RELATIVE(StringSplit_Gen_ReuseVector, iters) {
119 StringPiece line(kLine);
120 std::vector<StringPiece> parts;
123 split(line, ' ') | appendTo(parts);
126 folly::doNotOptimizeAway(s);
129 BENCHMARK_RELATIVE(StringSplit_Gen, iters) {
131 StringPiece line(kLine);
133 s += split(line, ' ') | count;
135 folly::doNotOptimizeAway(s);
138 BENCHMARK_RELATIVE(StringSplit_Gen_Take, iters) {
140 StringPiece line(kLine);
142 s += split(line, ' ') | take(10) | count;
144 folly::doNotOptimizeAway(s);
147 BENCHMARK_DRAW_LINE()
149 BENCHMARK(StringUnsplit_Old, iters) {
153 join(',', testStrVector, joined);
156 folly::doNotOptimizeAway(s);
159 BENCHMARK_RELATIVE(StringUnsplit_Old_ReusedBuffer, iters) {
164 join(',', testStrVector, joined);
167 folly::doNotOptimizeAway(s);
170 BENCHMARK_RELATIVE(StringUnsplit_Gen, iters) {
172 StringPiece line(kLine);
174 fbstring joined = from(testStrVector) | unsplit(',');
177 folly::doNotOptimizeAway(s);
180 BENCHMARK_RELATIVE(StringUnsplit_Gen_ReusedBuffer, iters) {
185 from(testStrVector) | unsplit(',', &buffer);
188 folly::doNotOptimizeAway(s);
191 BENCHMARK_DRAW_LINE()
193 void StringUnsplit_Gen(size_t iters, size_t joinSize) {
194 std::vector<fbstring> v;
196 FOR_EACH_RANGE(i, 0, joinSize) {
197 v.push_back(to<fbstring>(rand()));
204 from(v) | unsplit(',', &buffer);
207 folly::doNotOptimizeAway(s);
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)
215 BENCHMARK_DRAW_LINE()
218 = seq<size_t>(1, 1000)
219 | mapped([](size_t i) {
220 return folly::to<fbstring>(i, ' ', i * i, ' ', i * i * i);
224 BENCHMARK(Records_EachToTuple, iters) {
226 for (size_t i = 0; i < iters; i += 1000) {
227 s += split(records, '\n')
228 | eachToTuple<int, size_t, StringPiece>(' ')
232 folly::doNotOptimizeAway(s);
235 BENCHMARK_RELATIVE(Records_VectorStringPieceReused, iters) {
237 std::vector<StringPiece> fields;
238 for (size_t i = 0; i < iters; i += 1000) {
239 s += split(records, '\n')
240 | mapped([&](StringPiece line) {
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]));
252 folly::doNotOptimizeAway(s);
255 BENCHMARK_RELATIVE(Records_VectorStringPiece, iters) {
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]));
271 folly::doNotOptimizeAway(s);
274 BENCHMARK_RELATIVE(Records_VectorString, iters) {
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]));
290 folly::doNotOptimizeAway(s);
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 // ============================================================================
324 int main(int argc, char *argv[]) {
325 gflags::ParseCommandLineFlags(&argc, &argv, true);
326 initStringResplitterBenchmark();