str_split_benchmark.cc (5861B)
1 // Copyright 2018 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <cstddef> 16 #include <iterator> 17 #include <string> 18 #include <unordered_map> 19 #include <unordered_set> 20 #include <vector> 21 22 #include "absl/base/internal/raw_logging.h" 23 #include "absl/strings/str_split.h" 24 #include "absl/strings/string_view.h" 25 #include "benchmark/benchmark.h" 26 27 namespace { 28 29 std::string MakeTestString(int desired_length) { 30 static const int kAverageValueLen = 25; 31 std::string test(desired_length * kAverageValueLen, 'x'); 32 for (int i = 1; i < test.size(); i += kAverageValueLen) { 33 test[i] = ';'; 34 } 35 return test; 36 } 37 38 void BM_Split2StringView(benchmark::State& state) { 39 std::string test = MakeTestString(state.range(0)); 40 for (auto _ : state) { 41 std::vector<absl::string_view> result = absl::StrSplit(test, ';'); 42 benchmark::DoNotOptimize(result); 43 } 44 } 45 BENCHMARK_RANGE(BM_Split2StringView, 0, 1 << 20); 46 47 static const absl::string_view kDelimiters = ";:,."; 48 49 std::string MakeMultiDelimiterTestString(int desired_length) { 50 static const int kAverageValueLen = 25; 51 std::string test(desired_length * kAverageValueLen, 'x'); 52 for (int i = 0; i * kAverageValueLen < test.size(); ++i) { 53 // Cycle through a variety of delimiters. 54 test[i * kAverageValueLen] = kDelimiters[i % kDelimiters.size()]; 55 } 56 return test; 57 } 58 59 // Measure StrSplit with ByAnyChar with four delimiters to choose from. 60 void BM_Split2StringViewByAnyChar(benchmark::State& state) { 61 std::string test = MakeMultiDelimiterTestString(state.range(0)); 62 for (auto _ : state) { 63 std::vector<absl::string_view> result = 64 absl::StrSplit(test, absl::ByAnyChar(kDelimiters)); 65 benchmark::DoNotOptimize(result); 66 } 67 } 68 BENCHMARK_RANGE(BM_Split2StringViewByAnyChar, 0, 1 << 20); 69 70 void BM_Split2StringViewLifted(benchmark::State& state) { 71 std::string test = MakeTestString(state.range(0)); 72 std::vector<absl::string_view> result; 73 for (auto _ : state) { 74 result = absl::StrSplit(test, ';'); 75 } 76 benchmark::DoNotOptimize(result); 77 } 78 BENCHMARK_RANGE(BM_Split2StringViewLifted, 0, 1 << 20); 79 80 void BM_Split2String(benchmark::State& state) { 81 std::string test = MakeTestString(state.range(0)); 82 for (auto _ : state) { 83 std::vector<std::string> result = absl::StrSplit(test, ';'); 84 benchmark::DoNotOptimize(result); 85 } 86 } 87 BENCHMARK_RANGE(BM_Split2String, 0, 1 << 20); 88 89 // This benchmark is for comparing Split2 to Split1 (SplitStringUsing). In 90 // particular, this benchmark uses SkipEmpty() to match SplitStringUsing's 91 // behavior. 92 void BM_Split2SplitStringUsing(benchmark::State& state) { 93 std::string test = MakeTestString(state.range(0)); 94 for (auto _ : state) { 95 std::vector<std::string> result = 96 absl::StrSplit(test, ';', absl::SkipEmpty()); 97 benchmark::DoNotOptimize(result); 98 } 99 } 100 BENCHMARK_RANGE(BM_Split2SplitStringUsing, 0, 1 << 20); 101 102 void BM_SplitStringToUnorderedSet(benchmark::State& state) { 103 const int len = state.range(0); 104 std::string test(len, 'x'); 105 for (int i = 1; i < len; i += 2) { 106 test[i] = ';'; 107 } 108 for (auto _ : state) { 109 std::unordered_set<std::string> result = 110 absl::StrSplit(test, ':', absl::SkipEmpty()); 111 benchmark::DoNotOptimize(result); 112 } 113 } 114 BENCHMARK_RANGE(BM_SplitStringToUnorderedSet, 0, 1 << 20); 115 116 void BM_SplitStringToUnorderedMap(benchmark::State& state) { 117 const int len = state.range(0); 118 std::string test(len, 'x'); 119 for (int i = 1; i < len; i += 2) { 120 test[i] = ';'; 121 } 122 for (auto _ : state) { 123 std::unordered_map<std::string, std::string> result = 124 absl::StrSplit(test, ':', absl::SkipEmpty()); 125 benchmark::DoNotOptimize(result); 126 } 127 } 128 BENCHMARK_RANGE(BM_SplitStringToUnorderedMap, 0, 1 << 20); 129 130 void BM_SplitStringAllowEmpty(benchmark::State& state) { 131 const int len = state.range(0); 132 std::string test(len, 'x'); 133 for (int i = 1; i < len; i += 2) { 134 test[i] = ';'; 135 } 136 for (auto _ : state) { 137 std::vector<std::string> result = absl::StrSplit(test, ';'); 138 benchmark::DoNotOptimize(result); 139 } 140 } 141 BENCHMARK_RANGE(BM_SplitStringAllowEmpty, 0, 1 << 20); 142 143 struct OneCharLiteral { 144 char operator()() const { return 'X'; } 145 }; 146 147 struct OneCharStringLiteral { 148 const char* operator()() const { return "X"; } 149 }; 150 151 template <typename DelimiterFactory> 152 void BM_SplitStringWithOneChar(benchmark::State& state) { 153 const auto delimiter = DelimiterFactory()(); 154 std::vector<absl::string_view> pieces; 155 size_t v = 0; 156 for (auto _ : state) { 157 pieces = absl::StrSplit("The quick brown fox jumps over the lazy dog", 158 delimiter); 159 v += pieces.size(); 160 } 161 ABSL_RAW_CHECK(v == state.iterations(), ""); 162 } 163 BENCHMARK_TEMPLATE(BM_SplitStringWithOneChar, OneCharLiteral); 164 BENCHMARK_TEMPLATE(BM_SplitStringWithOneChar, OneCharStringLiteral); 165 166 template <typename DelimiterFactory> 167 void BM_SplitStringWithOneCharNoVector(benchmark::State& state) { 168 const auto delimiter = DelimiterFactory()(); 169 size_t v = 0; 170 for (auto _ : state) { 171 auto splitter = absl::StrSplit( 172 "The quick brown fox jumps over the lazy dog", delimiter); 173 v += std::distance(splitter.begin(), splitter.end()); 174 } 175 ABSL_RAW_CHECK(v == state.iterations(), ""); 176 } 177 BENCHMARK_TEMPLATE(BM_SplitStringWithOneCharNoVector, OneCharLiteral); 178 BENCHMARK_TEMPLATE(BM_SplitStringWithOneCharNoVector, OneCharStringLiteral); 179 180 } // namespace