/* * Copyright 2014-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include using namespace folly; using namespace folly::gen; using std::pair; using std::set; using std::tuple; using std::vector; namespace { static std::atomic testSize(1000); static vector testStrVector = seq(1, testSize.load()) | eachTo() | as(); static auto testFileContent = from(testStrVector) | unsplit('\n'); const char* const kLine = "The quick brown fox jumped over the lazy dog.\n"; const size_t kLineCount = 10000; std::string bigLines; const size_t kSmallLineSize = 17; std::vector smallLines; void initStringResplitterBenchmark() { bigLines.reserve(kLineCount * strlen(kLine)); for (size_t i = 0; i < kLineCount; ++i) { bigLines += kLine; } size_t remaining = bigLines.size(); size_t pos = 0; while (remaining) { size_t n = std::min(kSmallLineSize, remaining); smallLines.push_back(bigLines.substr(pos, n)); pos += n; remaining -= n; } } size_t len(folly::StringPiece s) { return s.size(); } } // namespace BENCHMARK(StringResplitter_Big, iters) { size_t s = 0; while (iters--) { s += from({bigLines}) | resplit('\n') | map(&len) | sum; } folly::doNotOptimizeAway(s); } BENCHMARK_RELATIVE(StringResplitter_Small, iters) { size_t s = 0; while (iters--) { s += from(smallLines) | resplit('\n') | map(&len) | sum; } folly::doNotOptimizeAway(s); } BENCHMARK_DRAW_LINE(); BENCHMARK(StringSplit_Old, iters) { size_t s = 0; std::string line(kLine); while (iters--) { std::vector parts; split(' ', line, parts); s += parts.size(); } folly::doNotOptimizeAway(s); } BENCHMARK_RELATIVE(StringSplit_Gen_Vector, iters) { size_t s = 0; StringPiece line(kLine); while (iters--) { s += (split(line, ' ') | as()).size(); } folly::doNotOptimizeAway(s); } BENCHMARK_DRAW_LINE(); BENCHMARK(StringSplit_Old_ReuseVector, iters) { size_t s = 0; std::string line(kLine); std::vector parts; while (iters--) { parts.clear(); split(' ', line, parts); s += parts.size(); } folly::doNotOptimizeAway(s); } BENCHMARK_RELATIVE(StringSplit_Gen_ReuseVector, iters) { size_t s = 0; StringPiece line(kLine); std::vector parts; while (iters--) { parts.clear(); split(line, ' ') | appendTo(parts); s += parts.size(); } folly::doNotOptimizeAway(s); } BENCHMARK_RELATIVE(StringSplit_Gen, iters) { size_t s = 0; StringPiece line(kLine); while (iters--) { s += split(line, ' ') | count; } folly::doNotOptimizeAway(s); } BENCHMARK_RELATIVE(StringSplit_Gen_Take, iters) { size_t s = 0; StringPiece line(kLine); while (iters--) { s += split(line, ' ') | take(10) | count; } folly::doNotOptimizeAway(s); } BENCHMARK_DRAW_LINE(); BENCHMARK(StringUnsplit_Old, iters) { size_t s = 0; while (iters--) { fbstring joined; join(',', testStrVector, joined); s += joined.size(); } folly::doNotOptimizeAway(s); } BENCHMARK_RELATIVE(StringUnsplit_Old_ReusedBuffer, iters) { size_t s = 0; fbstring joined; while (iters--) { joined.clear(); join(',', testStrVector, joined); s += joined.size(); } folly::doNotOptimizeAway(s); } BENCHMARK_RELATIVE(StringUnsplit_Gen, iters) { size_t s = 0; while (iters--) { fbstring joined = from(testStrVector) | unsplit(','); s += joined.size(); } folly::doNotOptimizeAway(s); } BENCHMARK_RELATIVE(StringUnsplit_Gen_ReusedBuffer, iters) { size_t s = 0; fbstring buffer; while (iters--) { buffer.clear(); from(testStrVector) | unsplit(',', &buffer); s += buffer.size(); } folly::doNotOptimizeAway(s); } BENCHMARK_DRAW_LINE(); void StringUnsplit_Gen(size_t iters, size_t joinSize) { std::vector v; BENCHMARK_SUSPEND { FOR_EACH_RANGE (i, 0, joinSize) { v.push_back(to(rand())); } } size_t s = 0; fbstring buffer; while (iters--) { buffer.clear(); from(v) | unsplit(',', &buffer); s += buffer.size(); } folly::doNotOptimizeAway(s); } BENCHMARK_PARAM(StringUnsplit_Gen, 1000) BENCHMARK_RELATIVE_PARAM(StringUnsplit_Gen, 2000) BENCHMARK_RELATIVE_PARAM(StringUnsplit_Gen, 4000) BENCHMARK_RELATIVE_PARAM(StringUnsplit_Gen, 8000) BENCHMARK_DRAW_LINE(); void Lines_Gen(size_t iters, int joinSize) { size_t s = 0; StringPiece content = testFileContent; for (size_t i = 0; i < iters; ++i) { s += lines(content.subpiece(0, joinSize)) | take(100) | count; } folly::doNotOptimizeAway(s); } BENCHMARK_PARAM(Lines_Gen, 1e3) BENCHMARK_RELATIVE_PARAM(Lines_Gen, 2e3) BENCHMARK_RELATIVE_PARAM(Lines_Gen, 3e3) BENCHMARK_DRAW_LINE(); // clang-format off fbstring records = seq(1, 1000) | mapped([](size_t i) { return folly::to(i, ' ', i * i, ' ', i * i * i); }) | unsplit('\n'); // clang-format o BENCHMARK(Records_EachToTuple, iters) { size_t s = 0; for (size_t i = 0; i < iters; i += 1000) { // clang-format off s += split(records, '\n') | eachToTuple(' ') | get<1>() | sum; // clang-format on } folly::doNotOptimizeAway(s); } BENCHMARK_RELATIVE(Records_VectorStringPieceReused, iters) { size_t s = 0; std::vector fields; for (size_t i = 0; i < iters; i += 1000) { // clang-format off s += split(records, '\n') | mapped([&](StringPiece line) { fields.clear(); folly::split(' ', line, fields); CHECK(fields.size() == 3); return std::make_tuple( folly::to(fields[0]), folly::to(fields[1]), StringPiece(fields[2])); }) | get<1>() | sum; // clang-format on } folly::doNotOptimizeAway(s); } BENCHMARK_RELATIVE(Records_VectorStringPiece, iters) { size_t s = 0; for (size_t i = 0; i < iters; i += 1000) { // clang-format off s += split(records, '\n') | mapped([](StringPiece line) { std::vector fields; folly::split(' ', line, fields); CHECK(fields.size() == 3); return std::make_tuple( folly::to(fields[0]), folly::to(fields[1]), StringPiece(fields[2])); }) | get<1>() | sum; // clang-format on } folly::doNotOptimizeAway(s); } BENCHMARK_RELATIVE(Records_VectorString, iters) { size_t s = 0; for (size_t i = 0; i < iters; i += 1000) { // clang-format off s += split(records, '\n') | mapped([](StringPiece line) { std::vector fields; folly::split(' ', line, fields); CHECK(fields.size() == 3); return std::make_tuple( folly::to(fields[0]), folly::to(fields[1]), StringPiece(fields[2])); }) | get<1>() | sum; // clang-format on } folly::doNotOptimizeAway(s); } // Results from an Intel(R) Xeon(R) CPU E5-2660 0 @ 2.20GHz // ============================================================================ // folly/gen/test/StringBenchmark.cpp relative time/iter iters/s // ============================================================================ // StringResplitter_Big 108.58us 9.21K // StringResplitter_Small 10.60% 1.02ms 976.48 // ---------------------------------------------------------------------------- // StringSplit_Old 357.82ns 2.79M // StringSplit_Gen_Vector 105.10% 340.46ns 2.94M // ---------------------------------------------------------------------------- // StringSplit_Old_ReuseVector 96.45ns 10.37M // StringSplit_Gen_ReuseVector 124.01% 77.78ns 12.86M // StringSplit_Gen 140.10% 68.85ns 14.52M // StringSplit_Gen_Take 122.97% 78.44ns 12.75M // ---------------------------------------------------------------------------- // StringUnsplit_Old 42.99us 23.26K // StringUnsplit_Old_ReusedBuffer 100.48% 42.79us 23.37K // StringUnsplit_Gen 96.37% 44.61us 22.42K // StringUnsplit_Gen_ReusedBuffer 116.96% 36.76us 27.20K // ---------------------------------------------------------------------------- // StringUnsplit_Gen(1000) 44.71us 22.37K // StringUnsplit_Gen(2000) 49.28% 90.72us 11.02K // StringUnsplit_Gen(4000) 24.05% 185.91us 5.38K // StringUnsplit_Gen(8000) 12.23% 365.42us 2.74K // ---------------------------------------------------------------------------- // Records_EachToTuple 101.43us 9.86K // Records_VectorStringPieceReused 93.72% 108.22us 9.24K // Records_VectorStringPiece 37.14% 273.11us 3.66K // Records_VectorString 16.70% 607.47us 1.65K // ============================================================================ int main(int argc, char* argv[]) { gflags::ParseCommandLineFlags(&argc, &argv, true); initStringResplitterBenchmark(); runBenchmarks(); return 0; }