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