proxygen
ConvBenchmark.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2016-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/Conv.h>
18 
19 #include <boost/lexical_cast.hpp>
20 
21 #include <folly/Benchmark.h>
22 #include <folly/CppAttributes.h>
24 
25 #include <array>
26 #include <limits>
27 #include <stdexcept>
28 
29 using namespace std;
30 using namespace folly;
31 
32 // Android doesn't support std::to_string so just use a placeholder there.
33 #ifdef __ANDROID__
34 #define FOLLY_RANGE_CHECK_TO_STRING(x) std::string("N/A")
35 #else
36 #define FOLLY_RANGE_CHECK_TO_STRING(x) std::to_string(x)
37 #endif
38 
39 namespace folly {
40 namespace conv_bench_detail {
41 
42 // Keep this data global and non-const, so the compiler cannot make
43 // any assumptions about the actual values at compile time
44 
46  0,
47  1ULL,
48  12ULL,
49  123ULL,
50  1234ULL,
51  12345ULL,
52  123456ULL,
53  1234567ULL,
54  12345678ULL,
55  123456789ULL,
56  1234567890ULL,
57  12345678901ULL,
58  123456789012ULL,
59  1234567890123ULL,
60  12345678901234ULL,
61  123456789012345ULL,
62  1234567890123456ULL,
63  12345678901234567ULL,
64  123456789012345678ULL,
65  1234567890123456789ULL,
66  12345678901234567890ULL,
67 };
68 
70  0,
71  1LL,
72  12LL,
73  123LL,
74  1234LL,
75  12345LL,
76  123456LL,
77  1234567LL,
78  12345678LL,
79  123456789LL,
80  1234567890LL,
81  12345678901LL,
82  123456789012LL,
83  1234567890123LL,
84  12345678901234LL,
85  123456789012345LL,
86  1234567890123456LL,
87  12345678901234567LL,
88  123456789012345678LL,
89  1234567890123456789LL,
90 };
91 
93  0,
94  -1LL,
95  -12LL,
96  -123LL,
97  -1234LL,
98  -12345LL,
99  -123456LL,
100  -1234567LL,
101  -12345678LL,
102  -123456789LL,
103  -1234567890LL,
104  -12345678901LL,
105  -123456789012LL,
106  -1234567890123LL,
107  -12345678901234LL,
108  -123456789012345LL,
109  -1234567890123456LL,
110  -12345678901234567LL,
111  -123456789012345678LL,
112  -1234567890123456789LL,
113 };
114 
115 #if FOLLY_HAVE_INT128_T
116 
117 unsigned __int128 uint128Num[] = {
118  0,
119  static_cast<unsigned __int128>(1) << 0,
120  static_cast<unsigned __int128>(1) << 4,
121  static_cast<unsigned __int128>(1) << 7,
122  static_cast<unsigned __int128>(1) << 10,
123  static_cast<unsigned __int128>(1) << 14,
124  static_cast<unsigned __int128>(1) << 17,
125  static_cast<unsigned __int128>(1) << 20,
126  static_cast<unsigned __int128>(1) << 24,
127  static_cast<unsigned __int128>(1) << 27,
128  static_cast<unsigned __int128>(1) << 30,
129  static_cast<unsigned __int128>(1) << 34,
130  static_cast<unsigned __int128>(1) << 37,
131  static_cast<unsigned __int128>(1) << 40,
132  static_cast<unsigned __int128>(1) << 44,
133  static_cast<unsigned __int128>(1) << 47,
134  static_cast<unsigned __int128>(1) << 50,
135  static_cast<unsigned __int128>(1) << 54,
136  static_cast<unsigned __int128>(1) << 57,
137  static_cast<unsigned __int128>(1) << 60,
138  static_cast<unsigned __int128>(1) << 64,
139  static_cast<unsigned __int128>(1) << 67,
140  static_cast<unsigned __int128>(1) << 70,
141  static_cast<unsigned __int128>(1) << 74,
142  static_cast<unsigned __int128>(1) << 77,
143  static_cast<unsigned __int128>(1) << 80,
144  static_cast<unsigned __int128>(1) << 84,
145  static_cast<unsigned __int128>(1) << 87,
146  static_cast<unsigned __int128>(1) << 90,
147  static_cast<unsigned __int128>(1) << 94,
148  static_cast<unsigned __int128>(1) << 97,
149  static_cast<unsigned __int128>(1) << 100,
150  static_cast<unsigned __int128>(1) << 103,
151  static_cast<unsigned __int128>(1) << 107,
152  static_cast<unsigned __int128>(1) << 110,
153  static_cast<unsigned __int128>(1) << 113,
154  static_cast<unsigned __int128>(1) << 117,
155  static_cast<unsigned __int128>(1) << 120,
156  static_cast<unsigned __int128>(1) << 123,
157  static_cast<unsigned __int128>(1) << 127,
158 };
159 
160 __int128 int128Pos[] = {
161  0,
162  static_cast<__int128>(1) << 0,
163  static_cast<__int128>(1) << 4,
164  static_cast<__int128>(1) << 7,
165  static_cast<__int128>(1) << 10,
166  static_cast<__int128>(1) << 14,
167  static_cast<__int128>(1) << 17,
168  static_cast<__int128>(1) << 20,
169  static_cast<__int128>(1) << 24,
170  static_cast<__int128>(1) << 27,
171  static_cast<__int128>(1) << 30,
172  static_cast<__int128>(1) << 34,
173  static_cast<__int128>(1) << 37,
174  static_cast<__int128>(1) << 40,
175  static_cast<__int128>(1) << 44,
176  static_cast<__int128>(1) << 47,
177  static_cast<__int128>(1) << 50,
178  static_cast<__int128>(1) << 54,
179  static_cast<__int128>(1) << 57,
180  static_cast<__int128>(1) << 60,
181  static_cast<__int128>(1) << 64,
182  static_cast<__int128>(1) << 67,
183  static_cast<__int128>(1) << 70,
184  static_cast<__int128>(1) << 74,
185  static_cast<__int128>(1) << 77,
186  static_cast<__int128>(1) << 80,
187  static_cast<__int128>(1) << 84,
188  static_cast<__int128>(1) << 87,
189  static_cast<__int128>(1) << 90,
190  static_cast<__int128>(1) << 94,
191  static_cast<__int128>(1) << 97,
192  static_cast<__int128>(1) << 100,
193  static_cast<__int128>(1) << 103,
194  static_cast<__int128>(1) << 107,
195  static_cast<__int128>(1) << 110,
196  static_cast<__int128>(1) << 113,
197  static_cast<__int128>(1) << 117,
198  static_cast<__int128>(1) << 120,
199  static_cast<__int128>(1) << 123,
200  static_cast<__int128>(3) << 125,
201 };
202 
203 __int128 int128Neg[] = {
204  0,
205  -(static_cast<__int128>(1) << 0),
206  -(static_cast<__int128>(1) << 4),
207  -(static_cast<__int128>(1) << 7),
208  -(static_cast<__int128>(1) << 10),
209  -(static_cast<__int128>(1) << 14),
210  -(static_cast<__int128>(1) << 17),
211  -(static_cast<__int128>(1) << 20),
212  -(static_cast<__int128>(1) << 24),
213  -(static_cast<__int128>(1) << 27),
214  -(static_cast<__int128>(1) << 30),
215  -(static_cast<__int128>(1) << 34),
216  -(static_cast<__int128>(1) << 37),
217  -(static_cast<__int128>(1) << 40),
218  -(static_cast<__int128>(1) << 44),
219  -(static_cast<__int128>(1) << 47),
220  -(static_cast<__int128>(1) << 50),
221  -(static_cast<__int128>(1) << 54),
222  -(static_cast<__int128>(1) << 57),
223  -(static_cast<__int128>(1) << 60),
224  -(static_cast<__int128>(1) << 64),
225  -(static_cast<__int128>(1) << 67),
226  -(static_cast<__int128>(1) << 70),
227  -(static_cast<__int128>(1) << 74),
228  -(static_cast<__int128>(1) << 77),
229  -(static_cast<__int128>(1) << 80),
230  -(static_cast<__int128>(1) << 84),
231  -(static_cast<__int128>(1) << 87),
232  -(static_cast<__int128>(1) << 90),
233  -(static_cast<__int128>(1) << 94),
234  -(static_cast<__int128>(1) << 97),
235  -(static_cast<__int128>(1) << 100),
236  -(static_cast<__int128>(1) << 103),
237  -(static_cast<__int128>(1) << 107),
238  -(static_cast<__int128>(1) << 110),
239  -(static_cast<__int128>(1) << 113),
240  -(static_cast<__int128>(1) << 117),
241  -(static_cast<__int128>(1) << 120),
242  -(static_cast<__int128>(1) << 123),
243  -(static_cast<__int128>(3) << 125),
244 };
245 
246 #endif
247 } // namespace conv_bench_detail
248 } // namespace folly
249 
250 using namespace folly::conv_bench_detail;
251 
252 namespace {
253 
254 template <typename T>
255 void checkArrayIndex(const T& array, size_t index) {
256  DCHECK_LT(index, sizeof(array) / sizeof(array[0]));
257 }
258 } // namespace
259 
261 // Benchmarks for ASCII to int conversion
263 // @author: Rajat Goel (rajat)
264 
265 static int64_t handwrittenAtoi(const char* start, const char* end) {
266  bool positive = true;
267  int64_t retVal = 0;
268 
269  if (start == end) {
270  throw std::runtime_error("empty string");
271  }
272 
273  while (start < end && isspace(*start)) {
274  ++start;
275  }
276 
277  switch (*start) {
278  case '-':
279  positive = false;
281  case '+':
282  ++start;
284  default:
285  break;
286  }
287 
288  while (start < end && *start >= '0' && *start <= '9') {
289  auto const newRetVal = retVal * 10 + (*start++ - '0');
290  if (newRetVal < retVal) {
291  throw std::runtime_error("overflow");
292  }
293  retVal = newRetVal;
294  }
295 
296  if (start != end) {
297  throw std::runtime_error("extra chars at the end");
298  }
299 
300  return positive ? retVal : -retVal;
301 }
302 
303 static StringPiece pc1 = "1234567890123456789";
304 
305 void handwrittenAtoiMeasure(unsigned int n, unsigned int digits) {
306  auto p = pc1.subpiece(pc1.size() - digits, digits);
307  FOR_EACH_RANGE (i, 0, n) {
308  doNotOptimizeAway(handwrittenAtoi(p.begin(), p.end()));
309  }
310 }
311 
312 void follyAtoiMeasure(unsigned int n, unsigned int digits) {
313  auto p = pc1.subpiece(pc1.size() - digits, digits);
314  FOR_EACH_RANGE (i, 0, n) {
315  doNotOptimizeAway(folly::to<int64_t>(p.begin(), p.end()));
316  }
317 }
318 
319 void clibAtoiMeasure(unsigned int n, unsigned int digits) {
320  auto p = pc1.subpiece(pc1.size() - digits, digits);
321  assert(*p.end() == 0);
322  FOR_EACH_RANGE (i, 0, n) { doNotOptimizeAway(atoll(p.begin())); }
323 }
324 
325 void lexicalCastMeasure(unsigned int n, unsigned int digits) {
326  auto p = pc1.subpiece(pc1.size() - digits, digits);
327  assert(*p.end() == 0);
328  FOR_EACH_RANGE (i, 0, n) {
329  doNotOptimizeAway(boost::lexical_cast<uint64_t>(p.begin()));
330  }
331 }
332 
333 // Benchmarks for unsigned to string conversion, raw
334 
335 unsigned u64ToAsciiTable(uint64_t value, char* dst) {
336  static const char digits[201] =
337  "00010203040506070809"
338  "10111213141516171819"
339  "20212223242526272829"
340  "30313233343536373839"
341  "40414243444546474849"
342  "50515253545556575859"
343  "60616263646566676869"
344  "70717273747576777879"
345  "80818283848586878889"
346  "90919293949596979899";
347 
348  uint32_t const length = digits10(value);
349  uint32_t next = length - 1;
350  while (value >= 100) {
351  auto const i = (value % 100) * 2;
352  value /= 100;
353  dst[next] = digits[i + 1];
354  dst[next - 1] = digits[i];
355  next -= 2;
356  }
357  // Handle last 1-2 digits
358  if (value < 10) {
359  dst[next] = '0' + uint32_t(value);
360  } else {
361  auto i = uint32_t(value) * 2;
362  dst[next] = digits[i + 1];
363  dst[next - 1] = digits[i];
364  }
365  return length;
366 }
367 
368 void u64ToAsciiTableBM(unsigned int n, size_t index) {
369  checkArrayIndex(uint64Num, index);
370  char buf[20];
371  FOR_EACH_RANGE (i, 0, n) {
372  doNotOptimizeAway(u64ToAsciiTable(uint64Num[index] + (i % 8), buf));
373  }
374 }
375 
376 unsigned u64ToAsciiClassic(uint64_t value, char* dst) {
377  // Write backwards.
378  char* next = (char*)dst;
379  char* start = next;
380  do {
381  *next++ = '0' + (value % 10);
382  value /= 10;
383  } while (value != 0);
384  unsigned length = next - start;
385 
386  // Reverse in-place.
387  next--;
388  while (next > start) {
389  char swap = *next;
390  *next = *start;
391  *start = swap;
392  next--;
393  start++;
394  }
395  return length;
396 }
397 
398 void u64ToAsciiClassicBM(unsigned int n, size_t index) {
399  checkArrayIndex(uint64Num, index);
400  char buf[20];
401  FOR_EACH_RANGE (i, 0, n) {
402  doNotOptimizeAway(u64ToAsciiClassic(uint64Num[index] + (i % 8), buf));
403  }
404 }
405 
406 void u64ToAsciiFollyBM(unsigned int n, size_t index) {
407  checkArrayIndex(uint64Num, index);
408  char buf[20];
409  FOR_EACH_RANGE (i, 0, n) {
410  doNotOptimizeAway(uint64ToBufferUnsafe(uint64Num[index] + (i % 8), buf));
411  }
412 }
413 
414 // Benchmark unsigned to string conversion
415 
416 void u64ToStringClibMeasure(unsigned int n, size_t index) {
417  // FOLLY_RANGE_CHECK_TO_STRING expands to std::to_string, except on Android
418  // where std::to_string is not supported
419  checkArrayIndex(uint64Num, index);
420  FOR_EACH_RANGE (i, 0, n) {
422  FOLLY_RANGE_CHECK_TO_STRING(uint64Num[index] + (i % 8)).size());
423  }
424 }
425 
426 void u64ToStringFollyMeasure(unsigned int n, size_t index) {
427  checkArrayIndex(uint64Num, index);
428  FOR_EACH_RANGE (i, 0, n) {
429  doNotOptimizeAway(to<std::string>(uint64Num[index] + (i % 8)).size());
430  }
431 }
432 
433 // Signed
434 
435 void i64ToStringFollyMeasurePos(unsigned int n, size_t index) {
436  checkArrayIndex(int64Pos, index);
437  FOR_EACH_RANGE (i, 0, n) {
438  doNotOptimizeAway(to<std::string>(int64Pos[index] + (i % 8)).size());
439  }
440 }
441 
442 void i64ToStringFollyMeasureNeg(unsigned int n, size_t index) {
443  checkArrayIndex(int64Neg, index);
444  FOR_EACH_RANGE (i, 0, n) {
445  doNotOptimizeAway(to<std::string>(int64Neg[index] - (i % 8)).size());
446  }
447 }
448 
449 // Benchmark uitoa with string append
450 
451 void u2aAppendClassicBM(unsigned int n, size_t index) {
452  checkArrayIndex(uint64Num, index);
453  string s;
454  FOR_EACH_RANGE (i, 0, n) {
455  // auto buf = &s.back() + 1;
456  char buffer[20];
457  s.append(buffer, u64ToAsciiClassic(uint64Num[index] + (i % 8), buffer));
458  doNotOptimizeAway(s.size());
459  }
460 }
461 
462 void u2aAppendFollyBM(unsigned int n, size_t index) {
463  checkArrayIndex(uint64Num, index);
464  string s;
465  FOR_EACH_RANGE (i, 0, n) {
466  // auto buf = &s.back() + 1;
467  char buffer[20];
468  s.append(buffer, uint64ToBufferUnsafe(uint64Num[index] + (i % 8), buffer));
469  doNotOptimizeAway(s.size());
470  }
471 }
472 
473 template <class String>
476  void operator()(unsigned int n, size_t len) const {
477  String s;
479  s.append(len, '0');
480  }
481  FOR_EACH_RANGE (i, 0, n) {
482  String result = to<String>(s);
483  doNotOptimizeAway(result.size());
484  }
485  }
486 };
487 
488 template <class String>
491  void operator()(unsigned int n, size_t len) const {
492  String s;
494  s.append(len, '0');
495  }
496  FOR_EACH_RANGE (i, 0, n) {
497  String result = to<String>(s, nullptr);
498  doNotOptimizeAway(result.size());
499  }
500  }
501 };
502 
503 namespace folly {
504 namespace conv_bench_detail {
505 
506 // Keep this data global and non-const, so the compiler cannot make
507 // any assumptions about the actual values at compile time
508 
509 size_t bigInt = 11424545345345;
510 size_t smallInt = 104;
511 char someString[] = "this is some nice string";
512 char otherString[] = "this is a long string, so it's not so nice";
513 char reallyShort[] = "meh";
514 std::string stdString = "std::strings are very nice";
515 float fValue = 1.2355f;
516 double dValue = 345345345.435;
517 } // namespace conv_bench_detail
518 } // namespace folly
519 
520 BENCHMARK(preallocateTestNoFloat, n) {
521  for (size_t i = 0; i < n; ++i) {
523  to<std::string>(bigInt, someString, stdString, otherString).size());
524  doNotOptimizeAway(to<std::string>(reallyShort, smallInt).size());
525  doNotOptimizeAway(to<std::string>(bigInt, stdString).size());
527  to<std::string>(bigInt, stdString, dValue, otherString).size());
528  doNotOptimizeAway(to<std::string>(bigInt, someString, reallyShort).size());
529  }
530 }
531 
532 BENCHMARK(preallocateTestFloat, n) {
533  for (size_t i = 0; i < n; ++i) {
534  doNotOptimizeAway(to<std::string>(stdString, ',', fValue, dValue).size());
535  doNotOptimizeAway(to<std::string>(stdString, ',', dValue).size());
536  }
537 }
538 
539 namespace folly {
540 namespace conv_bench_detail {
541 
542 // Keep this data global and non-const, so the compiler cannot make
543 // any assumptions about the actual values at compile time
544 
545 int8_t i8s[] = {
546  -(static_cast<int8_t>(1) << 4),
547  static_cast<int8_t>(1) << 5,
548  -(static_cast<int8_t>(1) << 6),
549 };
550 
552  static_cast<uint8_t>(1) << 4,
553  static_cast<uint8_t>(1) << 5,
554  static_cast<uint8_t>(1) << 7,
555 };
556 
558  -(static_cast<int16_t>(1) << 8),
559  static_cast<int16_t>(1) << 12,
560  -(static_cast<int16_t>(1) << 14),
561 };
562 
564  static_cast<uint16_t>(1) << 8,
565  static_cast<uint16_t>(1) << 12,
566  static_cast<uint16_t>(1) << 15,
567 };
568 
570  -(static_cast<int32_t>(1) << 16),
571  static_cast<int32_t>(1) << 25,
572  -(static_cast<int32_t>(1) << 30),
573 };
574 
576  static_cast<uint32_t>(1) << 16,
577  static_cast<uint32_t>(1) << 25,
578  static_cast<uint32_t>(1) << 31,
579 };
580 
582  -(static_cast<int64_t>(1) << 32),
583  static_cast<int64_t>(1) << 50,
584  -(static_cast<int64_t>(1) << 62),
585 };
586 
588  static_cast<uint64_t>(1) << 32,
589  static_cast<uint64_t>(1) << 50,
590  static_cast<uint64_t>(1) << 63,
591 };
592 } // namespace conv_bench_detail
593 } // namespace folly
594 
595 BENCHMARK(preallocateTestInt8, n) {
596  for (size_t i = 0; i < n; ++i) {
597  doNotOptimizeAway(to<std::string>(
598  i8s[0],
599  ',',
600  u8s[0],
601  ',',
602  i8s[1],
603  ',',
604  u8s[1],
605  ',',
606  i8s[2],
607  ',',
608  u8s[2])
609  .size());
610  }
611 }
612 
613 BENCHMARK(preallocateTestInt16, n) {
614  for (size_t i = 0; i < n; ++i) {
615  doNotOptimizeAway(to<std::string>(
616  i16s[0],
617  ',',
618  u16s[0],
619  ',',
620  i16s[1],
621  ',',
622  u16s[1],
623  ',',
624  i16s[2],
625  ',',
626  u16s[2])
627  .size());
628  }
629 }
630 
631 BENCHMARK(preallocateTestInt32, n) {
632  for (size_t i = 0; i < n; ++i) {
633  doNotOptimizeAway(to<std::string>(
634  i32s[0],
635  ',',
636  u32s[0],
637  ',',
638  i32s[1],
639  ',',
640  u32s[1],
641  ',',
642  i32s[2],
643  ',',
644  u32s[2])
645  .size());
646  }
647 }
648 
649 BENCHMARK(preallocateTestInt64, n) {
650  for (size_t i = 0; i < n; ++i) {
651  doNotOptimizeAway(to<std::string>(
652  i64s[0],
653  ',',
654  u64s[0],
655  ',',
656  i64s[1],
657  ',',
658  u64s[1],
659  ',',
660  i64s[2],
661  ',',
662  u64s[2])
663  .size());
664  }
665 }
666 
667 #if FOLLY_HAVE_INT128_T
668 namespace {
669 
670 __int128 i128s[] = {
671  -(static_cast<__int128>(1) << 2),
672  static_cast<__int128>(1) << 100,
673  -(static_cast<__int128>(1) << 126),
674 };
675 
676 unsigned __int128 u128s[] = {
677  static_cast<unsigned __int128>(1) << 2,
678  static_cast<unsigned __int128>(1) << 100,
679  static_cast<unsigned __int128>(1) << 127,
680 };
681 } // namespace
682 
683 BENCHMARK(preallocateTestInt128, n) {
684  for (size_t i = 0; i < n; ++i) {
685  doNotOptimizeAway(to<std::string>(
686  i128s[0],
687  ',',
688  u128s[0],
689  ',',
690  i128s[1],
691  ',',
692  u128s[1],
693  ',',
694  i128s[2],
695  ',',
696  u128s[2])
697  .size());
698  }
699 }
700 
701 BENCHMARK(preallocateTestNoFloatWithInt128, n) {
702  for (size_t i = 0; i < n; ++i) {
704  to<std::string>(bigInt, someString, stdString, otherString).size());
706  to<std::string>(reallyShort, u128s[0], smallInt, i128s[2]).size());
708  to<std::string>(bigInt, i128s[0], stdString, u128s[1]).size());
710  to<std::string>(bigInt, stdString, dValue, otherString).size());
712  to<std::string>(bigInt, u128s[2], someString, reallyShort).size());
713  }
714 }
715 #endif
716 
718 
723 
724 #define DEFINE_BENCHMARK_GROUP(n) \
725  BENCHMARK_PARAM(u64ToAsciiClassicBM, n) \
726  BENCHMARK_RELATIVE_PARAM(u64ToAsciiTableBM, n) \
727  BENCHMARK_RELATIVE_PARAM(u64ToAsciiFollyBM, n) \
728  BENCHMARK_DRAW_LINE()
729 
750 
751 #undef DEFINE_BENCHMARK_GROUP
752 
753 #define DEFINE_BENCHMARK_GROUP(n) \
754  BENCHMARK_PARAM(u64ToStringClibMeasure, n) \
755  BENCHMARK_RELATIVE_PARAM(u64ToStringFollyMeasure, n) \
756  BENCHMARK_RELATIVE_PARAM(i64ToStringFollyMeasurePos, n) \
757  BENCHMARK_RELATIVE_PARAM(i64ToStringFollyMeasureNeg, n) \
758  BENCHMARK_DRAW_LINE()
759 
779 
780 // Only for u64
784 
785 #undef DEFINE_BENCHMARK_GROUP
786 
787 #if FOLLY_HAVE_INT128_T
788 
789 void u128ToStringFollyMeasure(unsigned int n, size_t index) {
790  checkArrayIndex(uint128Num, index);
791  FOR_EACH_RANGE (i, 0, n) {
792  doNotOptimizeAway(to<std::string>(uint128Num[index] + (i % 8)).size());
793  }
794 }
795 
796 void i128ToStringFollyMeasurePos(unsigned int n, size_t index) {
797  checkArrayIndex(int128Pos, index);
798  FOR_EACH_RANGE (i, 0, n) {
799  doNotOptimizeAway(to<std::string>(int128Pos[index] + (i % 8)).size());
800  }
801 }
802 
803 void i128ToStringFollyMeasureNeg(unsigned int n, size_t index) {
804  checkArrayIndex(int128Neg, index);
805  FOR_EACH_RANGE (i, 0, n) {
806  doNotOptimizeAway(to<std::string>(int128Neg[index] + (i % 8)).size());
807  }
808 }
809 
810 #define DEFINE_BENCHMARK_GROUP(n) \
811  BENCHMARK_PARAM(u128ToStringFollyMeasure, n) \
812  BENCHMARK_RELATIVE_PARAM(i128ToStringFollyMeasurePos, n) \
813  BENCHMARK_RELATIVE_PARAM(i128ToStringFollyMeasureNeg, n) \
814  BENCHMARK_DRAW_LINE()
815 
855 
857 
858 #undef DEFINE_BENCHMARK_GROUP
859 
860 #endif
861 
862 #define DEFINE_BENCHMARK_GROUP(n) \
863  BENCHMARK_PARAM(clibAtoiMeasure, n) \
864  BENCHMARK_RELATIVE_PARAM(lexicalCastMeasure, n) \
865  BENCHMARK_RELATIVE_PARAM(handwrittenAtoiMeasure, n) \
866  BENCHMARK_RELATIVE_PARAM(follyAtoiMeasure, n) \
867  BENCHMARK_DRAW_LINE()
868 
888 
889 #undef DEFINE_BENCHMARK_GROUP
890 
891 #define DEFINE_BENCHMARK_GROUP(T, n) \
892  BENCHMARK_PARAM(T##VariadicToBM, n) \
893  BENCHMARK_RELATIVE_PARAM(T##IdenticalToBM, n) \
894  BENCHMARK_DRAW_LINE()
895 
896 DEFINE_BENCHMARK_GROUP(string, 32);
897 DEFINE_BENCHMARK_GROUP(string, 1024);
898 DEFINE_BENCHMARK_GROUP(string, 32768);
902 
903 #undef DEFINE_BENCHMARK_GROUP
904 
905 namespace {
906 
907 template <typename T>
908 inline void stringToTypeClassic(const char* str, uint32_t n) {
909  for (uint32_t i = 0; i < n; ++i) {
910  try {
911  auto val = to<T>(str);
913  } catch (const std::exception& e) {
914  doNotOptimizeAway(e.what());
915  }
917  }
918 }
919 
920 template <typename T>
921 inline void stringToTypeOptional(const char* str, uint32_t n) {
922  for (uint32_t i = 0; i < n; ++i) {
923  auto val = tryTo<T>(str);
924  if (val.hasValue()) {
925  doNotOptimizeAway(val.value());
926  }
927  }
928 }
929 
930 template <typename T>
931 inline void ptrPairToIntClassic(StringPiece sp, uint32_t n) {
932  for (uint32_t i = 0; i < n; ++i) {
933  try {
934  auto val = to<T>(sp.begin(), sp.end());
936  } catch (const std::exception& e) {
937  doNotOptimizeAway(e.what());
938  }
940  }
941 }
942 
943 template <typename T>
944 inline void ptrPairToIntOptional(StringPiece sp, uint32_t n) {
945  for (uint32_t i = 0; i < n; ++i) {
946  auto val = tryTo<T>(sp.begin(), sp.end());
947  if (val.hasValue()) {
948  doNotOptimizeAway(val.value());
949  }
950  }
951 }
952 
953 constexpr uint32_t kArithNumIter = 10000;
954 
955 template <typename T, typename U>
956 inline size_t arithToArithClassic(const U* in, uint32_t numItems) {
957  for (uint32_t i = 0; i < kArithNumIter; ++i) {
958  for (uint32_t j = 0; j < numItems; ++j) {
959  try {
960  auto val = to<T>(in[j]);
962  } catch (const std::exception& e) {
963  doNotOptimizeAway(e.what());
964  }
966  }
968  }
969 
970  return kArithNumIter * numItems;
971 }
972 
973 template <typename T, typename U>
974 inline size_t arithToArithOptional(const U* in, uint32_t numItems) {
975  for (uint32_t i = 0; i < kArithNumIter; ++i) {
976  for (uint32_t j = 0; j < numItems; ++j) {
977  auto val = tryTo<T>(*in);
978  doNotOptimizeAway(val.hasValue());
979  if (val.hasValue()) {
980  auto v2 = val.value();
981  doNotOptimizeAway(v2);
982  }
984  }
986  }
987 
988  return kArithNumIter * numItems;
989 }
990 
991 } // namespace
992 
993 namespace folly {
994 namespace conv_bench_detail {
995 
996 // Keep this data global and non-const, so the compiler cannot make
997 // any assumptions about the actual values at compile time
998 
999 std::array<int, 4> int2ScharGood{{-128, 127, 0, -50}};
1000 std::array<int, 4> int2ScharBad{{-129, 128, 255, 10000}};
1001 std::array<int, 4> int2UcharGood{{0, 1, 254, 255}};
1002 std::array<int, 4> int2UcharBad{{-128, -1000, 256, -1}};
1003 
1004 std::array<long long, 4> ll2SintOrFloatGood{{-2, -1, 0, 1}};
1005 std::array<long long, 4> ll2SintOrFloatBad{{
1010 }};
1011 std::array<long long, 4> ll2UintGood{{1, 2, 3, 4}};
1012 std::array<long long, 4> ll2UintBad{{-1, -2, -3, -4}};
1013 
1014 std::array<double, 4> double2FloatGood{{1.0, 1.25, 2.5, 1000.0}};
1015 std::array<double, 4> double2FloatBad{{1e100, 1e101, 1e102, 1e103}};
1016 std::array<double, 4> double2IntGood{{1.0, 10.0, 100.0, 1000.0}};
1017 std::array<double, 4> double2IntBad{{1e100, 1.25, 2.5, 100.00001}};
1018 } // namespace conv_bench_detail
1019 } // namespace folly
1020 
1021 #define STRING_TO_TYPE_BENCHMARK(type, name, pass, fail) \
1022  BENCHMARK(stringTo##name##Classic, n) { \
1023  stringToTypeClassic<type>(pass, n); \
1024  } \
1025  BENCHMARK(stringTo##name##ClassicError, n) { \
1026  stringToTypeClassic<type>(fail, n); \
1027  } \
1028  BENCHMARK(stringTo##name##Optional, n) { \
1029  stringToTypeOptional<type>(pass, n); \
1030  } \
1031  BENCHMARK(stringTo##name##OptionalError, n) { \
1032  stringToTypeOptional<type>(fail, n); \
1033  }
1034 
1035 #define PTR_PAIR_TO_INT_BENCHMARK(type, name, pass, fail) \
1036  BENCHMARK(ptrPairTo##name##Classic, n) { \
1037  ptrPairToIntClassic<type>(pass, n); \
1038  } \
1039  BENCHMARK(ptrPairTo##name##ClassicError, n) { \
1040  ptrPairToIntClassic<type>(fail, n); \
1041  } \
1042  BENCHMARK(ptrPairTo##name##Optional, n) { \
1043  ptrPairToIntOptional<type>(pass, n); \
1044  } \
1045  BENCHMARK(ptrPairTo##name##OptionalError, n) { \
1046  ptrPairToIntOptional<type>(fail, n); \
1047  }
1048 
1049 #define ARITH_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1050  BENCHMARK_MULTI(name##Classic) { \
1051  return arithToArithClassic<type>(pass.data(), pass.size()); \
1052  } \
1053  BENCHMARK_MULTI(name##ClassicError) { \
1054  return arithToArithClassic<type>(fail.data(), fail.size()); \
1055  } \
1056  BENCHMARK_MULTI(name##Optional) { \
1057  return arithToArithOptional<type>(pass.data(), pass.size()); \
1058  } \
1059  BENCHMARK_MULTI(name##OptionalError) { \
1060  return arithToArithOptional<type>(fail.data(), fail.size()); \
1061  }
1062 
1063 #define INT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1064  ARITH_TO_ARITH_BENCHMARK(type, intTo##name, pass, fail)
1065 
1066 #define FLOAT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1067  ARITH_TO_ARITH_BENCHMARK(type, floatTo##name, pass, fail)
1068 
1069 STRING_TO_TYPE_BENCHMARK(bool, BoolNum, " 1 ", "2")
1070 STRING_TO_TYPE_BENCHMARK(bool, BoolStr, "true", "xxxx")
1071 BENCHMARK_DRAW_LINE();
1072 STRING_TO_TYPE_BENCHMARK(float, FloatNum, " 3.14 ", "3e5000x")
1073 STRING_TO_TYPE_BENCHMARK(float, FloatStr, "-infinity", "xxxx")
1074 STRING_TO_TYPE_BENCHMARK(double, DoubleNum, " 3.14 ", "3e5000x")
1075 STRING_TO_TYPE_BENCHMARK(double, DoubleStr, "-infinity", "xxxx")
1076 BENCHMARK_DRAW_LINE();
1077 STRING_TO_TYPE_BENCHMARK(signed char, CharSigned, " -47 ", "1000")
1078 STRING_TO_TYPE_BENCHMARK(unsigned char, CharUnsigned, " 47 ", "-47")
1079 STRING_TO_TYPE_BENCHMARK(int, IntSigned, " -4711 ", "-10000000000000000000000")
1080 STRING_TO_TYPE_BENCHMARK(unsigned int, IntUnsigned, " 4711 ", "-4711")
1082  long long,
1083  LongLongSigned,
1084  " -8123456789123456789 ",
1085  "-10000000000000000000000")
1087  unsigned long long,
1088  LongLongUnsigned,
1089  " 18123456789123456789 ",
1090  "-4711")
1091 BENCHMARK_DRAW_LINE();
1092 
1093 PTR_PAIR_TO_INT_BENCHMARK(signed char, CharSigned, "-47", "1000")
1094 PTR_PAIR_TO_INT_BENCHMARK(unsigned char, CharUnsigned, "47", "1000")
1095 PTR_PAIR_TO_INT_BENCHMARK(int, IntSigned, "-4711", "-10000000000000000000000")
1097  unsigned int,
1098  IntUnsigned,
1099  "4711",
1100  "10000000000000000000000")
1102  long long,
1103  LongLongSigned,
1104  "-8123456789123456789",
1105  "-10000000000000000000000")
1107  unsigned long long,
1108  LongLongUnsigned,
1109  "18123456789123456789",
1110  "20000000000000000000")
1111 BENCHMARK_DRAW_LINE();
1112 
1114 INT_TO_ARITH_BENCHMARK(unsigned char, CharUnsigned, int2UcharGood, int2UcharBad)
1116 INT_TO_ARITH_BENCHMARK(unsigned int, IntUnsigned, ll2UintGood, ll2UintBad)
1117 BENCHMARK_DRAW_LINE();
1118 INT_TO_ARITH_BENCHMARK(float, Float, ll2SintOrFloatGood, ll2SintOrFloatBad)
1119 BENCHMARK_DRAW_LINE();
1121 BENCHMARK_DRAW_LINE();
1123 
1124 #undef STRING_TO_TYPE_BENCHMARK
1125 #undef PTR_PAIR_TO_INT_BENCHMARK
1126 #undef ARITH_TO_ARITH_BENCHMARK
1127 #undef INT_TO_ARITH_BENCHMARK
1128 #undef FLOAT_TO_ARITH_BENCHMARK
1129 
1130 int main(int argc, char** argv) {
1131  gflags::ParseCommandLineFlags(&argc, &argv, true);
1133  return 0;
1134 }
std::array< long long, 4 > ll2UintBad
std::vector< uint8_t > buffer(kBufferSize+16)
void i64ToStringFollyMeasurePos(unsigned int n, size_t index)
#define T(v)
Definition: http_parser.c:233
BENCHMARK_DRAW_LINE()
uint32_t uint64ToBufferUnsafe(uint64_t v, char *const buffer)
Definition: Conv.h:383
LogLevel max
Definition: LogLevel.cpp:31
unsigned u64ToAsciiClassic(uint64_t value, char *dst)
void clibAtoiMeasure(unsigned int n, unsigned int digits)
#define INT_TO_ARITH_BENCHMARK(type, name, pass, fail)
void i64ToStringFollyMeasureNeg(unsigned int n, size_t index)
std::array< double, 4 > double2FloatBad
std::array< int, 4 > int2UcharGood
static const StringVariadicToBM< fbstring > fbstringVariadicToBM
#define BENCHMARK_SUSPEND
Definition: Benchmark.h:576
uint32_t digits10(uint64_t v)
Definition: Conv.h:295
std::array< double, 4 > double2IntBad
std::array< double, 4 > double2IntGood
STL namespace.
constexpr size_type size() const
Definition: Range.h:431
double val
Definition: String.cpp:273
void operator()(unsigned int n, size_t len) const
static const StringIdenticalToBM< std::string > stringIdenticalToBM
BENCHMARK_PARAM(u64ToAsciiClassicBM, 1) BENCHMARK_RELATIVE_PARAM(u64ToAsciiTableBM
void u64ToAsciiTableBM(unsigned int n, size_t index)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void runBenchmarks()
Definition: Benchmark.cpp:456
std::array< long long, 4 > ll2SintOrFloatGood
#define DEFINE_BENCHMARK_GROUP(n)
std::array< long long, 4 > ll2UintGood
void follyAtoiMeasure(unsigned int n, unsigned int digits)
void u2aAppendFollyBM(unsigned int n, size_t index)
void u64ToStringClibMeasure(unsigned int n, size_t index)
static int64_t handwrittenAtoi(const char *start, const char *end)
#define FOR_EACH_RANGE(i, begin, end)
Definition: Foreach.h:313
#define PTR_PAIR_TO_INT_BENCHMARK(type, name, pass, fail)
char ** argv
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
int main(int argc, char **argv)
unsigned u64ToAsciiTable(uint64_t value, char *dst)
LogLevel min
Definition: LogLevel.cpp:30
#define FOLLY_RANGE_CHECK_TO_STRING(x)
BENCHMARK_RELATIVE_PARAM(u64ToAsciiFollyBM, 1) BENCHMARK_DRAW_LINE()
FloatingPoint< float > Float
void u64ToAsciiFollyBM(unsigned int n, size_t index)
std::array< double, 4 > double2FloatGood
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
Range subpiece(size_type first, size_type length=npos) const
Definition: Range.h:686
std::array< long long, 4 > ll2SintOrFloatBad
static const StringVariadicToBM< std::string > stringVariadicToBM
void handwrittenAtoiMeasure(unsigned int n, unsigned int digits)
std::array< int, 4 > int2ScharGood
static const char *const value
Definition: Conv.cpp:50
auto start
constexpr Iter end() const
Definition: Range.h:455
constexpr Iter begin() const
Definition: Range.h:452
void u64ToAsciiClassicBM(unsigned int n, size_t index)
void u2aAppendClassicBM(unsigned int n, size_t index)
const char * string
Definition: Conv.cpp:212
void operator()(unsigned int n, size_t len) const
#define FLOAT_TO_ARITH_BENCHMARK(type, name, pass, fail)
static set< string > s
void swap(SwapTrackingAlloc< T > &, SwapTrackingAlloc< T > &)
Definition: F14TestUtil.h:414
void u64ToStringFollyMeasure(unsigned int n, size_t index)
BENCHMARK(preallocateTestNoFloat, n)
#define STRING_TO_TYPE_BENCHMARK(type, name, pass, fail)
static StringPiece pc1
void lexicalCastMeasure(unsigned int n, unsigned int digits)
std::array< int, 4 > int2UcharBad
#define FOLLY_FALLTHROUGH
Definition: CppAttributes.h:63
static const StringIdenticalToBM< fbstring > fbstringIdenticalToBM
auto doNotOptimizeAway(const T &datum) -> typename std::enable_if< !detail::DoNotOptimizeAwayNeedsIndirect< T >::value >::type
Definition: Benchmark.h:258
std::array< int, 4 > int2ScharBad
def next(obj)
Definition: ast.py:58