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;
32 namespace conv_bench_detail {
34 // Keep this data global and non-const, so the compiler cannot make
35 // any assumptions about the actual values at compile time
37 uint64_t uint64Num[] = {
56 123456789012345678ULL,
57 1234567890123456789ULL,
58 12345678901234567890ULL,
61 int64_t int64Pos[] = {
81 1234567890123456789LL,
84 int64_t int64Neg[] = {
102 -12345678901234567LL,
103 -123456789012345678LL,
104 -1234567890123456789LL,
107 #if FOLLY_HAVE_INT128_T
109 unsigned __int128 uint128Num[] = {
111 static_cast<unsigned __int128>(1) << 0,
112 static_cast<unsigned __int128>(1) << 4,
113 static_cast<unsigned __int128>(1) << 7,
114 static_cast<unsigned __int128>(1) << 10,
115 static_cast<unsigned __int128>(1) << 14,
116 static_cast<unsigned __int128>(1) << 17,
117 static_cast<unsigned __int128>(1) << 20,
118 static_cast<unsigned __int128>(1) << 24,
119 static_cast<unsigned __int128>(1) << 27,
120 static_cast<unsigned __int128>(1) << 30,
121 static_cast<unsigned __int128>(1) << 34,
122 static_cast<unsigned __int128>(1) << 37,
123 static_cast<unsigned __int128>(1) << 40,
124 static_cast<unsigned __int128>(1) << 44,
125 static_cast<unsigned __int128>(1) << 47,
126 static_cast<unsigned __int128>(1) << 50,
127 static_cast<unsigned __int128>(1) << 54,
128 static_cast<unsigned __int128>(1) << 57,
129 static_cast<unsigned __int128>(1) << 60,
130 static_cast<unsigned __int128>(1) << 64,
131 static_cast<unsigned __int128>(1) << 67,
132 static_cast<unsigned __int128>(1) << 70,
133 static_cast<unsigned __int128>(1) << 74,
134 static_cast<unsigned __int128>(1) << 77,
135 static_cast<unsigned __int128>(1) << 80,
136 static_cast<unsigned __int128>(1) << 84,
137 static_cast<unsigned __int128>(1) << 87,
138 static_cast<unsigned __int128>(1) << 90,
139 static_cast<unsigned __int128>(1) << 94,
140 static_cast<unsigned __int128>(1) << 97,
141 static_cast<unsigned __int128>(1) << 100,
142 static_cast<unsigned __int128>(1) << 103,
143 static_cast<unsigned __int128>(1) << 107,
144 static_cast<unsigned __int128>(1) << 110,
145 static_cast<unsigned __int128>(1) << 113,
146 static_cast<unsigned __int128>(1) << 117,
147 static_cast<unsigned __int128>(1) << 120,
148 static_cast<unsigned __int128>(1) << 123,
149 static_cast<unsigned __int128>(1) << 127,
152 __int128 int128Pos[] = {
154 static_cast<__int128>(1) << 0,
155 static_cast<__int128>(1) << 4,
156 static_cast<__int128>(1) << 7,
157 static_cast<__int128>(1) << 10,
158 static_cast<__int128>(1) << 14,
159 static_cast<__int128>(1) << 17,
160 static_cast<__int128>(1) << 20,
161 static_cast<__int128>(1) << 24,
162 static_cast<__int128>(1) << 27,
163 static_cast<__int128>(1) << 30,
164 static_cast<__int128>(1) << 34,
165 static_cast<__int128>(1) << 37,
166 static_cast<__int128>(1) << 40,
167 static_cast<__int128>(1) << 44,
168 static_cast<__int128>(1) << 47,
169 static_cast<__int128>(1) << 50,
170 static_cast<__int128>(1) << 54,
171 static_cast<__int128>(1) << 57,
172 static_cast<__int128>(1) << 60,
173 static_cast<__int128>(1) << 64,
174 static_cast<__int128>(1) << 67,
175 static_cast<__int128>(1) << 70,
176 static_cast<__int128>(1) << 74,
177 static_cast<__int128>(1) << 77,
178 static_cast<__int128>(1) << 80,
179 static_cast<__int128>(1) << 84,
180 static_cast<__int128>(1) << 87,
181 static_cast<__int128>(1) << 90,
182 static_cast<__int128>(1) << 94,
183 static_cast<__int128>(1) << 97,
184 static_cast<__int128>(1) << 100,
185 static_cast<__int128>(1) << 103,
186 static_cast<__int128>(1) << 107,
187 static_cast<__int128>(1) << 110,
188 static_cast<__int128>(1) << 113,
189 static_cast<__int128>(1) << 117,
190 static_cast<__int128>(1) << 120,
191 static_cast<__int128>(1) << 123,
192 static_cast<__int128>(3) << 125,
195 __int128 int128Neg[] = {
197 -(static_cast<__int128>(1) << 0),
198 -(static_cast<__int128>(1) << 4),
199 -(static_cast<__int128>(1) << 7),
200 -(static_cast<__int128>(1) << 10),
201 -(static_cast<__int128>(1) << 14),
202 -(static_cast<__int128>(1) << 17),
203 -(static_cast<__int128>(1) << 20),
204 -(static_cast<__int128>(1) << 24),
205 -(static_cast<__int128>(1) << 27),
206 -(static_cast<__int128>(1) << 30),
207 -(static_cast<__int128>(1) << 34),
208 -(static_cast<__int128>(1) << 37),
209 -(static_cast<__int128>(1) << 40),
210 -(static_cast<__int128>(1) << 44),
211 -(static_cast<__int128>(1) << 47),
212 -(static_cast<__int128>(1) << 50),
213 -(static_cast<__int128>(1) << 54),
214 -(static_cast<__int128>(1) << 57),
215 -(static_cast<__int128>(1) << 60),
216 -(static_cast<__int128>(1) << 64),
217 -(static_cast<__int128>(1) << 67),
218 -(static_cast<__int128>(1) << 70),
219 -(static_cast<__int128>(1) << 74),
220 -(static_cast<__int128>(1) << 77),
221 -(static_cast<__int128>(1) << 80),
222 -(static_cast<__int128>(1) << 84),
223 -(static_cast<__int128>(1) << 87),
224 -(static_cast<__int128>(1) << 90),
225 -(static_cast<__int128>(1) << 94),
226 -(static_cast<__int128>(1) << 97),
227 -(static_cast<__int128>(1) << 100),
228 -(static_cast<__int128>(1) << 103),
229 -(static_cast<__int128>(1) << 107),
230 -(static_cast<__int128>(1) << 110),
231 -(static_cast<__int128>(1) << 113),
232 -(static_cast<__int128>(1) << 117),
233 -(static_cast<__int128>(1) << 120),
234 -(static_cast<__int128>(1) << 123),
235 -(static_cast<__int128>(3) << 125),
242 using namespace folly::conv_bench_detail;
246 template <typename T>
247 void checkArrayIndex(const T& array, size_t index) {
248 DCHECK_LT(index, sizeof(array) / sizeof(array[0]));
252 ////////////////////////////////////////////////////////////////////////////////
253 // Benchmarks for ASCII to int conversion
254 ////////////////////////////////////////////////////////////////////////////////
255 // @author: Rajat Goel (rajat)
257 static int64_t handwrittenAtoi(const char* start, const char* end) {
259 bool positive = true;
263 throw std::runtime_error("empty string");
266 while (start < end && isspace(*start)) {
279 while (start < end && *start >= '0' && *start <= '9') {
280 auto const newRetVal = retVal * 10 + (*start++ - '0');
281 if (newRetVal < retVal) {
282 throw std::runtime_error("overflow");
288 throw std::runtime_error("extra chars at the end");
291 return positive ? retVal : -retVal;
294 static StringPiece pc1 = "1234567890123456789";
296 void handwrittenAtoiMeasure(unsigned int n, unsigned int digits) {
297 auto p = pc1.subpiece(pc1.size() - digits, digits);
298 FOR_EACH_RANGE(i, 0, n) {
299 doNotOptimizeAway(handwrittenAtoi(p.begin(), p.end()));
303 void follyAtoiMeasure(unsigned int n, unsigned int digits) {
304 auto p = pc1.subpiece(pc1.size() - digits, digits);
305 FOR_EACH_RANGE(i, 0, n) {
306 doNotOptimizeAway(folly::to<int64_t>(p.begin(), p.end()));
310 void clibAtoiMeasure(unsigned int n, unsigned int digits) {
311 auto p = pc1.subpiece(pc1.size() - digits, digits);
312 assert(*p.end() == 0);
313 static_assert(sizeof(long) == 8, "64-bit long assumed");
314 FOR_EACH_RANGE(i, 0, n) { doNotOptimizeAway(atol(p.begin())); }
317 void clibStrtoulMeasure(unsigned int n, unsigned int digits) {
318 auto p = pc1.subpiece(pc1.size() - digits, digits);
319 assert(*p.end() == 0);
321 FOR_EACH_RANGE(i, 0, n) {
322 doNotOptimizeAway(strtoul(p.begin(), &endptr, 10));
326 void lexicalCastMeasure(unsigned int n, unsigned int digits) {
327 auto p = pc1.subpiece(pc1.size() - digits, digits);
328 assert(*p.end() == 0);
329 FOR_EACH_RANGE(i, 0, n) {
330 doNotOptimizeAway(boost::lexical_cast<uint64_t>(p.begin()));
334 // Benchmarks for unsigned to string conversion, raw
336 unsigned u64ToAsciiTable(uint64_t value, char* dst) {
337 static const char digits[201] =
338 "00010203040506070809"
339 "10111213141516171819"
340 "20212223242526272829"
341 "30313233343536373839"
342 "40414243444546474849"
343 "50515253545556575859"
344 "60616263646566676869"
345 "70717273747576777879"
346 "80818283848586878889"
347 "90919293949596979899";
349 uint32_t const length = digits10(value);
350 uint32_t next = length - 1;
351 while (value >= 100) {
352 auto const i = (value % 100) * 2;
354 dst[next] = digits[i + 1];
355 dst[next - 1] = digits[i];
358 // Handle last 1-2 digits
360 dst[next] = '0' + uint32_t(value);
362 auto i = uint32_t(value) * 2;
363 dst[next] = digits[i + 1];
364 dst[next - 1] = digits[i];
369 void u64ToAsciiTableBM(unsigned int n, size_t index) {
370 checkArrayIndex(uint64Num, index);
372 FOR_EACH_RANGE(i, 0, n) {
373 doNotOptimizeAway(u64ToAsciiTable(uint64Num[index] + (i % 8), buf));
377 unsigned u64ToAsciiClassic(uint64_t value, char* dst) {
379 char* next = (char*)dst;
382 *next++ = '0' + (value % 10);
384 } while (value != 0);
385 unsigned length = next - start;
389 while (next > start) {
399 void u64ToAsciiClassicBM(unsigned int n, size_t index) {
400 checkArrayIndex(uint64Num, index);
402 FOR_EACH_RANGE(i, 0, n) {
403 doNotOptimizeAway(u64ToAsciiClassic(uint64Num[index] + (i % 8), buf));
407 void u64ToAsciiFollyBM(unsigned int n, size_t index) {
408 checkArrayIndex(uint64Num, index);
410 FOR_EACH_RANGE(i, 0, n) {
411 doNotOptimizeAway(uint64ToBufferUnsafe(uint64Num[index] + (i % 8), buf));
415 // Benchmark unsigned to string conversion
417 void u64ToStringClibMeasure(unsigned int n, size_t index) {
418 // FOLLY_RANGE_CHECK_TO_STRING expands to std::to_string, except on Android
419 // where std::to_string is not supported
420 checkArrayIndex(uint64Num, index);
421 FOR_EACH_RANGE (i, 0, n) {
423 FOLLY_RANGE_CHECK_TO_STRING(uint64Num[index] + (i % 8)).size());
427 void u64ToStringFollyMeasure(unsigned int n, size_t index) {
428 checkArrayIndex(uint64Num, index);
429 FOR_EACH_RANGE (i, 0, n) {
430 doNotOptimizeAway(to<std::string>(uint64Num[index] + (i % 8)).size());
436 void i64ToStringFollyMeasurePos(unsigned int n, size_t index) {
437 checkArrayIndex(int64Pos, index);
438 FOR_EACH_RANGE (i, 0, n) {
439 doNotOptimizeAway(to<std::string>(int64Pos[index] + (i % 8)).size());
443 void i64ToStringFollyMeasureNeg(unsigned int n, size_t index) {
444 checkArrayIndex(int64Neg, index);
445 FOR_EACH_RANGE (i, 0, n) {
446 doNotOptimizeAway(to<std::string>(int64Neg[index] - (i % 8)).size());
450 // Benchmark uitoa with string append
452 void u2aAppendClassicBM(unsigned int n, size_t index) {
453 checkArrayIndex(uint64Num, index);
455 FOR_EACH_RANGE(i, 0, n) {
456 // auto buf = &s.back() + 1;
458 s.append(buffer, u64ToAsciiClassic(uint64Num[index] + (i % 8), buffer));
459 doNotOptimizeAway(s.size());
463 void u2aAppendFollyBM(unsigned int n, size_t index) {
464 checkArrayIndex(uint64Num, index);
466 FOR_EACH_RANGE(i, 0, n) {
467 // auto buf = &s.back() + 1;
469 s.append(buffer, uint64ToBufferUnsafe(uint64Num[index] + (i % 8), buffer));
470 doNotOptimizeAway(s.size());
474 template <class String>
475 struct StringIdenticalToBM {
476 StringIdenticalToBM() {}
477 void operator()(unsigned int n, size_t len) const {
479 BENCHMARK_SUSPEND { s.append(len, '0'); }
480 FOR_EACH_RANGE(i, 0, n) {
481 String result = to<String>(s);
482 doNotOptimizeAway(result.size());
487 template <class String>
488 struct StringVariadicToBM {
489 StringVariadicToBM() {}
490 void operator()(unsigned int n, size_t len) const {
492 BENCHMARK_SUSPEND { s.append(len, '0'); }
493 FOR_EACH_RANGE(i, 0, n) {
494 String result = to<String>(s, nullptr);
495 doNotOptimizeAway(result.size());
501 namespace conv_bench_detail {
503 // Keep this data global and non-const, so the compiler cannot make
504 // any assumptions about the actual values at compile time
506 size_t bigInt = 11424545345345;
507 size_t smallInt = 104;
508 char someString[] = "this is some nice string";
509 char otherString[] = "this is a long string, so it's not so nice";
510 char reallyShort[] = "meh";
511 std::string stdString = "std::strings are very nice";
512 float fValue = 1.2355f;
513 double dValue = 345345345.435;
517 BENCHMARK(preallocateTestNoFloat, n) {
518 for (size_t i = 0; i < n; ++i) {
520 to<std::string>(bigInt, someString, stdString, otherString).size());
521 doNotOptimizeAway(to<std::string>(reallyShort, smallInt).size());
522 doNotOptimizeAway(to<std::string>(bigInt, stdString).size());
524 to<std::string>(bigInt, stdString, dValue, otherString).size());
525 doNotOptimizeAway(to<std::string>(bigInt, someString, reallyShort).size());
529 BENCHMARK(preallocateTestFloat, n) {
530 for (size_t i = 0; i < n; ++i) {
531 doNotOptimizeAway(to<std::string>(stdString, ',', fValue, dValue).size());
532 doNotOptimizeAway(to<std::string>(stdString, ',', dValue).size());
537 namespace conv_bench_detail {
539 // Keep this data global and non-const, so the compiler cannot make
540 // any assumptions about the actual values at compile time
543 -(static_cast<int8_t>(1) << 4),
544 static_cast<int8_t>(1) << 5,
545 -(static_cast<int8_t>(1) << 6),
549 static_cast<uint8_t>(1) << 4,
550 static_cast<uint8_t>(1) << 5,
551 static_cast<uint8_t>(1) << 7,
555 -(static_cast<int16_t>(1) << 8),
556 static_cast<int16_t>(1) << 12,
557 -(static_cast<int16_t>(1) << 14),
561 static_cast<uint16_t>(1) << 8,
562 static_cast<uint16_t>(1) << 12,
563 static_cast<uint16_t>(1) << 15,
567 -(static_cast<int32_t>(1) << 16),
568 static_cast<int32_t>(1) << 25,
569 -(static_cast<int32_t>(1) << 30),
573 static_cast<uint32_t>(1) << 16,
574 static_cast<uint32_t>(1) << 25,
575 static_cast<uint32_t>(1) << 31,
579 -(static_cast<int64_t>(1) << 32),
580 static_cast<int64_t>(1) << 50,
581 -(static_cast<int64_t>(1) << 62),
585 static_cast<uint64_t>(1) << 32,
586 static_cast<uint64_t>(1) << 50,
587 static_cast<uint64_t>(1) << 63,
592 BENCHMARK(preallocateTestInt8, n) {
593 for (size_t i = 0; i < n; ++i) {
594 doNotOptimizeAway(to<std::string>(
610 BENCHMARK(preallocateTestInt16, n) {
611 for (size_t i = 0; i < n; ++i) {
612 doNotOptimizeAway(to<std::string>(
628 BENCHMARK(preallocateTestInt32, n) {
629 for (size_t i = 0; i < n; ++i) {
630 doNotOptimizeAway(to<std::string>(
646 BENCHMARK(preallocateTestInt64, n) {
647 for (size_t i = 0; i < n; ++i) {
648 doNotOptimizeAway(to<std::string>(
664 #if FOLLY_HAVE_INT128_T
668 -(static_cast<__int128>(1) << 2),
669 static_cast<__int128>(1) << 100,
670 -(static_cast<__int128>(1) << 126),
673 unsigned __int128 u128s[] = {
674 static_cast<unsigned __int128>(1) << 2,
675 static_cast<unsigned __int128>(1) << 100,
676 static_cast<unsigned __int128>(1) << 127,
680 BENCHMARK(preallocateTestInt128, n) {
681 for (size_t i = 0; i < n; ++i) {
682 doNotOptimizeAway(to<std::string>(
698 BENCHMARK(preallocateTestNoFloatWithInt128, n) {
699 for (size_t i = 0; i < n; ++i) {
701 to<std::string>(bigInt, someString, stdString, otherString).size());
703 to<std::string>(reallyShort, u128s[0], smallInt, i128s[2]).size());
705 to<std::string>(bigInt, i128s[0], stdString, u128s[1]).size());
707 to<std::string>(bigInt, stdString, dValue, otherString).size());
709 to<std::string>(bigInt, u128s[2], someString, reallyShort).size());
714 BENCHMARK_DRAW_LINE();
716 static const StringIdenticalToBM<std::string> stringIdenticalToBM;
717 static const StringVariadicToBM<std::string> stringVariadicToBM;
718 static const StringIdenticalToBM<fbstring> fbstringIdenticalToBM;
719 static const StringVariadicToBM<fbstring> fbstringVariadicToBM;
721 #define DEFINE_BENCHMARK_GROUP(n) \
722 BENCHMARK_PARAM(u64ToAsciiClassicBM, n); \
723 BENCHMARK_RELATIVE_PARAM(u64ToAsciiTableBM, n); \
724 BENCHMARK_RELATIVE_PARAM(u64ToAsciiFollyBM, n); \
725 BENCHMARK_DRAW_LINE();
727 DEFINE_BENCHMARK_GROUP(1);
728 DEFINE_BENCHMARK_GROUP(2);
729 DEFINE_BENCHMARK_GROUP(3);
730 DEFINE_BENCHMARK_GROUP(4);
731 DEFINE_BENCHMARK_GROUP(5);
732 DEFINE_BENCHMARK_GROUP(6);
733 DEFINE_BENCHMARK_GROUP(7);
734 DEFINE_BENCHMARK_GROUP(8);
735 DEFINE_BENCHMARK_GROUP(9);
736 DEFINE_BENCHMARK_GROUP(10);
737 DEFINE_BENCHMARK_GROUP(11);
738 DEFINE_BENCHMARK_GROUP(12);
739 DEFINE_BENCHMARK_GROUP(13);
740 DEFINE_BENCHMARK_GROUP(14);
741 DEFINE_BENCHMARK_GROUP(15);
742 DEFINE_BENCHMARK_GROUP(16);
743 DEFINE_BENCHMARK_GROUP(17);
744 DEFINE_BENCHMARK_GROUP(18);
745 DEFINE_BENCHMARK_GROUP(19);
746 DEFINE_BENCHMARK_GROUP(20);
748 #undef DEFINE_BENCHMARK_GROUP
750 #define DEFINE_BENCHMARK_GROUP(n) \
751 BENCHMARK_PARAM(u64ToStringClibMeasure, n); \
752 BENCHMARK_RELATIVE_PARAM(u64ToStringFollyMeasure, n); \
753 BENCHMARK_RELATIVE_PARAM(i64ToStringFollyMeasurePos, n); \
754 BENCHMARK_RELATIVE_PARAM(i64ToStringFollyMeasureNeg, n); \
755 BENCHMARK_DRAW_LINE();
757 DEFINE_BENCHMARK_GROUP(1);
758 DEFINE_BENCHMARK_GROUP(2);
759 DEFINE_BENCHMARK_GROUP(3);
760 DEFINE_BENCHMARK_GROUP(4);
761 DEFINE_BENCHMARK_GROUP(5);
762 DEFINE_BENCHMARK_GROUP(6);
763 DEFINE_BENCHMARK_GROUP(7);
764 DEFINE_BENCHMARK_GROUP(8);
765 DEFINE_BENCHMARK_GROUP(9);
766 DEFINE_BENCHMARK_GROUP(10);
767 DEFINE_BENCHMARK_GROUP(11);
768 DEFINE_BENCHMARK_GROUP(12);
769 DEFINE_BENCHMARK_GROUP(13);
770 DEFINE_BENCHMARK_GROUP(14);
771 DEFINE_BENCHMARK_GROUP(15);
772 DEFINE_BENCHMARK_GROUP(16);
773 DEFINE_BENCHMARK_GROUP(17);
774 DEFINE_BENCHMARK_GROUP(18);
775 DEFINE_BENCHMARK_GROUP(19);
778 BENCHMARK_PARAM(u64ToStringClibMeasure, 20);
779 BENCHMARK_RELATIVE_PARAM(u64ToStringFollyMeasure, 20);
780 BENCHMARK_DRAW_LINE();
782 #undef DEFINE_BENCHMARK_GROUP
784 #if FOLLY_HAVE_INT128_T
786 void u128ToStringFollyMeasure(unsigned int n, size_t index) {
787 checkArrayIndex(uint128Num, index);
788 FOR_EACH_RANGE (i, 0, n) {
789 doNotOptimizeAway(to<std::string>(uint128Num[index] + (i % 8)).size());
793 void i128ToStringFollyMeasurePos(unsigned int n, size_t index) {
794 checkArrayIndex(int128Pos, index);
795 FOR_EACH_RANGE (i, 0, n) {
796 doNotOptimizeAway(to<std::string>(int128Pos[index] + (i % 8)).size());
800 void i128ToStringFollyMeasureNeg(unsigned int n, size_t index) {
801 checkArrayIndex(int128Neg, index);
802 FOR_EACH_RANGE (i, 0, n) {
803 doNotOptimizeAway(to<std::string>(int128Neg[index] + (i % 8)).size());
807 #define DEFINE_BENCHMARK_GROUP(n) \
808 BENCHMARK_PARAM(u128ToStringFollyMeasure, n); \
809 BENCHMARK_RELATIVE_PARAM(i128ToStringFollyMeasurePos, n); \
810 BENCHMARK_RELATIVE_PARAM(i128ToStringFollyMeasureNeg, n); \
811 BENCHMARK_DRAW_LINE();
813 DEFINE_BENCHMARK_GROUP(1);
814 DEFINE_BENCHMARK_GROUP(2);
815 DEFINE_BENCHMARK_GROUP(3);
816 DEFINE_BENCHMARK_GROUP(4);
817 DEFINE_BENCHMARK_GROUP(5);
818 DEFINE_BENCHMARK_GROUP(6);
819 DEFINE_BENCHMARK_GROUP(7);
820 DEFINE_BENCHMARK_GROUP(8);
821 DEFINE_BENCHMARK_GROUP(9);
822 DEFINE_BENCHMARK_GROUP(10);
823 DEFINE_BENCHMARK_GROUP(11);
824 DEFINE_BENCHMARK_GROUP(12);
825 DEFINE_BENCHMARK_GROUP(13);
826 DEFINE_BENCHMARK_GROUP(14);
827 DEFINE_BENCHMARK_GROUP(15);
828 DEFINE_BENCHMARK_GROUP(16);
829 DEFINE_BENCHMARK_GROUP(17);
830 DEFINE_BENCHMARK_GROUP(18);
831 DEFINE_BENCHMARK_GROUP(19);
832 DEFINE_BENCHMARK_GROUP(20);
833 DEFINE_BENCHMARK_GROUP(21);
834 DEFINE_BENCHMARK_GROUP(22);
835 DEFINE_BENCHMARK_GROUP(23);
836 DEFINE_BENCHMARK_GROUP(24);
837 DEFINE_BENCHMARK_GROUP(25);
838 DEFINE_BENCHMARK_GROUP(26);
839 DEFINE_BENCHMARK_GROUP(27);
840 DEFINE_BENCHMARK_GROUP(28);
841 DEFINE_BENCHMARK_GROUP(29);
842 DEFINE_BENCHMARK_GROUP(30);
843 DEFINE_BENCHMARK_GROUP(31);
844 DEFINE_BENCHMARK_GROUP(32);
845 DEFINE_BENCHMARK_GROUP(33);
846 DEFINE_BENCHMARK_GROUP(34);
847 DEFINE_BENCHMARK_GROUP(35);
848 DEFINE_BENCHMARK_GROUP(36);
849 DEFINE_BENCHMARK_GROUP(37);
850 DEFINE_BENCHMARK_GROUP(38);
851 DEFINE_BENCHMARK_GROUP(39);
853 BENCHMARK_DRAW_LINE();
855 #undef DEFINE_BENCHMARK_GROUP
859 #define DEFINE_BENCHMARK_GROUP(n) \
860 BENCHMARK_PARAM(clibAtoiMeasure, n); \
861 BENCHMARK_RELATIVE_PARAM(lexicalCastMeasure, n); \
862 BENCHMARK_RELATIVE_PARAM(handwrittenAtoiMeasure, n); \
863 BENCHMARK_RELATIVE_PARAM(follyAtoiMeasure, n); \
864 BENCHMARK_DRAW_LINE();
866 DEFINE_BENCHMARK_GROUP(1);
867 DEFINE_BENCHMARK_GROUP(2);
868 DEFINE_BENCHMARK_GROUP(3);
869 DEFINE_BENCHMARK_GROUP(4);
870 DEFINE_BENCHMARK_GROUP(5);
871 DEFINE_BENCHMARK_GROUP(6);
872 DEFINE_BENCHMARK_GROUP(7);
873 DEFINE_BENCHMARK_GROUP(8);
874 DEFINE_BENCHMARK_GROUP(9);
875 DEFINE_BENCHMARK_GROUP(10);
876 DEFINE_BENCHMARK_GROUP(11);
877 DEFINE_BENCHMARK_GROUP(12);
878 DEFINE_BENCHMARK_GROUP(13);
879 DEFINE_BENCHMARK_GROUP(14);
880 DEFINE_BENCHMARK_GROUP(15);
881 DEFINE_BENCHMARK_GROUP(16);
882 DEFINE_BENCHMARK_GROUP(17);
883 DEFINE_BENCHMARK_GROUP(18);
884 DEFINE_BENCHMARK_GROUP(19);
886 #undef DEFINE_BENCHMARK_GROUP
888 #define DEFINE_BENCHMARK_GROUP(T, n) \
889 BENCHMARK_PARAM(T##VariadicToBM, n); \
890 BENCHMARK_RELATIVE_PARAM(T##IdenticalToBM, n); \
891 BENCHMARK_DRAW_LINE();
893 DEFINE_BENCHMARK_GROUP(string, 32);
894 DEFINE_BENCHMARK_GROUP(string, 1024);
895 DEFINE_BENCHMARK_GROUP(string, 32768);
896 DEFINE_BENCHMARK_GROUP(fbstring, 32);
897 DEFINE_BENCHMARK_GROUP(fbstring, 1024);
898 DEFINE_BENCHMARK_GROUP(fbstring, 32768);
900 #undef DEFINE_BENCHMARK_GROUP
904 template <typename T>
905 inline void stringToTypeClassic(const char* str, uint32_t n) {
906 for (uint32_t i = 0; i < n; ++i) {
908 auto val = to<T>(str);
909 doNotOptimizeAway(val);
910 } catch (const std::exception& e) {
911 doNotOptimizeAway(e.what());
913 doNotOptimizeAway(i);
917 template <typename T>
918 inline void ptrPairToIntClassic(StringPiece sp, uint32_t n) {
919 for (uint32_t i = 0; i < n; ++i) {
921 auto val = to<T>(sp.begin(), sp.end());
922 doNotOptimizeAway(val);
923 } catch (const std::exception& e) {
924 doNotOptimizeAway(e.what());
926 doNotOptimizeAway(i);
930 constexpr uint32_t kArithNumIter = 10000;
932 template <typename T, typename U>
933 inline size_t arithToArithClassic(const U* in, uint32_t numItems) {
934 for (uint32_t i = 0; i < kArithNumIter; ++i) {
935 for (uint32_t j = 0; j < numItems; ++j) {
937 auto val = to<T>(in[j]);
938 doNotOptimizeAway(val);
939 } catch (const std::exception& e) {
940 doNotOptimizeAway(e.what());
942 doNotOptimizeAway(j);
944 doNotOptimizeAway(i);
947 return kArithNumIter * numItems;
953 namespace conv_bench_detail {
955 // Keep this data global and non-const, so the compiler cannot make
956 // any assumptions about the actual values at compile time
958 std::array<int, 4> int2ScharGood{{-128, 127, 0, -50}};
959 std::array<int, 4> int2ScharBad{{-129, 128, 255, 10000}};
960 std::array<int, 4> int2UcharGood{{0, 1, 254, 255}};
961 std::array<int, 4> int2UcharBad{{-128, -1000, 256, -1}};
963 std::array<long long, 4> ll2SintOrFloatGood{{-2, -1, 0, 1}};
964 std::array<long long, 4> ll2SintOrFloatBad{{
965 std::numeric_limits<long long>::min() / 5,
966 std::numeric_limits<long long>::min() / 2,
967 std::numeric_limits<long long>::max() / 2,
968 std::numeric_limits<long long>::max() / 5,
970 std::array<long long, 4> ll2UintGood{{1, 2, 3, 4}};
971 std::array<long long, 4> ll2UintBad{{-1, -2, -3, -4}};
973 std::array<double, 4> double2FloatGood{{1.0, 1.25, 2.5, 1000.0}};
974 std::array<double, 4> double2FloatBad{{1e100, 1e101, 1e102, 1e103}};
975 std::array<double, 4> double2IntGood{{1.0, 10.0, 100.0, 1000.0}};
976 std::array<double, 4> double2IntBad{{1e100, 1.25, 2.5, 100.00001}};
980 #define STRING_TO_TYPE_BENCHMARK(type, name, pass, fail) \
981 BENCHMARK(stringTo##name##Classic, n) { \
982 stringToTypeClassic<type>(pass, n); \
984 BENCHMARK(stringTo##name##ClassicError, n) { \
985 stringToTypeClassic<type>(fail, n); \
988 #define PTR_PAIR_TO_INT_BENCHMARK(type, name, pass, fail) \
989 BENCHMARK(ptrPairTo##name##Classic, n) { \
990 ptrPairToIntClassic<type>(pass, n); \
992 BENCHMARK(ptrPairTo##name##ClassicError, n) { \
993 ptrPairToIntClassic<type>(fail, n); \
996 #define ARITH_TO_ARITH_BENCHMARK(type, name, pass, fail) \
997 BENCHMARK_MULTI(name##Classic) { \
998 return arithToArithClassic<type>(pass.data(), pass.size()); \
1000 BENCHMARK_MULTI(name##ClassicError) { \
1001 return arithToArithClassic<type>(fail.data(), fail.size()); \
1004 #define INT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1005 ARITH_TO_ARITH_BENCHMARK(type, intTo##name, pass, fail)
1007 #define FLOAT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1008 ARITH_TO_ARITH_BENCHMARK(type, floatTo##name, pass, fail)
1010 STRING_TO_TYPE_BENCHMARK(bool, BoolNum, " 1 ", "2")
1011 STRING_TO_TYPE_BENCHMARK(bool, BoolStr, "true", "xxxx")
1012 BENCHMARK_DRAW_LINE();
1013 STRING_TO_TYPE_BENCHMARK(float, FloatNum, " 3.14 ", "3e5000x")
1014 STRING_TO_TYPE_BENCHMARK(float, FloatStr, "-infinity", "xxxx")
1015 STRING_TO_TYPE_BENCHMARK(double, DoubleNum, " 3.14 ", "3e5000x")
1016 STRING_TO_TYPE_BENCHMARK(double, DoubleStr, "-infinity", "xxxx")
1017 BENCHMARK_DRAW_LINE();
1018 STRING_TO_TYPE_BENCHMARK(signed char, CharSigned, " -47 ", "1000")
1019 STRING_TO_TYPE_BENCHMARK(unsigned char, CharUnsigned, " 47 ", "-47")
1020 STRING_TO_TYPE_BENCHMARK(int, IntSigned, " -4711 ", "-10000000000000000000000")
1021 STRING_TO_TYPE_BENCHMARK(unsigned int, IntUnsigned, " 4711 ", "-4711")
1022 STRING_TO_TYPE_BENCHMARK(
1025 " -8123456789123456789 ",
1026 "-10000000000000000000000")
1027 STRING_TO_TYPE_BENCHMARK(
1030 " 18123456789123456789 ",
1032 BENCHMARK_DRAW_LINE();
1034 PTR_PAIR_TO_INT_BENCHMARK(signed char, CharSigned, "-47", "1000")
1035 PTR_PAIR_TO_INT_BENCHMARK(unsigned char, CharUnsigned, "47", "1000")
1036 PTR_PAIR_TO_INT_BENCHMARK(int, IntSigned, "-4711", "-10000000000000000000000")
1037 PTR_PAIR_TO_INT_BENCHMARK(
1041 "10000000000000000000000")
1042 PTR_PAIR_TO_INT_BENCHMARK(
1045 "-8123456789123456789",
1046 "-10000000000000000000000")
1047 PTR_PAIR_TO_INT_BENCHMARK(
1050 "18123456789123456789",
1051 "20000000000000000000")
1052 BENCHMARK_DRAW_LINE();
1054 INT_TO_ARITH_BENCHMARK(signed char, CharSigned, int2ScharGood, int2ScharBad)
1055 INT_TO_ARITH_BENCHMARK(unsigned char, CharUnsigned, int2UcharGood, int2UcharBad)
1056 INT_TO_ARITH_BENCHMARK(int, IntSigned, ll2SintOrFloatGood, ll2SintOrFloatBad)
1057 INT_TO_ARITH_BENCHMARK(unsigned int, IntUnsigned, ll2UintGood, ll2UintBad)
1058 BENCHMARK_DRAW_LINE();
1059 INT_TO_ARITH_BENCHMARK(float, Float, ll2SintOrFloatGood, ll2SintOrFloatBad)
1060 BENCHMARK_DRAW_LINE();
1061 FLOAT_TO_ARITH_BENCHMARK(float, Float, double2FloatGood, double2FloatBad)
1062 BENCHMARK_DRAW_LINE();
1063 FLOAT_TO_ARITH_BENCHMARK(int, Int, double2IntGood, double2IntBad)
1065 #undef STRING_TO_TYPE_BENCHMARK
1066 #undef PTR_PAIR_TO_INT_BENCHMARK
1067 #undef ARITH_TO_ARITH_BENCHMARK
1068 #undef INT_TO_ARITH_BENCHMARK
1069 #undef FLOAT_TO_ARITH_BENCHMARK
1071 int main(int argc, char** argv) {
1072 gflags::ParseCommandLineFlags(&argc, &argv, true);
1073 folly::runBenchmarks();