2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/Conv.h>
19 #include <boost/lexical_cast.hpp>
21 #include <folly/Benchmark.h>
22 #include <folly/Foreach.h>
29 using namespace folly;
31 // Android doesn't support std::to_string so just use a placeholder there.
33 #define FOLLY_RANGE_CHECK_TO_STRING(x) std::string("N/A")
35 #define FOLLY_RANGE_CHECK_TO_STRING(x) std::to_string(x)
39 namespace conv_bench_detail {
41 // Keep this data global and non-const, so the compiler cannot make
42 // any assumptions about the actual values at compile time
44 uint64_t uint64Num[] = {
63 123456789012345678ULL,
64 1234567890123456789ULL,
65 12345678901234567890ULL,
68 int64_t int64Pos[] = {
88 1234567890123456789LL,
91 int64_t int64Neg[] = {
109 -12345678901234567LL,
110 -123456789012345678LL,
111 -1234567890123456789LL,
114 #if FOLLY_HAVE_INT128_T
116 unsigned __int128 uint128Num[] = {
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,
159 __int128 int128Pos[] = {
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,
202 __int128 int128Neg[] = {
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),
249 using namespace folly::conv_bench_detail;
253 template <typename T>
254 void checkArrayIndex(const T& array, size_t index) {
255 DCHECK_LT(index, sizeof(array) / sizeof(array[0]));
259 ////////////////////////////////////////////////////////////////////////////////
260 // Benchmarks for ASCII to int conversion
261 ////////////////////////////////////////////////////////////////////////////////
262 // @author: Rajat Goel (rajat)
264 static int64_t handwrittenAtoi(const char* start, const char* end) {
266 bool positive = true;
270 throw std::runtime_error("empty string");
273 while (start < end && isspace(*start)) {
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");
295 throw std::runtime_error("extra chars at the end");
298 return positive ? retVal : -retVal;
301 static StringPiece pc1 = "1234567890123456789";
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()));
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()));
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())); }
324 void clibStrtoulMeasure(unsigned int n, unsigned int digits) {
325 auto p = pc1.subpiece(pc1.size() - digits, digits);
326 assert(*p.end() == 0);
328 FOR_EACH_RANGE(i, 0, n) {
329 doNotOptimizeAway(strtoul(p.begin(), &endptr, 10));
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()));
341 // Benchmarks for unsigned to string conversion, raw
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";
356 uint32_t const length = digits10(value);
357 uint32_t next = length - 1;
358 while (value >= 100) {
359 auto const i = (value % 100) * 2;
361 dst[next] = digits[i + 1];
362 dst[next - 1] = digits[i];
365 // Handle last 1-2 digits
367 dst[next] = '0' + uint32_t(value);
369 auto i = uint32_t(value) * 2;
370 dst[next] = digits[i + 1];
371 dst[next - 1] = digits[i];
376 void u64ToAsciiTableBM(unsigned int n, size_t index) {
377 checkArrayIndex(uint64Num, index);
379 FOR_EACH_RANGE(i, 0, n) {
380 doNotOptimizeAway(u64ToAsciiTable(uint64Num[index] + (i % 8), buf));
384 unsigned u64ToAsciiClassic(uint64_t value, char* dst) {
386 char* next = (char*)dst;
389 *next++ = '0' + (value % 10);
391 } while (value != 0);
392 unsigned length = next - start;
396 while (next > start) {
406 void u64ToAsciiClassicBM(unsigned int n, size_t index) {
407 checkArrayIndex(uint64Num, index);
409 FOR_EACH_RANGE(i, 0, n) {
410 doNotOptimizeAway(u64ToAsciiClassic(uint64Num[index] + (i % 8), buf));
414 void u64ToAsciiFollyBM(unsigned int n, size_t index) {
415 checkArrayIndex(uint64Num, index);
417 FOR_EACH_RANGE(i, 0, n) {
418 doNotOptimizeAway(uint64ToBufferUnsafe(uint64Num[index] + (i % 8), buf));
422 // Benchmark unsigned to string conversion
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) {
430 FOLLY_RANGE_CHECK_TO_STRING(uint64Num[index] + (i % 8)).size());
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());
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());
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());
457 // Benchmark uitoa with string append
459 void u2aAppendClassicBM(unsigned int n, size_t index) {
460 checkArrayIndex(uint64Num, index);
462 FOR_EACH_RANGE(i, 0, n) {
463 // auto buf = &s.back() + 1;
465 s.append(buffer, u64ToAsciiClassic(uint64Num[index] + (i % 8), buffer));
466 doNotOptimizeAway(s.size());
470 void u2aAppendFollyBM(unsigned int n, size_t index) {
471 checkArrayIndex(uint64Num, index);
473 FOR_EACH_RANGE(i, 0, n) {
474 // auto buf = &s.back() + 1;
476 s.append(buffer, uint64ToBufferUnsafe(uint64Num[index] + (i % 8), buffer));
477 doNotOptimizeAway(s.size());
481 template <class String>
482 struct StringIdenticalToBM {
483 StringIdenticalToBM() {}
484 void operator()(unsigned int n, size_t len) const {
486 BENCHMARK_SUSPEND { s.append(len, '0'); }
487 FOR_EACH_RANGE(i, 0, n) {
488 String result = to<String>(s);
489 doNotOptimizeAway(result.size());
494 template <class String>
495 struct StringVariadicToBM {
496 StringVariadicToBM() {}
497 void operator()(unsigned int n, size_t len) const {
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());
508 namespace conv_bench_detail {
510 // Keep this data global and non-const, so the compiler cannot make
511 // any assumptions about the actual values at compile time
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;
524 BENCHMARK(preallocateTestNoFloat, n) {
525 for (size_t i = 0; i < n; ++i) {
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());
531 to<std::string>(bigInt, stdString, dValue, otherString).size());
532 doNotOptimizeAway(to<std::string>(bigInt, someString, reallyShort).size());
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());
544 namespace conv_bench_detail {
546 // Keep this data global and non-const, so the compiler cannot make
547 // any assumptions about the actual values at compile time
550 -(static_cast<int8_t>(1) << 4),
551 static_cast<int8_t>(1) << 5,
552 -(static_cast<int8_t>(1) << 6),
556 static_cast<uint8_t>(1) << 4,
557 static_cast<uint8_t>(1) << 5,
558 static_cast<uint8_t>(1) << 7,
562 -(static_cast<int16_t>(1) << 8),
563 static_cast<int16_t>(1) << 12,
564 -(static_cast<int16_t>(1) << 14),
568 static_cast<uint16_t>(1) << 8,
569 static_cast<uint16_t>(1) << 12,
570 static_cast<uint16_t>(1) << 15,
574 -(static_cast<int32_t>(1) << 16),
575 static_cast<int32_t>(1) << 25,
576 -(static_cast<int32_t>(1) << 30),
580 static_cast<uint32_t>(1) << 16,
581 static_cast<uint32_t>(1) << 25,
582 static_cast<uint32_t>(1) << 31,
586 -(static_cast<int64_t>(1) << 32),
587 static_cast<int64_t>(1) << 50,
588 -(static_cast<int64_t>(1) << 62),
592 static_cast<uint64_t>(1) << 32,
593 static_cast<uint64_t>(1) << 50,
594 static_cast<uint64_t>(1) << 63,
599 BENCHMARK(preallocateTestInt8, n) {
600 for (size_t i = 0; i < n; ++i) {
601 doNotOptimizeAway(to<std::string>(
617 BENCHMARK(preallocateTestInt16, n) {
618 for (size_t i = 0; i < n; ++i) {
619 doNotOptimizeAway(to<std::string>(
635 BENCHMARK(preallocateTestInt32, n) {
636 for (size_t i = 0; i < n; ++i) {
637 doNotOptimizeAway(to<std::string>(
653 BENCHMARK(preallocateTestInt64, n) {
654 for (size_t i = 0; i < n; ++i) {
655 doNotOptimizeAway(to<std::string>(
671 #if FOLLY_HAVE_INT128_T
675 -(static_cast<__int128>(1) << 2),
676 static_cast<__int128>(1) << 100,
677 -(static_cast<__int128>(1) << 126),
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,
687 BENCHMARK(preallocateTestInt128, n) {
688 for (size_t i = 0; i < n; ++i) {
689 doNotOptimizeAway(to<std::string>(
705 BENCHMARK(preallocateTestNoFloatWithInt128, n) {
706 for (size_t i = 0; i < n; ++i) {
708 to<std::string>(bigInt, someString, stdString, otherString).size());
710 to<std::string>(reallyShort, u128s[0], smallInt, i128s[2]).size());
712 to<std::string>(bigInt, i128s[0], stdString, u128s[1]).size());
714 to<std::string>(bigInt, stdString, dValue, otherString).size());
716 to<std::string>(bigInt, u128s[2], someString, reallyShort).size());
721 BENCHMARK_DRAW_LINE();
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;
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();
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);
755 #undef DEFINE_BENCHMARK_GROUP
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();
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);
785 BENCHMARK_PARAM(u64ToStringClibMeasure, 20);
786 BENCHMARK_RELATIVE_PARAM(u64ToStringFollyMeasure, 20);
787 BENCHMARK_DRAW_LINE();
789 #undef DEFINE_BENCHMARK_GROUP
791 #if FOLLY_HAVE_INT128_T
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());
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());
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());
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();
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);
860 BENCHMARK_DRAW_LINE();
862 #undef DEFINE_BENCHMARK_GROUP
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();
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);
893 #undef DEFINE_BENCHMARK_GROUP
895 #define DEFINE_BENCHMARK_GROUP(T, n) \
896 BENCHMARK_PARAM(T##VariadicToBM, n); \
897 BENCHMARK_RELATIVE_PARAM(T##IdenticalToBM, n); \
898 BENCHMARK_DRAW_LINE();
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);
907 #undef DEFINE_BENCHMARK_GROUP
911 template <typename T>
912 inline void stringToTypeClassic(const char* str, uint32_t n) {
913 for (uint32_t i = 0; i < n; ++i) {
915 auto val = to<T>(str);
916 doNotOptimizeAway(val);
917 } catch (const std::exception& e) {
918 doNotOptimizeAway(e.what());
920 doNotOptimizeAway(i);
924 template <typename T>
925 inline void ptrPairToIntClassic(StringPiece sp, uint32_t n) {
926 for (uint32_t i = 0; i < n; ++i) {
928 auto val = to<T>(sp.begin(), sp.end());
929 doNotOptimizeAway(val);
930 } catch (const std::exception& e) {
931 doNotOptimizeAway(e.what());
933 doNotOptimizeAway(i);
937 constexpr uint32_t kArithNumIter = 10000;
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) {
944 auto val = to<T>(in[j]);
945 doNotOptimizeAway(val);
946 } catch (const std::exception& e) {
947 doNotOptimizeAway(e.what());
949 doNotOptimizeAway(j);
951 doNotOptimizeAway(i);
954 return kArithNumIter * numItems;
960 namespace conv_bench_detail {
962 // Keep this data global and non-const, so the compiler cannot make
963 // any assumptions about the actual values at compile time
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}};
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,
977 std::array<long long, 4> ll2UintGood{{1, 2, 3, 4}};
978 std::array<long long, 4> ll2UintBad{{-1, -2, -3, -4}};
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}};
987 #define STRING_TO_TYPE_BENCHMARK(type, name, pass, fail) \
988 BENCHMARK(stringTo##name##Classic, n) { \
989 stringToTypeClassic<type>(pass, n); \
991 BENCHMARK(stringTo##name##ClassicError, n) { \
992 stringToTypeClassic<type>(fail, n); \
995 #define PTR_PAIR_TO_INT_BENCHMARK(type, name, pass, fail) \
996 BENCHMARK(ptrPairTo##name##Classic, n) { \
997 ptrPairToIntClassic<type>(pass, n); \
999 BENCHMARK(ptrPairTo##name##ClassicError, n) { \
1000 ptrPairToIntClassic<type>(fail, n); \
1003 #define ARITH_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1004 BENCHMARK_MULTI(name##Classic) { \
1005 return arithToArithClassic<type>(pass.data(), pass.size()); \
1007 BENCHMARK_MULTI(name##ClassicError) { \
1008 return arithToArithClassic<type>(fail.data(), fail.size()); \
1011 #define INT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1012 ARITH_TO_ARITH_BENCHMARK(type, intTo##name, pass, fail)
1014 #define FLOAT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1015 ARITH_TO_ARITH_BENCHMARK(type, floatTo##name, pass, fail)
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(
1032 " -8123456789123456789 ",
1033 "-10000000000000000000000")
1034 STRING_TO_TYPE_BENCHMARK(
1037 " 18123456789123456789 ",
1039 BENCHMARK_DRAW_LINE();
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(
1048 "10000000000000000000000")
1049 PTR_PAIR_TO_INT_BENCHMARK(
1052 "-8123456789123456789",
1053 "-10000000000000000000000")
1054 PTR_PAIR_TO_INT_BENCHMARK(
1057 "18123456789123456789",
1058 "20000000000000000000")
1059 BENCHMARK_DRAW_LINE();
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)
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
1078 int main(int argc, char** argv) {
1079 gflags::ParseCommandLineFlags(&argc, &argv, true);
1080 folly::runBenchmarks();