2 * Copyright 2017 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/CppAttributes.h>
23 #include <folly/Foreach.h>
30 using namespace folly;
32 // Android doesn't support std::to_string so just use a placeholder there.
34 #define FOLLY_RANGE_CHECK_TO_STRING(x) std::string("N/A")
36 #define FOLLY_RANGE_CHECK_TO_STRING(x) std::to_string(x)
40 namespace conv_bench_detail {
42 // Keep this data global and non-const, so the compiler cannot make
43 // any assumptions about the actual values at compile time
45 uint64_t uint64Num[] = {
64 123456789012345678ULL,
65 1234567890123456789ULL,
66 12345678901234567890ULL,
69 int64_t int64Pos[] = {
89 1234567890123456789LL,
92 int64_t int64Neg[] = {
110 -12345678901234567LL,
111 -123456789012345678LL,
112 -1234567890123456789LL,
115 #if FOLLY_HAVE_INT128_T
117 unsigned __int128 uint128Num[] = {
119 static_cast<unsigned __int128>(1) << 0,
120 static_cast<unsigned __int128>(1) << 4,
121 static_cast<unsigned __int128>(1) << 7,
122 static_cast<unsigned __int128>(1) << 10,
123 static_cast<unsigned __int128>(1) << 14,
124 static_cast<unsigned __int128>(1) << 17,
125 static_cast<unsigned __int128>(1) << 20,
126 static_cast<unsigned __int128>(1) << 24,
127 static_cast<unsigned __int128>(1) << 27,
128 static_cast<unsigned __int128>(1) << 30,
129 static_cast<unsigned __int128>(1) << 34,
130 static_cast<unsigned __int128>(1) << 37,
131 static_cast<unsigned __int128>(1) << 40,
132 static_cast<unsigned __int128>(1) << 44,
133 static_cast<unsigned __int128>(1) << 47,
134 static_cast<unsigned __int128>(1) << 50,
135 static_cast<unsigned __int128>(1) << 54,
136 static_cast<unsigned __int128>(1) << 57,
137 static_cast<unsigned __int128>(1) << 60,
138 static_cast<unsigned __int128>(1) << 64,
139 static_cast<unsigned __int128>(1) << 67,
140 static_cast<unsigned __int128>(1) << 70,
141 static_cast<unsigned __int128>(1) << 74,
142 static_cast<unsigned __int128>(1) << 77,
143 static_cast<unsigned __int128>(1) << 80,
144 static_cast<unsigned __int128>(1) << 84,
145 static_cast<unsigned __int128>(1) << 87,
146 static_cast<unsigned __int128>(1) << 90,
147 static_cast<unsigned __int128>(1) << 94,
148 static_cast<unsigned __int128>(1) << 97,
149 static_cast<unsigned __int128>(1) << 100,
150 static_cast<unsigned __int128>(1) << 103,
151 static_cast<unsigned __int128>(1) << 107,
152 static_cast<unsigned __int128>(1) << 110,
153 static_cast<unsigned __int128>(1) << 113,
154 static_cast<unsigned __int128>(1) << 117,
155 static_cast<unsigned __int128>(1) << 120,
156 static_cast<unsigned __int128>(1) << 123,
157 static_cast<unsigned __int128>(1) << 127,
160 __int128 int128Pos[] = {
162 static_cast<__int128>(1) << 0,
163 static_cast<__int128>(1) << 4,
164 static_cast<__int128>(1) << 7,
165 static_cast<__int128>(1) << 10,
166 static_cast<__int128>(1) << 14,
167 static_cast<__int128>(1) << 17,
168 static_cast<__int128>(1) << 20,
169 static_cast<__int128>(1) << 24,
170 static_cast<__int128>(1) << 27,
171 static_cast<__int128>(1) << 30,
172 static_cast<__int128>(1) << 34,
173 static_cast<__int128>(1) << 37,
174 static_cast<__int128>(1) << 40,
175 static_cast<__int128>(1) << 44,
176 static_cast<__int128>(1) << 47,
177 static_cast<__int128>(1) << 50,
178 static_cast<__int128>(1) << 54,
179 static_cast<__int128>(1) << 57,
180 static_cast<__int128>(1) << 60,
181 static_cast<__int128>(1) << 64,
182 static_cast<__int128>(1) << 67,
183 static_cast<__int128>(1) << 70,
184 static_cast<__int128>(1) << 74,
185 static_cast<__int128>(1) << 77,
186 static_cast<__int128>(1) << 80,
187 static_cast<__int128>(1) << 84,
188 static_cast<__int128>(1) << 87,
189 static_cast<__int128>(1) << 90,
190 static_cast<__int128>(1) << 94,
191 static_cast<__int128>(1) << 97,
192 static_cast<__int128>(1) << 100,
193 static_cast<__int128>(1) << 103,
194 static_cast<__int128>(1) << 107,
195 static_cast<__int128>(1) << 110,
196 static_cast<__int128>(1) << 113,
197 static_cast<__int128>(1) << 117,
198 static_cast<__int128>(1) << 120,
199 static_cast<__int128>(1) << 123,
200 static_cast<__int128>(3) << 125,
203 __int128 int128Neg[] = {
205 -(static_cast<__int128>(1) << 0),
206 -(static_cast<__int128>(1) << 4),
207 -(static_cast<__int128>(1) << 7),
208 -(static_cast<__int128>(1) << 10),
209 -(static_cast<__int128>(1) << 14),
210 -(static_cast<__int128>(1) << 17),
211 -(static_cast<__int128>(1) << 20),
212 -(static_cast<__int128>(1) << 24),
213 -(static_cast<__int128>(1) << 27),
214 -(static_cast<__int128>(1) << 30),
215 -(static_cast<__int128>(1) << 34),
216 -(static_cast<__int128>(1) << 37),
217 -(static_cast<__int128>(1) << 40),
218 -(static_cast<__int128>(1) << 44),
219 -(static_cast<__int128>(1) << 47),
220 -(static_cast<__int128>(1) << 50),
221 -(static_cast<__int128>(1) << 54),
222 -(static_cast<__int128>(1) << 57),
223 -(static_cast<__int128>(1) << 60),
224 -(static_cast<__int128>(1) << 64),
225 -(static_cast<__int128>(1) << 67),
226 -(static_cast<__int128>(1) << 70),
227 -(static_cast<__int128>(1) << 74),
228 -(static_cast<__int128>(1) << 77),
229 -(static_cast<__int128>(1) << 80),
230 -(static_cast<__int128>(1) << 84),
231 -(static_cast<__int128>(1) << 87),
232 -(static_cast<__int128>(1) << 90),
233 -(static_cast<__int128>(1) << 94),
234 -(static_cast<__int128>(1) << 97),
235 -(static_cast<__int128>(1) << 100),
236 -(static_cast<__int128>(1) << 103),
237 -(static_cast<__int128>(1) << 107),
238 -(static_cast<__int128>(1) << 110),
239 -(static_cast<__int128>(1) << 113),
240 -(static_cast<__int128>(1) << 117),
241 -(static_cast<__int128>(1) << 120),
242 -(static_cast<__int128>(1) << 123),
243 -(static_cast<__int128>(3) << 125),
250 using namespace folly::conv_bench_detail;
254 template <typename T>
255 void checkArrayIndex(const T& array, size_t index) {
256 DCHECK_LT(index, sizeof(array) / sizeof(array[0]));
260 ////////////////////////////////////////////////////////////////////////////////
261 // Benchmarks for ASCII to int conversion
262 ////////////////////////////////////////////////////////////////////////////////
263 // @author: Rajat Goel (rajat)
265 static int64_t handwrittenAtoi(const char* start, const char* end) {
267 bool positive = true;
271 throw std::runtime_error("empty string");
274 while (start < end && isspace(*start)) {
289 while (start < end && *start >= '0' && *start <= '9') {
290 auto const newRetVal = retVal * 10 + (*start++ - '0');
291 if (newRetVal < retVal) {
292 throw std::runtime_error("overflow");
298 throw std::runtime_error("extra chars at the end");
301 return positive ? retVal : -retVal;
304 static StringPiece pc1 = "1234567890123456789";
306 void handwrittenAtoiMeasure(unsigned int n, unsigned int digits) {
307 auto p = pc1.subpiece(pc1.size() - digits, digits);
308 FOR_EACH_RANGE(i, 0, n) {
309 doNotOptimizeAway(handwrittenAtoi(p.begin(), p.end()));
313 void follyAtoiMeasure(unsigned int n, unsigned int digits) {
314 auto p = pc1.subpiece(pc1.size() - digits, digits);
315 FOR_EACH_RANGE(i, 0, n) {
316 doNotOptimizeAway(folly::to<int64_t>(p.begin(), p.end()));
320 void clibAtoiMeasure(unsigned int n, unsigned int digits) {
321 auto p = pc1.subpiece(pc1.size() - digits, digits);
322 assert(*p.end() == 0);
323 FOR_EACH_RANGE(i, 0, n) { doNotOptimizeAway(atoll(p.begin())); }
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 stringToTypeOptional(const char* str, uint32_t n) {
919 for (uint32_t i = 0; i < n; ++i) {
920 auto val = tryTo<T>(str);
921 if (val.hasValue()) {
922 doNotOptimizeAway(val.value());
927 template <typename T>
928 inline void ptrPairToIntClassic(StringPiece sp, uint32_t n) {
929 for (uint32_t i = 0; i < n; ++i) {
931 auto val = to<T>(sp.begin(), sp.end());
932 doNotOptimizeAway(val);
933 } catch (const std::exception& e) {
934 doNotOptimizeAway(e.what());
936 doNotOptimizeAway(i);
940 template <typename T>
941 inline void ptrPairToIntOptional(StringPiece sp, uint32_t n) {
942 for (uint32_t i = 0; i < n; ++i) {
943 auto val = tryTo<T>(sp.begin(), sp.end());
944 if (val.hasValue()) {
945 doNotOptimizeAway(val.value());
950 constexpr uint32_t kArithNumIter = 10000;
952 template <typename T, typename U>
953 inline size_t arithToArithClassic(const U* in, uint32_t numItems) {
954 for (uint32_t i = 0; i < kArithNumIter; ++i) {
955 for (uint32_t j = 0; j < numItems; ++j) {
957 auto val = to<T>(in[j]);
958 doNotOptimizeAway(val);
959 } catch (const std::exception& e) {
960 doNotOptimizeAway(e.what());
962 doNotOptimizeAway(j);
964 doNotOptimizeAway(i);
967 return kArithNumIter * numItems;
970 template <typename T, typename U>
971 inline size_t arithToArithOptional(const U* in, uint32_t numItems) {
972 for (uint32_t i = 0; i < kArithNumIter; ++i) {
973 for (uint32_t j = 0; j < numItems; ++j) {
974 auto val = tryTo<T>(*in);
975 doNotOptimizeAway(val.hasValue());
976 if (val.hasValue()) {
977 auto v2 = val.value();
978 doNotOptimizeAway(v2);
980 doNotOptimizeAway(j);
982 doNotOptimizeAway(i);
985 return kArithNumIter * numItems;
991 namespace conv_bench_detail {
993 // Keep this data global and non-const, so the compiler cannot make
994 // any assumptions about the actual values at compile time
996 std::array<int, 4> int2ScharGood{{-128, 127, 0, -50}};
997 std::array<int, 4> int2ScharBad{{-129, 128, 255, 10000}};
998 std::array<int, 4> int2UcharGood{{0, 1, 254, 255}};
999 std::array<int, 4> int2UcharBad{{-128, -1000, 256, -1}};
1001 std::array<long long, 4> ll2SintOrFloatGood{{-2, -1, 0, 1}};
1002 std::array<long long, 4> ll2SintOrFloatBad{{
1003 std::numeric_limits<long long>::min() / 5,
1004 std::numeric_limits<long long>::min() / 2,
1005 std::numeric_limits<long long>::max() / 2,
1006 std::numeric_limits<long long>::max() / 5,
1008 std::array<long long, 4> ll2UintGood{{1, 2, 3, 4}};
1009 std::array<long long, 4> ll2UintBad{{-1, -2, -3, -4}};
1011 std::array<double, 4> double2FloatGood{{1.0, 1.25, 2.5, 1000.0}};
1012 std::array<double, 4> double2FloatBad{{1e100, 1e101, 1e102, 1e103}};
1013 std::array<double, 4> double2IntGood{{1.0, 10.0, 100.0, 1000.0}};
1014 std::array<double, 4> double2IntBad{{1e100, 1.25, 2.5, 100.00001}};
1018 #define STRING_TO_TYPE_BENCHMARK(type, name, pass, fail) \
1019 BENCHMARK(stringTo##name##Classic, n) { \
1020 stringToTypeClassic<type>(pass, n); \
1022 BENCHMARK(stringTo##name##ClassicError, n) { \
1023 stringToTypeClassic<type>(fail, n); \
1025 BENCHMARK(stringTo##name##Optional, n) { \
1026 stringToTypeOptional<type>(pass, n); \
1028 BENCHMARK(stringTo##name##OptionalError, n) { \
1029 stringToTypeOptional<type>(fail, n); \
1032 #define PTR_PAIR_TO_INT_BENCHMARK(type, name, pass, fail) \
1033 BENCHMARK(ptrPairTo##name##Classic, n) { \
1034 ptrPairToIntClassic<type>(pass, n); \
1036 BENCHMARK(ptrPairTo##name##ClassicError, n) { \
1037 ptrPairToIntClassic<type>(fail, n); \
1039 BENCHMARK(ptrPairTo##name##Optional, n) { \
1040 ptrPairToIntOptional<type>(pass, n); \
1042 BENCHMARK(ptrPairTo##name##OptionalError, n) { \
1043 ptrPairToIntOptional<type>(fail, n); \
1046 #define ARITH_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1047 BENCHMARK_MULTI(name##Classic) { \
1048 return arithToArithClassic<type>(pass.data(), pass.size()); \
1050 BENCHMARK_MULTI(name##ClassicError) { \
1051 return arithToArithClassic<type>(fail.data(), fail.size()); \
1053 BENCHMARK_MULTI(name##Optional) { \
1054 return arithToArithOptional<type>(pass.data(), pass.size()); \
1056 BENCHMARK_MULTI(name##OptionalError) { \
1057 return arithToArithOptional<type>(fail.data(), fail.size()); \
1060 #define INT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1061 ARITH_TO_ARITH_BENCHMARK(type, intTo##name, pass, fail)
1063 #define FLOAT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1064 ARITH_TO_ARITH_BENCHMARK(type, floatTo##name, pass, fail)
1066 STRING_TO_TYPE_BENCHMARK(bool, BoolNum, " 1 ", "2")
1067 STRING_TO_TYPE_BENCHMARK(bool, BoolStr, "true", "xxxx")
1068 BENCHMARK_DRAW_LINE();
1069 STRING_TO_TYPE_BENCHMARK(float, FloatNum, " 3.14 ", "3e5000x")
1070 STRING_TO_TYPE_BENCHMARK(float, FloatStr, "-infinity", "xxxx")
1071 STRING_TO_TYPE_BENCHMARK(double, DoubleNum, " 3.14 ", "3e5000x")
1072 STRING_TO_TYPE_BENCHMARK(double, DoubleStr, "-infinity", "xxxx")
1073 BENCHMARK_DRAW_LINE();
1074 STRING_TO_TYPE_BENCHMARK(signed char, CharSigned, " -47 ", "1000")
1075 STRING_TO_TYPE_BENCHMARK(unsigned char, CharUnsigned, " 47 ", "-47")
1076 STRING_TO_TYPE_BENCHMARK(int, IntSigned, " -4711 ", "-10000000000000000000000")
1077 STRING_TO_TYPE_BENCHMARK(unsigned int, IntUnsigned, " 4711 ", "-4711")
1078 STRING_TO_TYPE_BENCHMARK(
1081 " -8123456789123456789 ",
1082 "-10000000000000000000000")
1083 STRING_TO_TYPE_BENCHMARK(
1086 " 18123456789123456789 ",
1088 BENCHMARK_DRAW_LINE();
1090 PTR_PAIR_TO_INT_BENCHMARK(signed char, CharSigned, "-47", "1000")
1091 PTR_PAIR_TO_INT_BENCHMARK(unsigned char, CharUnsigned, "47", "1000")
1092 PTR_PAIR_TO_INT_BENCHMARK(int, IntSigned, "-4711", "-10000000000000000000000")
1093 PTR_PAIR_TO_INT_BENCHMARK(
1097 "10000000000000000000000")
1098 PTR_PAIR_TO_INT_BENCHMARK(
1101 "-8123456789123456789",
1102 "-10000000000000000000000")
1103 PTR_PAIR_TO_INT_BENCHMARK(
1106 "18123456789123456789",
1107 "20000000000000000000")
1108 BENCHMARK_DRAW_LINE();
1110 INT_TO_ARITH_BENCHMARK(signed char, CharSigned, int2ScharGood, int2ScharBad)
1111 INT_TO_ARITH_BENCHMARK(unsigned char, CharUnsigned, int2UcharGood, int2UcharBad)
1112 INT_TO_ARITH_BENCHMARK(int, IntSigned, ll2SintOrFloatGood, ll2SintOrFloatBad)
1113 INT_TO_ARITH_BENCHMARK(unsigned int, IntUnsigned, ll2UintGood, ll2UintBad)
1114 BENCHMARK_DRAW_LINE();
1115 INT_TO_ARITH_BENCHMARK(float, Float, ll2SintOrFloatGood, ll2SintOrFloatBad)
1116 BENCHMARK_DRAW_LINE();
1117 FLOAT_TO_ARITH_BENCHMARK(float, Float, double2FloatGood, double2FloatBad)
1118 BENCHMARK_DRAW_LINE();
1119 FLOAT_TO_ARITH_BENCHMARK(int, Int, double2IntGood, double2IntBad)
1121 #undef STRING_TO_TYPE_BENCHMARK
1122 #undef PTR_PAIR_TO_INT_BENCHMARK
1123 #undef ARITH_TO_ARITH_BENCHMARK
1124 #undef INT_TO_ARITH_BENCHMARK
1125 #undef FLOAT_TO_ARITH_BENCHMARK
1127 int main(int argc, char** argv) {
1128 gflags::ParseCommandLineFlags(&argc, &argv, true);
1129 folly::runBenchmarks();