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