Fix some copyright lines in folly/
[folly.git] / folly / test / ConvBenchmark.cpp
1 /*
2  * Copyright 2011-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>
23 #include <folly/container/Foreach.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
45 uint64_t uint64Num[] = {
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
69 int64_t int64Pos[] = {
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
92 int64_t int64Neg[] = {
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
260 ////////////////////////////////////////////////////////////////////////////////
261 // Benchmarks for ASCII to int conversion
262 ////////////////////////////////////////////////////////////////////////////////
263 // @author: Rajat Goel (rajat)
264
265 static int64_t handwrittenAtoi(const char* start, const char* end) {
266
267   bool positive = true;
268   int64_t retVal = 0;
269
270   if (start == end) {
271     throw std::runtime_error("empty string");
272   }
273
274   while (start < end && isspace(*start)) {
275     ++start;
276   }
277
278   switch (*start) {
279     case '-':
280       positive = false;
281       FOLLY_FALLTHROUGH;
282     case '+':
283       ++start;
284       FOLLY_FALLTHROUGH;
285     default:
286       break;
287   }
288
289   while (start < end && *start >= '0' && *start <= '9') {
290     auto const newRetVal = retVal * 10 + (*start++ - '0');
291     if (newRetVal < retVal) {
292       throw std::runtime_error("overflow");
293     }
294     retVal = newRetVal;
295   }
296
297   if (start != end) {
298     throw std::runtime_error("extra chars at the end");
299   }
300
301   return positive ? retVal : -retVal;
302 }
303
304 static StringPiece pc1 = "1234567890123456789";
305
306 void handwrittenAtoiMeasure(unsigned int n, unsigned int digits) {
307   auto p = pc1.subpiece(pc1.size() - digits, digits);
308   FOR_EACH_RANGE(i, 0, n) {
309     doNotOptimizeAway(handwrittenAtoi(p.begin(), p.end()));
310   }
311 }
312
313 void follyAtoiMeasure(unsigned int n, unsigned int digits) {
314   auto p = pc1.subpiece(pc1.size() - digits, digits);
315   FOR_EACH_RANGE(i, 0, n) {
316     doNotOptimizeAway(folly::to<int64_t>(p.begin(), p.end()));
317   }
318 }
319
320 void clibAtoiMeasure(unsigned int n, unsigned int digits) {
321   auto p = pc1.subpiece(pc1.size() - digits, digits);
322   assert(*p.end() == 0);
323   FOR_EACH_RANGE(i, 0, n) { doNotOptimizeAway(atoll(p.begin())); }
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 } // namespace conv_bench_detail
515 } // namespace folly
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 } // namespace conv_bench_detail
590 } // namespace folly
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 } // namespace
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 stringToTypeOptional(const char* str, uint32_t n) {
919   for (uint32_t i = 0; i < n; ++i) {
920     auto val = tryTo<T>(str);
921     if (val.hasValue()) {
922       doNotOptimizeAway(val.value());
923     }
924   }
925 }
926
927 template <typename T>
928 inline void ptrPairToIntClassic(StringPiece sp, uint32_t n) {
929   for (uint32_t i = 0; i < n; ++i) {
930     try {
931       auto val = to<T>(sp.begin(), sp.end());
932       doNotOptimizeAway(val);
933     } catch (const std::exception& e) {
934       doNotOptimizeAway(e.what());
935     }
936     doNotOptimizeAway(i);
937   }
938 }
939
940 template <typename T>
941 inline void ptrPairToIntOptional(StringPiece sp, uint32_t n) {
942   for (uint32_t i = 0; i < n; ++i) {
943     auto val = tryTo<T>(sp.begin(), sp.end());
944     if (val.hasValue()) {
945       doNotOptimizeAway(val.value());
946     }
947   }
948 }
949
950 constexpr uint32_t kArithNumIter = 10000;
951
952 template <typename T, typename U>
953 inline size_t arithToArithClassic(const U* in, uint32_t numItems) {
954   for (uint32_t i = 0; i < kArithNumIter; ++i) {
955     for (uint32_t j = 0; j < numItems; ++j) {
956       try {
957         auto val = to<T>(in[j]);
958         doNotOptimizeAway(val);
959       } catch (const std::exception& e) {
960         doNotOptimizeAway(e.what());
961       }
962       doNotOptimizeAway(j);
963     }
964     doNotOptimizeAway(i);
965   }
966
967   return kArithNumIter * numItems;
968 }
969
970 template <typename T, typename U>
971 inline size_t arithToArithOptional(const U* in, uint32_t numItems) {
972   for (uint32_t i = 0; i < kArithNumIter; ++i) {
973     for (uint32_t j = 0; j < numItems; ++j) {
974       auto val = tryTo<T>(*in);
975       doNotOptimizeAway(val.hasValue());
976       if (val.hasValue()) {
977         auto v2 = val.value();
978         doNotOptimizeAway(v2);
979       }
980       doNotOptimizeAway(j);
981     }
982     doNotOptimizeAway(i);
983   }
984
985   return kArithNumIter * numItems;
986 }
987
988 } // namespace
989
990 namespace folly {
991 namespace conv_bench_detail {
992
993 // Keep this data global and non-const, so the compiler cannot make
994 // any assumptions about the actual values at compile time
995
996 std::array<int, 4> int2ScharGood{{-128, 127, 0, -50}};
997 std::array<int, 4> int2ScharBad{{-129, 128, 255, 10000}};
998 std::array<int, 4> int2UcharGood{{0, 1, 254, 255}};
999 std::array<int, 4> int2UcharBad{{-128, -1000, 256, -1}};
1000
1001 std::array<long long, 4> ll2SintOrFloatGood{{-2, -1, 0, 1}};
1002 std::array<long long, 4> ll2SintOrFloatBad{{
1003     std::numeric_limits<long long>::min() / 5,
1004     std::numeric_limits<long long>::min() / 2,
1005     std::numeric_limits<long long>::max() / 2,
1006     std::numeric_limits<long long>::max() / 5,
1007 }};
1008 std::array<long long, 4> ll2UintGood{{1, 2, 3, 4}};
1009 std::array<long long, 4> ll2UintBad{{-1, -2, -3, -4}};
1010
1011 std::array<double, 4> double2FloatGood{{1.0, 1.25, 2.5, 1000.0}};
1012 std::array<double, 4> double2FloatBad{{1e100, 1e101, 1e102, 1e103}};
1013 std::array<double, 4> double2IntGood{{1.0, 10.0, 100.0, 1000.0}};
1014 std::array<double, 4> double2IntBad{{1e100, 1.25, 2.5, 100.00001}};
1015 } // namespace conv_bench_detail
1016 } // namespace folly
1017
1018 #define STRING_TO_TYPE_BENCHMARK(type, name, pass, fail) \
1019   BENCHMARK(stringTo##name##Classic, n) {                \
1020     stringToTypeClassic<type>(pass, n);                  \
1021   }                                                      \
1022   BENCHMARK(stringTo##name##ClassicError, n) {           \
1023     stringToTypeClassic<type>(fail, n);                  \
1024   }                                                      \
1025   BENCHMARK(stringTo##name##Optional, n) {               \
1026     stringToTypeOptional<type>(pass, n);                 \
1027   }                                                      \
1028   BENCHMARK(stringTo##name##OptionalError, n) {          \
1029     stringToTypeOptional<type>(fail, n);                 \
1030   }
1031
1032 #define PTR_PAIR_TO_INT_BENCHMARK(type, name, pass, fail) \
1033   BENCHMARK(ptrPairTo##name##Classic, n) {                \
1034     ptrPairToIntClassic<type>(pass, n);                   \
1035   }                                                       \
1036   BENCHMARK(ptrPairTo##name##ClassicError, n) {           \
1037     ptrPairToIntClassic<type>(fail, n);                   \
1038   }                                                       \
1039   BENCHMARK(ptrPairTo##name##Optional, n) {               \
1040     ptrPairToIntOptional<type>(pass, n);                  \
1041   }                                                       \
1042   BENCHMARK(ptrPairTo##name##OptionalError, n) {          \
1043     ptrPairToIntOptional<type>(fail, n);                  \
1044   }
1045
1046 #define ARITH_TO_ARITH_BENCHMARK(type, name, pass, fail)         \
1047   BENCHMARK_MULTI(name##Classic) {                               \
1048     return arithToArithClassic<type>(pass.data(), pass.size());  \
1049   }                                                              \
1050   BENCHMARK_MULTI(name##ClassicError) {                          \
1051     return arithToArithClassic<type>(fail.data(), fail.size());  \
1052   }                                                              \
1053   BENCHMARK_MULTI(name##Optional) {                              \
1054     return arithToArithOptional<type>(pass.data(), pass.size()); \
1055   }                                                              \
1056   BENCHMARK_MULTI(name##OptionalError) {                         \
1057     return arithToArithOptional<type>(fail.data(), fail.size()); \
1058   }
1059
1060 #define INT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1061   ARITH_TO_ARITH_BENCHMARK(type, intTo##name, pass, fail)
1062
1063 #define FLOAT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1064   ARITH_TO_ARITH_BENCHMARK(type, floatTo##name, pass, fail)
1065
1066 STRING_TO_TYPE_BENCHMARK(bool, BoolNum, " 1 ", "2")
1067 STRING_TO_TYPE_BENCHMARK(bool, BoolStr, "true", "xxxx")
1068 BENCHMARK_DRAW_LINE();
1069 STRING_TO_TYPE_BENCHMARK(float, FloatNum, " 3.14 ", "3e5000x")
1070 STRING_TO_TYPE_BENCHMARK(float, FloatStr, "-infinity", "xxxx")
1071 STRING_TO_TYPE_BENCHMARK(double, DoubleNum, " 3.14 ", "3e5000x")
1072 STRING_TO_TYPE_BENCHMARK(double, DoubleStr, "-infinity", "xxxx")
1073 BENCHMARK_DRAW_LINE();
1074 STRING_TO_TYPE_BENCHMARK(signed char, CharSigned, " -47 ", "1000")
1075 STRING_TO_TYPE_BENCHMARK(unsigned char, CharUnsigned, " 47 ", "-47")
1076 STRING_TO_TYPE_BENCHMARK(int, IntSigned, " -4711 ", "-10000000000000000000000")
1077 STRING_TO_TYPE_BENCHMARK(unsigned int, IntUnsigned, " 4711 ", "-4711")
1078 STRING_TO_TYPE_BENCHMARK(
1079     long long,
1080     LongLongSigned,
1081     " -8123456789123456789 ",
1082     "-10000000000000000000000")
1083 STRING_TO_TYPE_BENCHMARK(
1084     unsigned long long,
1085     LongLongUnsigned,
1086     " 18123456789123456789 ",
1087     "-4711")
1088 BENCHMARK_DRAW_LINE();
1089
1090 PTR_PAIR_TO_INT_BENCHMARK(signed char, CharSigned, "-47", "1000")
1091 PTR_PAIR_TO_INT_BENCHMARK(unsigned char, CharUnsigned, "47", "1000")
1092 PTR_PAIR_TO_INT_BENCHMARK(int, IntSigned, "-4711", "-10000000000000000000000")
1093 PTR_PAIR_TO_INT_BENCHMARK(
1094     unsigned int,
1095     IntUnsigned,
1096     "4711",
1097     "10000000000000000000000")
1098 PTR_PAIR_TO_INT_BENCHMARK(
1099     long long,
1100     LongLongSigned,
1101     "-8123456789123456789",
1102     "-10000000000000000000000")
1103 PTR_PAIR_TO_INT_BENCHMARK(
1104     unsigned long long,
1105     LongLongUnsigned,
1106     "18123456789123456789",
1107     "20000000000000000000")
1108 BENCHMARK_DRAW_LINE();
1109
1110 INT_TO_ARITH_BENCHMARK(signed char, CharSigned, int2ScharGood, int2ScharBad)
1111 INT_TO_ARITH_BENCHMARK(unsigned char, CharUnsigned, int2UcharGood, int2UcharBad)
1112 INT_TO_ARITH_BENCHMARK(int, IntSigned, ll2SintOrFloatGood, ll2SintOrFloatBad)
1113 INT_TO_ARITH_BENCHMARK(unsigned int, IntUnsigned, ll2UintGood, ll2UintBad)
1114 BENCHMARK_DRAW_LINE();
1115 INT_TO_ARITH_BENCHMARK(float, Float, ll2SintOrFloatGood, ll2SintOrFloatBad)
1116 BENCHMARK_DRAW_LINE();
1117 FLOAT_TO_ARITH_BENCHMARK(float, Float, double2FloatGood, double2FloatBad)
1118 BENCHMARK_DRAW_LINE();
1119 FLOAT_TO_ARITH_BENCHMARK(int, Int, double2IntGood, double2IntBad)
1120
1121 #undef STRING_TO_TYPE_BENCHMARK
1122 #undef PTR_PAIR_TO_INT_BENCHMARK
1123 #undef ARITH_TO_ARITH_BENCHMARK
1124 #undef INT_TO_ARITH_BENCHMARK
1125 #undef FLOAT_TO_ARITH_BENCHMARK
1126
1127 int main(int argc, char** argv) {
1128   gflags::ParseCommandLineFlags(&argc, &argv, true);
1129   folly::runBenchmarks();
1130   return 0;
1131 }