Fix the linking of various tests against GMock
[folly.git] / folly / test / ConvBenchmark.cpp
1 /*
2  * Copyright 2017 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   FOR_EACH_RANGE(i, 0, n) { doNotOptimizeAway(atoll(p.begin())); }
321 }
322
323 void lexicalCastMeasure(unsigned int n, unsigned int digits) {
324   auto p = pc1.subpiece(pc1.size() - digits, digits);
325   assert(*p.end() == 0);
326   FOR_EACH_RANGE(i, 0, n) {
327     doNotOptimizeAway(boost::lexical_cast<uint64_t>(p.begin()));
328   }
329 }
330
331 // Benchmarks for unsigned to string conversion, raw
332
333 unsigned u64ToAsciiTable(uint64_t value, char* dst) {
334   static const char digits[201] =
335       "00010203040506070809"
336       "10111213141516171819"
337       "20212223242526272829"
338       "30313233343536373839"
339       "40414243444546474849"
340       "50515253545556575859"
341       "60616263646566676869"
342       "70717273747576777879"
343       "80818283848586878889"
344       "90919293949596979899";
345
346   uint32_t const length = digits10(value);
347   uint32_t next = length - 1;
348   while (value >= 100) {
349     auto const i = (value % 100) * 2;
350     value /= 100;
351     dst[next] = digits[i + 1];
352     dst[next - 1] = digits[i];
353     next -= 2;
354   }
355   // Handle last 1-2 digits
356   if (value < 10) {
357     dst[next] = '0' + uint32_t(value);
358   } else {
359     auto i = uint32_t(value) * 2;
360     dst[next] = digits[i + 1];
361     dst[next - 1] = digits[i];
362   }
363   return length;
364 }
365
366 void u64ToAsciiTableBM(unsigned int n, size_t index) {
367   checkArrayIndex(uint64Num, index);
368   char buf[20];
369   FOR_EACH_RANGE(i, 0, n) {
370     doNotOptimizeAway(u64ToAsciiTable(uint64Num[index] + (i % 8), buf));
371   }
372 }
373
374 unsigned u64ToAsciiClassic(uint64_t value, char* dst) {
375   // Write backwards.
376   char* next = (char*)dst;
377   char* start = next;
378   do {
379     *next++ = '0' + (value % 10);
380     value /= 10;
381   } while (value != 0);
382   unsigned length = next - start;
383
384   // Reverse in-place.
385   next--;
386   while (next > start) {
387     char swap = *next;
388     *next = *start;
389     *start = swap;
390     next--;
391     start++;
392   }
393   return length;
394 }
395
396 void u64ToAsciiClassicBM(unsigned int n, size_t index) {
397   checkArrayIndex(uint64Num, index);
398   char buf[20];
399   FOR_EACH_RANGE(i, 0, n) {
400     doNotOptimizeAway(u64ToAsciiClassic(uint64Num[index] + (i % 8), buf));
401   }
402 }
403
404 void u64ToAsciiFollyBM(unsigned int n, size_t index) {
405   checkArrayIndex(uint64Num, index);
406   char buf[20];
407   FOR_EACH_RANGE(i, 0, n) {
408     doNotOptimizeAway(uint64ToBufferUnsafe(uint64Num[index] + (i % 8), buf));
409   }
410 }
411
412 // Benchmark unsigned to string conversion
413
414 void u64ToStringClibMeasure(unsigned int n, size_t index) {
415   // FOLLY_RANGE_CHECK_TO_STRING expands to std::to_string, except on Android
416   // where std::to_string is not supported
417   checkArrayIndex(uint64Num, index);
418   FOR_EACH_RANGE (i, 0, n) {
419     doNotOptimizeAway(
420         FOLLY_RANGE_CHECK_TO_STRING(uint64Num[index] + (i % 8)).size());
421   }
422 }
423
424 void u64ToStringFollyMeasure(unsigned int n, size_t index) {
425   checkArrayIndex(uint64Num, index);
426   FOR_EACH_RANGE (i, 0, n) {
427     doNotOptimizeAway(to<std::string>(uint64Num[index] + (i % 8)).size());
428   }
429 }
430
431 // Signed
432
433 void i64ToStringFollyMeasurePos(unsigned int n, size_t index) {
434   checkArrayIndex(int64Pos, index);
435   FOR_EACH_RANGE (i, 0, n) {
436     doNotOptimizeAway(to<std::string>(int64Pos[index] + (i % 8)).size());
437   }
438 }
439
440 void i64ToStringFollyMeasureNeg(unsigned int n, size_t index) {
441   checkArrayIndex(int64Neg, index);
442   FOR_EACH_RANGE (i, 0, n) {
443     doNotOptimizeAway(to<std::string>(int64Neg[index] - (i % 8)).size());
444   }
445 }
446
447 // Benchmark uitoa with string append
448
449 void u2aAppendClassicBM(unsigned int n, size_t index) {
450   checkArrayIndex(uint64Num, index);
451   string s;
452   FOR_EACH_RANGE(i, 0, n) {
453     // auto buf = &s.back() + 1;
454     char buffer[20];
455     s.append(buffer, u64ToAsciiClassic(uint64Num[index] + (i % 8), buffer));
456     doNotOptimizeAway(s.size());
457   }
458 }
459
460 void u2aAppendFollyBM(unsigned int n, size_t index) {
461   checkArrayIndex(uint64Num, index);
462   string s;
463   FOR_EACH_RANGE(i, 0, n) {
464     // auto buf = &s.back() + 1;
465     char buffer[20];
466     s.append(buffer, uint64ToBufferUnsafe(uint64Num[index] + (i % 8), buffer));
467     doNotOptimizeAway(s.size());
468   }
469 }
470
471 template <class String>
472 struct StringIdenticalToBM {
473   StringIdenticalToBM() {}
474   void operator()(unsigned int n, size_t len) const {
475     String s;
476     BENCHMARK_SUSPEND { s.append(len, '0'); }
477     FOR_EACH_RANGE(i, 0, n) {
478       String result = to<String>(s);
479       doNotOptimizeAway(result.size());
480     }
481   }
482 };
483
484 template <class String>
485 struct StringVariadicToBM {
486   StringVariadicToBM() {}
487   void operator()(unsigned int n, size_t len) const {
488     String s;
489     BENCHMARK_SUSPEND { s.append(len, '0'); }
490     FOR_EACH_RANGE(i, 0, n) {
491       String result = to<String>(s, nullptr);
492       doNotOptimizeAway(result.size());
493     }
494   }
495 };
496
497 namespace folly {
498 namespace conv_bench_detail {
499
500 // Keep this data global and non-const, so the compiler cannot make
501 // any assumptions about the actual values at compile time
502
503 size_t bigInt = 11424545345345;
504 size_t smallInt = 104;
505 char someString[] = "this is some nice string";
506 char otherString[] = "this is a long string, so it's not so nice";
507 char reallyShort[] = "meh";
508 std::string stdString = "std::strings are very nice";
509 float fValue = 1.2355f;
510 double dValue = 345345345.435;
511 }
512 }
513
514 BENCHMARK(preallocateTestNoFloat, n) {
515   for (size_t i = 0; i < n; ++i) {
516     doNotOptimizeAway(
517         to<std::string>(bigInt, someString, stdString, otherString).size());
518     doNotOptimizeAway(to<std::string>(reallyShort, smallInt).size());
519     doNotOptimizeAway(to<std::string>(bigInt, stdString).size());
520     doNotOptimizeAway(
521         to<std::string>(bigInt, stdString, dValue, otherString).size());
522     doNotOptimizeAway(to<std::string>(bigInt, someString, reallyShort).size());
523   }
524 }
525
526 BENCHMARK(preallocateTestFloat, n) {
527   for (size_t i = 0; i < n; ++i) {
528     doNotOptimizeAway(to<std::string>(stdString, ',', fValue, dValue).size());
529     doNotOptimizeAway(to<std::string>(stdString, ',', dValue).size());
530   }
531 }
532
533 namespace folly {
534 namespace conv_bench_detail {
535
536 // Keep this data global and non-const, so the compiler cannot make
537 // any assumptions about the actual values at compile time
538
539 int8_t i8s[] = {
540     -(static_cast<int8_t>(1) << 4),
541     static_cast<int8_t>(1) << 5,
542     -(static_cast<int8_t>(1) << 6),
543 };
544
545 uint8_t u8s[] = {
546     static_cast<uint8_t>(1) << 4,
547     static_cast<uint8_t>(1) << 5,
548     static_cast<uint8_t>(1) << 7,
549 };
550
551 int16_t i16s[] = {
552     -(static_cast<int16_t>(1) << 8),
553     static_cast<int16_t>(1) << 12,
554     -(static_cast<int16_t>(1) << 14),
555 };
556
557 uint16_t u16s[] = {
558     static_cast<uint16_t>(1) << 8,
559     static_cast<uint16_t>(1) << 12,
560     static_cast<uint16_t>(1) << 15,
561 };
562
563 int32_t i32s[] = {
564     -(static_cast<int32_t>(1) << 16),
565     static_cast<int32_t>(1) << 25,
566     -(static_cast<int32_t>(1) << 30),
567 };
568
569 uint32_t u32s[] = {
570     static_cast<uint32_t>(1) << 16,
571     static_cast<uint32_t>(1) << 25,
572     static_cast<uint32_t>(1) << 31,
573 };
574
575 int64_t i64s[] = {
576     -(static_cast<int64_t>(1) << 32),
577     static_cast<int64_t>(1) << 50,
578     -(static_cast<int64_t>(1) << 62),
579 };
580
581 uint64_t u64s[] = {
582     static_cast<uint64_t>(1) << 32,
583     static_cast<uint64_t>(1) << 50,
584     static_cast<uint64_t>(1) << 63,
585 };
586 }
587 }
588
589 BENCHMARK(preallocateTestInt8, n) {
590   for (size_t i = 0; i < n; ++i) {
591     doNotOptimizeAway(to<std::string>(
592                           i8s[0],
593                           ',',
594                           u8s[0],
595                           ',',
596                           i8s[1],
597                           ',',
598                           u8s[1],
599                           ',',
600                           i8s[2],
601                           ',',
602                           u8s[2])
603                           .size());
604   }
605 }
606
607 BENCHMARK(preallocateTestInt16, n) {
608   for (size_t i = 0; i < n; ++i) {
609     doNotOptimizeAway(to<std::string>(
610                           i16s[0],
611                           ',',
612                           u16s[0],
613                           ',',
614                           i16s[1],
615                           ',',
616                           u16s[1],
617                           ',',
618                           i16s[2],
619                           ',',
620                           u16s[2])
621                           .size());
622   }
623 }
624
625 BENCHMARK(preallocateTestInt32, n) {
626   for (size_t i = 0; i < n; ++i) {
627     doNotOptimizeAway(to<std::string>(
628                           i32s[0],
629                           ',',
630                           u32s[0],
631                           ',',
632                           i32s[1],
633                           ',',
634                           u32s[1],
635                           ',',
636                           i32s[2],
637                           ',',
638                           u32s[2])
639                           .size());
640   }
641 }
642
643 BENCHMARK(preallocateTestInt64, n) {
644   for (size_t i = 0; i < n; ++i) {
645     doNotOptimizeAway(to<std::string>(
646                           i64s[0],
647                           ',',
648                           u64s[0],
649                           ',',
650                           i64s[1],
651                           ',',
652                           u64s[1],
653                           ',',
654                           i64s[2],
655                           ',',
656                           u64s[2])
657                           .size());
658   }
659 }
660
661 #if FOLLY_HAVE_INT128_T
662 namespace {
663
664 __int128 i128s[] = {
665     -(static_cast<__int128>(1) << 2),
666     static_cast<__int128>(1) << 100,
667     -(static_cast<__int128>(1) << 126),
668 };
669
670 unsigned __int128 u128s[] = {
671     static_cast<unsigned __int128>(1) << 2,
672     static_cast<unsigned __int128>(1) << 100,
673     static_cast<unsigned __int128>(1) << 127,
674 };
675 }
676
677 BENCHMARK(preallocateTestInt128, n) {
678   for (size_t i = 0; i < n; ++i) {
679     doNotOptimizeAway(to<std::string>(
680                           i128s[0],
681                           ',',
682                           u128s[0],
683                           ',',
684                           i128s[1],
685                           ',',
686                           u128s[1],
687                           ',',
688                           i128s[2],
689                           ',',
690                           u128s[2])
691                           .size());
692   }
693 }
694
695 BENCHMARK(preallocateTestNoFloatWithInt128, n) {
696   for (size_t i = 0; i < n; ++i) {
697     doNotOptimizeAway(
698         to<std::string>(bigInt, someString, stdString, otherString).size());
699     doNotOptimizeAway(
700         to<std::string>(reallyShort, u128s[0], smallInt, i128s[2]).size());
701     doNotOptimizeAway(
702         to<std::string>(bigInt, i128s[0], stdString, u128s[1]).size());
703     doNotOptimizeAway(
704         to<std::string>(bigInt, stdString, dValue, otherString).size());
705     doNotOptimizeAway(
706         to<std::string>(bigInt, u128s[2], someString, reallyShort).size());
707   }
708 }
709 #endif
710
711 BENCHMARK_DRAW_LINE();
712
713 static const StringIdenticalToBM<std::string> stringIdenticalToBM;
714 static const StringVariadicToBM<std::string> stringVariadicToBM;
715 static const StringIdenticalToBM<fbstring> fbstringIdenticalToBM;
716 static const StringVariadicToBM<fbstring> fbstringVariadicToBM;
717
718 #define DEFINE_BENCHMARK_GROUP(n)                 \
719   BENCHMARK_PARAM(u64ToAsciiClassicBM, n);        \
720   BENCHMARK_RELATIVE_PARAM(u64ToAsciiTableBM, n); \
721   BENCHMARK_RELATIVE_PARAM(u64ToAsciiFollyBM, n); \
722   BENCHMARK_DRAW_LINE();
723
724 DEFINE_BENCHMARK_GROUP(1);
725 DEFINE_BENCHMARK_GROUP(2);
726 DEFINE_BENCHMARK_GROUP(3);
727 DEFINE_BENCHMARK_GROUP(4);
728 DEFINE_BENCHMARK_GROUP(5);
729 DEFINE_BENCHMARK_GROUP(6);
730 DEFINE_BENCHMARK_GROUP(7);
731 DEFINE_BENCHMARK_GROUP(8);
732 DEFINE_BENCHMARK_GROUP(9);
733 DEFINE_BENCHMARK_GROUP(10);
734 DEFINE_BENCHMARK_GROUP(11);
735 DEFINE_BENCHMARK_GROUP(12);
736 DEFINE_BENCHMARK_GROUP(13);
737 DEFINE_BENCHMARK_GROUP(14);
738 DEFINE_BENCHMARK_GROUP(15);
739 DEFINE_BENCHMARK_GROUP(16);
740 DEFINE_BENCHMARK_GROUP(17);
741 DEFINE_BENCHMARK_GROUP(18);
742 DEFINE_BENCHMARK_GROUP(19);
743 DEFINE_BENCHMARK_GROUP(20);
744
745 #undef DEFINE_BENCHMARK_GROUP
746
747 #define DEFINE_BENCHMARK_GROUP(n)                          \
748   BENCHMARK_PARAM(u64ToStringClibMeasure, n);              \
749   BENCHMARK_RELATIVE_PARAM(u64ToStringFollyMeasure, n);    \
750   BENCHMARK_RELATIVE_PARAM(i64ToStringFollyMeasurePos, n); \
751   BENCHMARK_RELATIVE_PARAM(i64ToStringFollyMeasureNeg, n); \
752   BENCHMARK_DRAW_LINE();
753
754 DEFINE_BENCHMARK_GROUP(1);
755 DEFINE_BENCHMARK_GROUP(2);
756 DEFINE_BENCHMARK_GROUP(3);
757 DEFINE_BENCHMARK_GROUP(4);
758 DEFINE_BENCHMARK_GROUP(5);
759 DEFINE_BENCHMARK_GROUP(6);
760 DEFINE_BENCHMARK_GROUP(7);
761 DEFINE_BENCHMARK_GROUP(8);
762 DEFINE_BENCHMARK_GROUP(9);
763 DEFINE_BENCHMARK_GROUP(10);
764 DEFINE_BENCHMARK_GROUP(11);
765 DEFINE_BENCHMARK_GROUP(12);
766 DEFINE_BENCHMARK_GROUP(13);
767 DEFINE_BENCHMARK_GROUP(14);
768 DEFINE_BENCHMARK_GROUP(15);
769 DEFINE_BENCHMARK_GROUP(16);
770 DEFINE_BENCHMARK_GROUP(17);
771 DEFINE_BENCHMARK_GROUP(18);
772 DEFINE_BENCHMARK_GROUP(19);
773
774 // Only for u64
775 BENCHMARK_PARAM(u64ToStringClibMeasure, 20);
776 BENCHMARK_RELATIVE_PARAM(u64ToStringFollyMeasure, 20);
777 BENCHMARK_DRAW_LINE();
778
779 #undef DEFINE_BENCHMARK_GROUP
780
781 #if FOLLY_HAVE_INT128_T
782
783 void u128ToStringFollyMeasure(unsigned int n, size_t index) {
784   checkArrayIndex(uint128Num, index);
785   FOR_EACH_RANGE (i, 0, n) {
786     doNotOptimizeAway(to<std::string>(uint128Num[index] + (i % 8)).size());
787   }
788 }
789
790 void i128ToStringFollyMeasurePos(unsigned int n, size_t index) {
791   checkArrayIndex(int128Pos, index);
792   FOR_EACH_RANGE (i, 0, n) {
793     doNotOptimizeAway(to<std::string>(int128Pos[index] + (i % 8)).size());
794   }
795 }
796
797 void i128ToStringFollyMeasureNeg(unsigned int n, size_t index) {
798   checkArrayIndex(int128Neg, index);
799   FOR_EACH_RANGE (i, 0, n) {
800     doNotOptimizeAway(to<std::string>(int128Neg[index] + (i % 8)).size());
801   }
802 }
803
804 #define DEFINE_BENCHMARK_GROUP(n)                           \
805   BENCHMARK_PARAM(u128ToStringFollyMeasure, n);             \
806   BENCHMARK_RELATIVE_PARAM(i128ToStringFollyMeasurePos, n); \
807   BENCHMARK_RELATIVE_PARAM(i128ToStringFollyMeasureNeg, n); \
808   BENCHMARK_DRAW_LINE();
809
810 DEFINE_BENCHMARK_GROUP(1);
811 DEFINE_BENCHMARK_GROUP(2);
812 DEFINE_BENCHMARK_GROUP(3);
813 DEFINE_BENCHMARK_GROUP(4);
814 DEFINE_BENCHMARK_GROUP(5);
815 DEFINE_BENCHMARK_GROUP(6);
816 DEFINE_BENCHMARK_GROUP(7);
817 DEFINE_BENCHMARK_GROUP(8);
818 DEFINE_BENCHMARK_GROUP(9);
819 DEFINE_BENCHMARK_GROUP(10);
820 DEFINE_BENCHMARK_GROUP(11);
821 DEFINE_BENCHMARK_GROUP(12);
822 DEFINE_BENCHMARK_GROUP(13);
823 DEFINE_BENCHMARK_GROUP(14);
824 DEFINE_BENCHMARK_GROUP(15);
825 DEFINE_BENCHMARK_GROUP(16);
826 DEFINE_BENCHMARK_GROUP(17);
827 DEFINE_BENCHMARK_GROUP(18);
828 DEFINE_BENCHMARK_GROUP(19);
829 DEFINE_BENCHMARK_GROUP(20);
830 DEFINE_BENCHMARK_GROUP(21);
831 DEFINE_BENCHMARK_GROUP(22);
832 DEFINE_BENCHMARK_GROUP(23);
833 DEFINE_BENCHMARK_GROUP(24);
834 DEFINE_BENCHMARK_GROUP(25);
835 DEFINE_BENCHMARK_GROUP(26);
836 DEFINE_BENCHMARK_GROUP(27);
837 DEFINE_BENCHMARK_GROUP(28);
838 DEFINE_BENCHMARK_GROUP(29);
839 DEFINE_BENCHMARK_GROUP(30);
840 DEFINE_BENCHMARK_GROUP(31);
841 DEFINE_BENCHMARK_GROUP(32);
842 DEFINE_BENCHMARK_GROUP(33);
843 DEFINE_BENCHMARK_GROUP(34);
844 DEFINE_BENCHMARK_GROUP(35);
845 DEFINE_BENCHMARK_GROUP(36);
846 DEFINE_BENCHMARK_GROUP(37);
847 DEFINE_BENCHMARK_GROUP(38);
848 DEFINE_BENCHMARK_GROUP(39);
849
850 BENCHMARK_DRAW_LINE();
851
852 #undef DEFINE_BENCHMARK_GROUP
853
854 #endif
855
856 #define DEFINE_BENCHMARK_GROUP(n)                      \
857   BENCHMARK_PARAM(clibAtoiMeasure, n);                 \
858   BENCHMARK_RELATIVE_PARAM(lexicalCastMeasure, n);     \
859   BENCHMARK_RELATIVE_PARAM(handwrittenAtoiMeasure, n); \
860   BENCHMARK_RELATIVE_PARAM(follyAtoiMeasure, n);       \
861   BENCHMARK_DRAW_LINE();
862
863 DEFINE_BENCHMARK_GROUP(1);
864 DEFINE_BENCHMARK_GROUP(2);
865 DEFINE_BENCHMARK_GROUP(3);
866 DEFINE_BENCHMARK_GROUP(4);
867 DEFINE_BENCHMARK_GROUP(5);
868 DEFINE_BENCHMARK_GROUP(6);
869 DEFINE_BENCHMARK_GROUP(7);
870 DEFINE_BENCHMARK_GROUP(8);
871 DEFINE_BENCHMARK_GROUP(9);
872 DEFINE_BENCHMARK_GROUP(10);
873 DEFINE_BENCHMARK_GROUP(11);
874 DEFINE_BENCHMARK_GROUP(12);
875 DEFINE_BENCHMARK_GROUP(13);
876 DEFINE_BENCHMARK_GROUP(14);
877 DEFINE_BENCHMARK_GROUP(15);
878 DEFINE_BENCHMARK_GROUP(16);
879 DEFINE_BENCHMARK_GROUP(17);
880 DEFINE_BENCHMARK_GROUP(18);
881 DEFINE_BENCHMARK_GROUP(19);
882
883 #undef DEFINE_BENCHMARK_GROUP
884
885 #define DEFINE_BENCHMARK_GROUP(T, n)             \
886   BENCHMARK_PARAM(T##VariadicToBM, n);           \
887   BENCHMARK_RELATIVE_PARAM(T##IdenticalToBM, n); \
888   BENCHMARK_DRAW_LINE();
889
890 DEFINE_BENCHMARK_GROUP(string, 32);
891 DEFINE_BENCHMARK_GROUP(string, 1024);
892 DEFINE_BENCHMARK_GROUP(string, 32768);
893 DEFINE_BENCHMARK_GROUP(fbstring, 32);
894 DEFINE_BENCHMARK_GROUP(fbstring, 1024);
895 DEFINE_BENCHMARK_GROUP(fbstring, 32768);
896
897 #undef DEFINE_BENCHMARK_GROUP
898
899 namespace {
900
901 template <typename T>
902 inline void stringToTypeClassic(const char* str, uint32_t n) {
903   for (uint32_t i = 0; i < n; ++i) {
904     try {
905       auto val = to<T>(str);
906       doNotOptimizeAway(val);
907     } catch (const std::exception& e) {
908       doNotOptimizeAway(e.what());
909     }
910     doNotOptimizeAway(i);
911   }
912 }
913
914 template <typename T>
915 inline void stringToTypeOptional(const char* str, uint32_t n) {
916   for (uint32_t i = 0; i < n; ++i) {
917     auto val = tryTo<T>(str);
918     if (val.hasValue()) {
919       doNotOptimizeAway(val.value());
920     }
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 template <typename T>
938 inline void ptrPairToIntOptional(StringPiece sp, uint32_t n) {
939   for (uint32_t i = 0; i < n; ++i) {
940     auto val = tryTo<T>(sp.begin(), sp.end());
941     if (val.hasValue()) {
942       doNotOptimizeAway(val.value());
943     }
944   }
945 }
946
947 constexpr uint32_t kArithNumIter = 10000;
948
949 template <typename T, typename U>
950 inline size_t arithToArithClassic(const U* in, uint32_t numItems) {
951   for (uint32_t i = 0; i < kArithNumIter; ++i) {
952     for (uint32_t j = 0; j < numItems; ++j) {
953       try {
954         auto val = to<T>(in[j]);
955         doNotOptimizeAway(val);
956       } catch (const std::exception& e) {
957         doNotOptimizeAway(e.what());
958       }
959       doNotOptimizeAway(j);
960     }
961     doNotOptimizeAway(i);
962   }
963
964   return kArithNumIter * numItems;
965 }
966
967 template <typename T, typename U>
968 inline size_t arithToArithOptional(const U* in, uint32_t numItems) {
969   for (uint32_t i = 0; i < kArithNumIter; ++i) {
970     for (uint32_t j = 0; j < numItems; ++j) {
971       auto val = tryTo<T>(*in);
972       doNotOptimizeAway(val.hasValue());
973       if (val.hasValue()) {
974         auto v2 = val.value();
975         doNotOptimizeAway(v2);
976       }
977       doNotOptimizeAway(j);
978     }
979     doNotOptimizeAway(i);
980   }
981
982   return kArithNumIter * numItems;
983 }
984
985 } // namespace
986
987 namespace folly {
988 namespace conv_bench_detail {
989
990 // Keep this data global and non-const, so the compiler cannot make
991 // any assumptions about the actual values at compile time
992
993 std::array<int, 4> int2ScharGood{{-128, 127, 0, -50}};
994 std::array<int, 4> int2ScharBad{{-129, 128, 255, 10000}};
995 std::array<int, 4> int2UcharGood{{0, 1, 254, 255}};
996 std::array<int, 4> int2UcharBad{{-128, -1000, 256, -1}};
997
998 std::array<long long, 4> ll2SintOrFloatGood{{-2, -1, 0, 1}};
999 std::array<long long, 4> ll2SintOrFloatBad{{
1000     std::numeric_limits<long long>::min() / 5,
1001     std::numeric_limits<long long>::min() / 2,
1002     std::numeric_limits<long long>::max() / 2,
1003     std::numeric_limits<long long>::max() / 5,
1004 }};
1005 std::array<long long, 4> ll2UintGood{{1, 2, 3, 4}};
1006 std::array<long long, 4> ll2UintBad{{-1, -2, -3, -4}};
1007
1008 std::array<double, 4> double2FloatGood{{1.0, 1.25, 2.5, 1000.0}};
1009 std::array<double, 4> double2FloatBad{{1e100, 1e101, 1e102, 1e103}};
1010 std::array<double, 4> double2IntGood{{1.0, 10.0, 100.0, 1000.0}};
1011 std::array<double, 4> double2IntBad{{1e100, 1.25, 2.5, 100.00001}};
1012 }
1013 }
1014
1015 #define STRING_TO_TYPE_BENCHMARK(type, name, pass, fail) \
1016   BENCHMARK(stringTo##name##Classic, n) {                \
1017     stringToTypeClassic<type>(pass, n);                  \
1018   }                                                      \
1019   BENCHMARK(stringTo##name##ClassicError, n) {           \
1020     stringToTypeClassic<type>(fail, n);                  \
1021   }                                                      \
1022   BENCHMARK(stringTo##name##Optional, n) {               \
1023     stringToTypeOptional<type>(pass, n);                 \
1024   }                                                      \
1025   BENCHMARK(stringTo##name##OptionalError, n) {          \
1026     stringToTypeOptional<type>(fail, n);                 \
1027   }
1028
1029 #define PTR_PAIR_TO_INT_BENCHMARK(type, name, pass, fail) \
1030   BENCHMARK(ptrPairTo##name##Classic, n) {                \
1031     ptrPairToIntClassic<type>(pass, n);                   \
1032   }                                                       \
1033   BENCHMARK(ptrPairTo##name##ClassicError, n) {           \
1034     ptrPairToIntClassic<type>(fail, n);                   \
1035   }                                                       \
1036   BENCHMARK(ptrPairTo##name##Optional, n) {               \
1037     ptrPairToIntOptional<type>(pass, n);                  \
1038   }                                                       \
1039   BENCHMARK(ptrPairTo##name##OptionalError, n) {          \
1040     ptrPairToIntOptional<type>(fail, n);                  \
1041   }
1042
1043 #define ARITH_TO_ARITH_BENCHMARK(type, name, pass, fail)         \
1044   BENCHMARK_MULTI(name##Classic) {                               \
1045     return arithToArithClassic<type>(pass.data(), pass.size());  \
1046   }                                                              \
1047   BENCHMARK_MULTI(name##ClassicError) {                          \
1048     return arithToArithClassic<type>(fail.data(), fail.size());  \
1049   }                                                              \
1050   BENCHMARK_MULTI(name##Optional) {                              \
1051     return arithToArithOptional<type>(pass.data(), pass.size()); \
1052   }                                                              \
1053   BENCHMARK_MULTI(name##OptionalError) {                         \
1054     return arithToArithOptional<type>(fail.data(), fail.size()); \
1055   }
1056
1057 #define INT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1058   ARITH_TO_ARITH_BENCHMARK(type, intTo##name, pass, fail)
1059
1060 #define FLOAT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1061   ARITH_TO_ARITH_BENCHMARK(type, floatTo##name, pass, fail)
1062
1063 STRING_TO_TYPE_BENCHMARK(bool, BoolNum, " 1 ", "2")
1064 STRING_TO_TYPE_BENCHMARK(bool, BoolStr, "true", "xxxx")
1065 BENCHMARK_DRAW_LINE();
1066 STRING_TO_TYPE_BENCHMARK(float, FloatNum, " 3.14 ", "3e5000x")
1067 STRING_TO_TYPE_BENCHMARK(float, FloatStr, "-infinity", "xxxx")
1068 STRING_TO_TYPE_BENCHMARK(double, DoubleNum, " 3.14 ", "3e5000x")
1069 STRING_TO_TYPE_BENCHMARK(double, DoubleStr, "-infinity", "xxxx")
1070 BENCHMARK_DRAW_LINE();
1071 STRING_TO_TYPE_BENCHMARK(signed char, CharSigned, " -47 ", "1000")
1072 STRING_TO_TYPE_BENCHMARK(unsigned char, CharUnsigned, " 47 ", "-47")
1073 STRING_TO_TYPE_BENCHMARK(int, IntSigned, " -4711 ", "-10000000000000000000000")
1074 STRING_TO_TYPE_BENCHMARK(unsigned int, IntUnsigned, " 4711 ", "-4711")
1075 STRING_TO_TYPE_BENCHMARK(
1076     long long,
1077     LongLongSigned,
1078     " -8123456789123456789 ",
1079     "-10000000000000000000000")
1080 STRING_TO_TYPE_BENCHMARK(
1081     unsigned long long,
1082     LongLongUnsigned,
1083     " 18123456789123456789 ",
1084     "-4711")
1085 BENCHMARK_DRAW_LINE();
1086
1087 PTR_PAIR_TO_INT_BENCHMARK(signed char, CharSigned, "-47", "1000")
1088 PTR_PAIR_TO_INT_BENCHMARK(unsigned char, CharUnsigned, "47", "1000")
1089 PTR_PAIR_TO_INT_BENCHMARK(int, IntSigned, "-4711", "-10000000000000000000000")
1090 PTR_PAIR_TO_INT_BENCHMARK(
1091     unsigned int,
1092     IntUnsigned,
1093     "4711",
1094     "10000000000000000000000")
1095 PTR_PAIR_TO_INT_BENCHMARK(
1096     long long,
1097     LongLongSigned,
1098     "-8123456789123456789",
1099     "-10000000000000000000000")
1100 PTR_PAIR_TO_INT_BENCHMARK(
1101     unsigned long long,
1102     LongLongUnsigned,
1103     "18123456789123456789",
1104     "20000000000000000000")
1105 BENCHMARK_DRAW_LINE();
1106
1107 INT_TO_ARITH_BENCHMARK(signed char, CharSigned, int2ScharGood, int2ScharBad)
1108 INT_TO_ARITH_BENCHMARK(unsigned char, CharUnsigned, int2UcharGood, int2UcharBad)
1109 INT_TO_ARITH_BENCHMARK(int, IntSigned, ll2SintOrFloatGood, ll2SintOrFloatBad)
1110 INT_TO_ARITH_BENCHMARK(unsigned int, IntUnsigned, ll2UintGood, ll2UintBad)
1111 BENCHMARK_DRAW_LINE();
1112 INT_TO_ARITH_BENCHMARK(float, Float, ll2SintOrFloatGood, ll2SintOrFloatBad)
1113 BENCHMARK_DRAW_LINE();
1114 FLOAT_TO_ARITH_BENCHMARK(float, Float, double2FloatGood, double2FloatBad)
1115 BENCHMARK_DRAW_LINE();
1116 FLOAT_TO_ARITH_BENCHMARK(int, Int, double2IntGood, double2IntBad)
1117
1118 #undef STRING_TO_TYPE_BENCHMARK
1119 #undef PTR_PAIR_TO_INT_BENCHMARK
1120 #undef ARITH_TO_ARITH_BENCHMARK
1121 #undef INT_TO_ARITH_BENCHMARK
1122 #undef FLOAT_TO_ARITH_BENCHMARK
1123
1124 int main(int argc, char** argv) {
1125   gflags::ParseCommandLineFlags(&argc, &argv, true);
1126   folly::runBenchmarks();
1127   return 0;
1128 }