proxygen
RangeFindBenchmark.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2012-present 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 
17 #include <folly/Range.h>
18 
19 #include <algorithm>
20 #include <iostream>
21 #include <random>
22 #include <string>
23 
24 #include <folly/Benchmark.h>
26 
27 using namespace folly;
28 using namespace std;
29 
30 namespace {
31 
32 std::string str;
33 constexpr int kVstrSize = 16;
34 std::vector<std::string> vstr;
35 std::vector<StringPiece> vstrp;
36 std::string file;
37 
38 void initStr(int len) {
39  str.clear();
40  vstr.clear();
41  vstrp.clear();
42 
43  str.reserve(len + 1);
44  str.append(len, 'a');
45  str.append(1, 'b');
46 
47  // create 16 copies of str, each with a different 16byte alignment.
48  // Useful because some implementations of find_first_of have different
49  // behaviors based on byte alignment.
50  for (int i = 0; i < kVstrSize; ++i) {
51  string s(i, '$');
52  s += str;
53  if (i % 2) {
54  // some find_first_of implementations have special (page-safe) logic
55  // for handling the end of a string. Flex that logic only sometimes.
56  s += string(32, '$');
57  }
58  vstr.push_back(s);
59  StringPiece sp(vstr.back());
60  sp.advance(i);
61  vstrp.push_back(sp);
62  }
63 }
64 
65 std::mt19937 rnd;
66 string ffoTestString;
67 const size_t ffoDelimSize = 128;
68 vector<string> ffoDelim;
69 
70 void initFile(int len) {
71  std::uniform_int_distribution<uint32_t> validChar(1, 64);
72  file.clear();
73  while (len--) {
74  char ch = validChar(rnd);
75  if (ch == '\r') {
76  ch = '\n';
77  }
78  file.push_back(ch);
79  }
80 }
81 
82 string generateString(int len) {
83  std::uniform_int_distribution<uint32_t> validChar(1, 255); // no null-char
84  string ret;
85  while (len--) {
86  ret.push_back(validChar(rnd));
87  }
88  return ret;
89 }
90 
91 void initDelims(int len) {
92  ffoDelim.clear();
93 
94  string s(len - 1, '\0'); // find_first_of won't finish until last char
95  s.push_back('a');
96  ffoTestString = s;
97 
98  for (size_t i = 0; i < ffoDelimSize; ++i) {
99  // most delimiter sets are pretty small, but occasionally there could
100  // be a big one.
101  auto n = rnd() % 8 + 1;
102  if (n == 8) {
103  n = 32;
104  }
105  auto s_ = generateString(n);
106  if (rnd() % 2) {
107  // ~half of tests will find a hit
108  s_[rnd() % s_.size()] = 'a'; // yes, this could mean 'a' is a duplicate
109  }
110  ffoDelim.push_back(s_);
111  }
112 }
113 
114 } // namespace
115 
116 BENCHMARK(FindSingleCharMemchr, n) {
117  StringPiece haystack(str);
118  FOR_EACH_RANGE (i, 0, n) {
119  doNotOptimizeAway(haystack.find('b'));
120  char x = haystack[0];
121  doNotOptimizeAway(&x);
122  }
123 }
124 
125 BENCHMARK_RELATIVE(FindSingleCharRange, n) {
126  const char c = 'b';
127  StringPiece haystack(str);
128  folly::StringPiece needle(&c, &c + 1);
129  FOR_EACH_RANGE (i, 0, n) {
130  doNotOptimizeAway(haystack.find(needle));
131  char x = haystack[0];
132  doNotOptimizeAway(&x);
133  }
134 }
135 
137 
138 template <class Func>
139 void countHits(Func func, size_t n) {
140  StringPiece needles = "\r\n\1";
141  FOR_EACH_RANGE (i, 0, n) {
142  size_t p, c = 0;
143  for (StringPiece left = file;
144  (p = func(left, needles)) != StringPiece::npos;
145  left.advance(p + 1)) {
146  ++c;
147  }
149  }
150 }
151 
152 template <class Func>
153 void findFirstOfRange(StringPiece needles, Func func, size_t n) {
154  FOR_EACH_RANGE (i, 0, n) {
155  const StringPiece haystack = vstrp[i % kVstrSize];
156  doNotOptimizeAway(func(haystack, needles));
157  char x = haystack[0];
158  doNotOptimizeAway(&x);
159  }
160 }
161 
162 const string delims1 = "b";
163 
164 BENCHMARK(FindFirstOf1NeedlesBase, n) {
166 }
167 
168 BENCHMARK_RELATIVE(FindFirstOf1NeedlesNoSSE, n) {
170 }
171 
172 BENCHMARK_RELATIVE(FindFirstOf1NeedlesStd, n) {
174 }
175 
176 BENCHMARK_RELATIVE(FindFirstOf1NeedlesByteSet, n) {
178 }
179 
180 BENCHMARK_RELATIVE(FindFirstOf1NeedlesBitSet, n) {
182 }
183 
185 
186 const string delims2 = "bc";
187 
188 BENCHMARK(FindFirstOf2NeedlesBase, n) {
190 }
191 
192 BENCHMARK_RELATIVE(FindFirstOf2NeedlesNoSSE, n) {
194 }
195 
196 BENCHMARK_RELATIVE(FindFirstOf2NeedlesStd, n) {
198 }
199 
200 BENCHMARK_RELATIVE(FindFirstOf2NeedlesByteSet, n) {
202 }
203 
204 BENCHMARK_RELATIVE(FindFirstOf2NeedlesBitSet, n) {
206 }
207 
209 
210 const string delims4 = "bcde";
211 
212 BENCHMARK(FindFirstOf4NeedlesBase, n) {
214 }
215 
216 BENCHMARK_RELATIVE(FindFirstOf4NeedlesNoSSE, n) {
218 }
219 
220 BENCHMARK_RELATIVE(FindFirstOf4NeedlesStd, n) {
222 }
223 
224 BENCHMARK_RELATIVE(FindFirstOf4NeedlesByteSet, n) {
226 }
227 
228 BENCHMARK_RELATIVE(FindFirstOf4NeedlesBitSet, n) {
230 }
231 
233 
234 const string delims8 = "0123456b";
235 
236 BENCHMARK(FindFirstOf8NeedlesBase, n) {
238 }
239 
240 BENCHMARK_RELATIVE(FindFirstOf8NeedlesNoSSE, n) {
242 }
243 
244 BENCHMARK_RELATIVE(FindFirstOf8NeedlesStd, n) {
246 }
247 
248 BENCHMARK_RELATIVE(FindFirstOf8NeedlesByteSet, n) {
250 }
251 
252 BENCHMARK_RELATIVE(FindFirstOf8NeedlesBitSet, n) {
254 }
255 
257 
258 const string delims16 = "0123456789bcdefg";
259 
260 BENCHMARK(FindFirstOf16NeedlesBase, n) {
262 }
263 
264 BENCHMARK_RELATIVE(FindFirstOf16NeedlesNoSSE, n) {
266 }
267 
268 BENCHMARK_RELATIVE(FindFirstOf16NeedlesStd, n) {
270 }
271 
272 BENCHMARK_RELATIVE(FindFirstOf16NeedlesByteSet, n) {
274 }
275 
276 BENCHMARK_RELATIVE(FindFirstOf16NeedlesBitSet, n) {
278 }
279 
281 
282 const string delims32 = "!bcdefghijklmnopqrstuvwxyz_012345";
283 
284 BENCHMARK(FindFirstOf32NeedlesBase, n) {
286 }
287 
288 BENCHMARK_RELATIVE(FindFirstOf32NeedlesNoSSE, n) {
290 }
291 
292 BENCHMARK_RELATIVE(FindFirstOf32NeedlesStd, n) {
294 }
295 
296 BENCHMARK_RELATIVE(FindFirstOf32NeedlesByteSet, n) {
298 }
299 
300 BENCHMARK_RELATIVE(FindFirstOf32NeedlesBitSet, n) {
302 }
303 
305 
306 const string delims64 =
307  "!bcdefghijklmnopqrstuvwxyz_"
308  "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789$";
309 
310 BENCHMARK(FindFirstOf64NeedlesBase, n) {
312 }
313 
314 BENCHMARK_RELATIVE(FindFirstOf64NeedlesNoSSE, n) {
316 }
317 
318 BENCHMARK_RELATIVE(FindFirstOf64NeedlesStd, n) {
320 }
321 
322 BENCHMARK_RELATIVE(FindFirstOf64NeedlesByteSet, n) {
324 }
325 
326 BENCHMARK_RELATIVE(FindFirstOf64NeedlesBitSet, n) {
328 }
329 
331 
332 template <class Func>
333 void findFirstOfRandom(Func func, size_t iters) {
334  for (size_t i = 0; i < iters; ++i) {
335  auto test = i % ffoDelim.size();
336  auto p = func(ffoTestString, ffoDelim[test]);
338  }
339 }
340 
341 BENCHMARK(FindFirstOfRandomBase, n) {
343 }
344 
345 BENCHMARK_RELATIVE(FindFirstOfRandomNoSSE, n) {
347 }
348 
349 BENCHMARK_RELATIVE(FindFirstOfRandomStd, n) {
351 }
352 
353 BENCHMARK_RELATIVE(FindFirstOfRandomByteSet, n) {
355 }
356 
357 BENCHMARK_RELATIVE(FindFirstOfRandomBitSet, n) {
359 }
360 
362 
363 BENCHMARK(CountDelimsBase, n) {
365 }
366 
367 BENCHMARK_RELATIVE(CountDelimsNoSSE, n) {
369 }
370 
371 BENCHMARK_RELATIVE(CountDelimsStd, n) {
373 }
374 
375 BENCHMARK_RELATIVE(CountDelimsByteSet, n) {
377 }
378 
379 BENCHMARK_RELATIVE(CountDelimsBitSet, n) {
381 }
382 
384 
385 BENCHMARK(FindFirstOfOffsetRange, n) {
386  StringPiece haystack(str);
387  folly::StringPiece needles("bc");
388  DCHECK_EQ(haystack.size() - 1, haystack.find_first_of(needles, 1)); // works!
389  FOR_EACH_RANGE (i, 0, n) {
390  size_t pos = i % 2; // not a constant to prevent optimization
391  doNotOptimizeAway(haystack.find_first_of(needles, pos));
392  char x = haystack[0];
393  doNotOptimizeAway(&x);
394  }
395 }
396 
398 
399 int main(int argc, char** argv) {
400  gflags::ParseCommandLineFlags(&argc, &argv, true);
401 
402  for (int len : {1, 8, 10, 16, 32, 64, 128, 256, 10 * 1024, 1024 * 1024}) {
403  initStr(len);
404  initDelims(len);
405  initFile(len);
406  runBenchmarks();
407  }
408  return 0;
409 }
const string needle
Definition: InvokeTest.cpp:58
std::string s_
const string delims16
BENCHMARK_RELATIVE(FindSingleCharRange, n)
size_t qfind_first_byte_of_std(const StringPieceLite haystack, const StringPieceLite needles)
Definition: RangeCommon.h:72
size_type find_first_of(const_range_type needles) const
Definition: Range.h:773
const string delims2
size_type find(const_range_type str) const
Definition: Range.h:721
size_t qfind_first_byte_of_byteset(const StringPieceLite haystack, const StringPieceLite needles)
Definition: RangeCommon.cpp:42
void advance(size_type n)
Definition: Range.h:672
STL namespace.
constexpr size_type size() const
Definition: Range.h:431
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void findFirstOfRange(StringPiece needles, Func func, size_t n)
void runBenchmarks()
Definition: Benchmark.cpp:456
auto ch
void countHits(Func func, size_t n)
#define FOR_EACH_RANGE(i, begin, end)
Definition: Foreach.h:313
const string delims8
char ** argv
Function< void()> Func
Definition: Executor.h:27
size_t qfind_first_byte_of(const StringPiece haystack, const StringPiece needles)
Definition: Range.h:1349
const string delims64
size_t qfind_first_byte_of_nosse(const StringPieceLite haystack, const StringPieceLite needles)
Definition: RangeCommon.h:92
const string delims1
BENCHMARK(fbFollyGlobalBenchmarkBaseline)
Definition: Benchmark.cpp:84
static const size_type npos
Definition: Range.h:197
const char * string
Definition: Conv.cpp:212
BENCHMARK_DRAW_LINE()
static set< string > s
size_t qfind_first_byte_of_bitset(const StringPieceLite haystack, const StringPieceLite needles)
Definition: RangeCommon.cpp:27
void findFirstOfRandom(Func func, size_t iters)
char c
const string delims4
auto doNotOptimizeAway(const T &datum) -> typename std::enable_if< !detail::DoNotOptimizeAwayNeedsIndirect< T >::value >::type
Definition: Benchmark.h:258
int main(int argc, char **argv)
const string delims32