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 FOR_EACH_RANGE(i, 0, n) { doNotOptimizeAway(atoll(p.begin())); }
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()));
331 // Benchmarks for unsigned to string conversion, raw
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";
346 uint32_t const length = digits10(value);
347 uint32_t next = length - 1;
348 while (value >= 100) {
349 auto const i = (value % 100) * 2;
351 dst[next] = digits[i + 1];
352 dst[next - 1] = digits[i];
355 // Handle last 1-2 digits
357 dst[next] = '0' + uint32_t(value);
359 auto i = uint32_t(value) * 2;
360 dst[next] = digits[i + 1];
361 dst[next - 1] = digits[i];
366 void u64ToAsciiTableBM(unsigned int n, size_t index) {
367 checkArrayIndex(uint64Num, index);
369 FOR_EACH_RANGE(i, 0, n) {
370 doNotOptimizeAway(u64ToAsciiTable(uint64Num[index] + (i % 8), buf));
374 unsigned u64ToAsciiClassic(uint64_t value, char* dst) {
376 char* next = (char*)dst;
379 *next++ = '0' + (value % 10);
381 } while (value != 0);
382 unsigned length = next - start;
386 while (next > start) {
396 void u64ToAsciiClassicBM(unsigned int n, size_t index) {
397 checkArrayIndex(uint64Num, index);
399 FOR_EACH_RANGE(i, 0, n) {
400 doNotOptimizeAway(u64ToAsciiClassic(uint64Num[index] + (i % 8), buf));
404 void u64ToAsciiFollyBM(unsigned int n, size_t index) {
405 checkArrayIndex(uint64Num, index);
407 FOR_EACH_RANGE(i, 0, n) {
408 doNotOptimizeAway(uint64ToBufferUnsafe(uint64Num[index] + (i % 8), buf));
412 // Benchmark unsigned to string conversion
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) {
420 FOLLY_RANGE_CHECK_TO_STRING(uint64Num[index] + (i % 8)).size());
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());
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());
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());
447 // Benchmark uitoa with string append
449 void u2aAppendClassicBM(unsigned int n, size_t index) {
450 checkArrayIndex(uint64Num, index);
452 FOR_EACH_RANGE(i, 0, n) {
453 // auto buf = &s.back() + 1;
455 s.append(buffer, u64ToAsciiClassic(uint64Num[index] + (i % 8), buffer));
456 doNotOptimizeAway(s.size());
460 void u2aAppendFollyBM(unsigned int n, size_t index) {
461 checkArrayIndex(uint64Num, index);
463 FOR_EACH_RANGE(i, 0, n) {
464 // auto buf = &s.back() + 1;
466 s.append(buffer, uint64ToBufferUnsafe(uint64Num[index] + (i % 8), buffer));
467 doNotOptimizeAway(s.size());
471 template <class String>
472 struct StringIdenticalToBM {
473 StringIdenticalToBM() {}
474 void operator()(unsigned int n, size_t len) const {
476 BENCHMARK_SUSPEND { s.append(len, '0'); }
477 FOR_EACH_RANGE(i, 0, n) {
478 String result = to<String>(s);
479 doNotOptimizeAway(result.size());
484 template <class String>
485 struct StringVariadicToBM {
486 StringVariadicToBM() {}
487 void operator()(unsigned int n, size_t len) const {
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());
498 namespace conv_bench_detail {
500 // Keep this data global and non-const, so the compiler cannot make
501 // any assumptions about the actual values at compile time
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;
514 BENCHMARK(preallocateTestNoFloat, n) {
515 for (size_t i = 0; i < n; ++i) {
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());
521 to<std::string>(bigInt, stdString, dValue, otherString).size());
522 doNotOptimizeAway(to<std::string>(bigInt, someString, reallyShort).size());
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());
534 namespace conv_bench_detail {
536 // Keep this data global and non-const, so the compiler cannot make
537 // any assumptions about the actual values at compile time
540 -(static_cast<int8_t>(1) << 4),
541 static_cast<int8_t>(1) << 5,
542 -(static_cast<int8_t>(1) << 6),
546 static_cast<uint8_t>(1) << 4,
547 static_cast<uint8_t>(1) << 5,
548 static_cast<uint8_t>(1) << 7,
552 -(static_cast<int16_t>(1) << 8),
553 static_cast<int16_t>(1) << 12,
554 -(static_cast<int16_t>(1) << 14),
558 static_cast<uint16_t>(1) << 8,
559 static_cast<uint16_t>(1) << 12,
560 static_cast<uint16_t>(1) << 15,
564 -(static_cast<int32_t>(1) << 16),
565 static_cast<int32_t>(1) << 25,
566 -(static_cast<int32_t>(1) << 30),
570 static_cast<uint32_t>(1) << 16,
571 static_cast<uint32_t>(1) << 25,
572 static_cast<uint32_t>(1) << 31,
576 -(static_cast<int64_t>(1) << 32),
577 static_cast<int64_t>(1) << 50,
578 -(static_cast<int64_t>(1) << 62),
582 static_cast<uint64_t>(1) << 32,
583 static_cast<uint64_t>(1) << 50,
584 static_cast<uint64_t>(1) << 63,
589 BENCHMARK(preallocateTestInt8, n) {
590 for (size_t i = 0; i < n; ++i) {
591 doNotOptimizeAway(to<std::string>(
607 BENCHMARK(preallocateTestInt16, n) {
608 for (size_t i = 0; i < n; ++i) {
609 doNotOptimizeAway(to<std::string>(
625 BENCHMARK(preallocateTestInt32, n) {
626 for (size_t i = 0; i < n; ++i) {
627 doNotOptimizeAway(to<std::string>(
643 BENCHMARK(preallocateTestInt64, n) {
644 for (size_t i = 0; i < n; ++i) {
645 doNotOptimizeAway(to<std::string>(
661 #if FOLLY_HAVE_INT128_T
665 -(static_cast<__int128>(1) << 2),
666 static_cast<__int128>(1) << 100,
667 -(static_cast<__int128>(1) << 126),
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,
677 BENCHMARK(preallocateTestInt128, n) {
678 for (size_t i = 0; i < n; ++i) {
679 doNotOptimizeAway(to<std::string>(
695 BENCHMARK(preallocateTestNoFloatWithInt128, n) {
696 for (size_t i = 0; i < n; ++i) {
698 to<std::string>(bigInt, someString, stdString, otherString).size());
700 to<std::string>(reallyShort, u128s[0], smallInt, i128s[2]).size());
702 to<std::string>(bigInt, i128s[0], stdString, u128s[1]).size());
704 to<std::string>(bigInt, stdString, dValue, otherString).size());
706 to<std::string>(bigInt, u128s[2], someString, reallyShort).size());
711 BENCHMARK_DRAW_LINE();
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;
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();
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);
745 #undef DEFINE_BENCHMARK_GROUP
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();
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);
775 BENCHMARK_PARAM(u64ToStringClibMeasure, 20);
776 BENCHMARK_RELATIVE_PARAM(u64ToStringFollyMeasure, 20);
777 BENCHMARK_DRAW_LINE();
779 #undef DEFINE_BENCHMARK_GROUP
781 #if FOLLY_HAVE_INT128_T
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());
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());
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());
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();
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);
850 BENCHMARK_DRAW_LINE();
852 #undef DEFINE_BENCHMARK_GROUP
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();
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);
883 #undef DEFINE_BENCHMARK_GROUP
885 #define DEFINE_BENCHMARK_GROUP(T, n) \
886 BENCHMARK_PARAM(T##VariadicToBM, n); \
887 BENCHMARK_RELATIVE_PARAM(T##IdenticalToBM, n); \
888 BENCHMARK_DRAW_LINE();
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);
897 #undef DEFINE_BENCHMARK_GROUP
901 template <typename T>
902 inline void stringToTypeClassic(const char* str, uint32_t n) {
903 for (uint32_t i = 0; i < n; ++i) {
905 auto val = to<T>(str);
906 doNotOptimizeAway(val);
907 } catch (const std::exception& e) {
908 doNotOptimizeAway(e.what());
910 doNotOptimizeAway(i);
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());
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 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());
947 constexpr uint32_t kArithNumIter = 10000;
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) {
954 auto val = to<T>(in[j]);
955 doNotOptimizeAway(val);
956 } catch (const std::exception& e) {
957 doNotOptimizeAway(e.what());
959 doNotOptimizeAway(j);
961 doNotOptimizeAway(i);
964 return kArithNumIter * numItems;
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);
977 doNotOptimizeAway(j);
979 doNotOptimizeAway(i);
982 return kArithNumIter * numItems;
988 namespace conv_bench_detail {
990 // Keep this data global and non-const, so the compiler cannot make
991 // any assumptions about the actual values at compile time
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}};
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,
1005 std::array<long long, 4> ll2UintGood{{1, 2, 3, 4}};
1006 std::array<long long, 4> ll2UintBad{{-1, -2, -3, -4}};
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}};
1015 #define STRING_TO_TYPE_BENCHMARK(type, name, pass, fail) \
1016 BENCHMARK(stringTo##name##Classic, n) { \
1017 stringToTypeClassic<type>(pass, n); \
1019 BENCHMARK(stringTo##name##ClassicError, n) { \
1020 stringToTypeClassic<type>(fail, n); \
1022 BENCHMARK(stringTo##name##Optional, n) { \
1023 stringToTypeOptional<type>(pass, n); \
1025 BENCHMARK(stringTo##name##OptionalError, n) { \
1026 stringToTypeOptional<type>(fail, n); \
1029 #define PTR_PAIR_TO_INT_BENCHMARK(type, name, pass, fail) \
1030 BENCHMARK(ptrPairTo##name##Classic, n) { \
1031 ptrPairToIntClassic<type>(pass, n); \
1033 BENCHMARK(ptrPairTo##name##ClassicError, n) { \
1034 ptrPairToIntClassic<type>(fail, n); \
1036 BENCHMARK(ptrPairTo##name##Optional, n) { \
1037 ptrPairToIntOptional<type>(pass, n); \
1039 BENCHMARK(ptrPairTo##name##OptionalError, n) { \
1040 ptrPairToIntOptional<type>(fail, n); \
1043 #define ARITH_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1044 BENCHMARK_MULTI(name##Classic) { \
1045 return arithToArithClassic<type>(pass.data(), pass.size()); \
1047 BENCHMARK_MULTI(name##ClassicError) { \
1048 return arithToArithClassic<type>(fail.data(), fail.size()); \
1050 BENCHMARK_MULTI(name##Optional) { \
1051 return arithToArithOptional<type>(pass.data(), pass.size()); \
1053 BENCHMARK_MULTI(name##OptionalError) { \
1054 return arithToArithOptional<type>(fail.data(), fail.size()); \
1057 #define INT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1058 ARITH_TO_ARITH_BENCHMARK(type, intTo##name, pass, fail)
1060 #define FLOAT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
1061 ARITH_TO_ARITH_BENCHMARK(type, floatTo##name, pass, fail)
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(
1078 " -8123456789123456789 ",
1079 "-10000000000000000000000")
1080 STRING_TO_TYPE_BENCHMARK(
1083 " 18123456789123456789 ",
1085 BENCHMARK_DRAW_LINE();
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(
1094 "10000000000000000000000")
1095 PTR_PAIR_TO_INT_BENCHMARK(
1098 "-8123456789123456789",
1099 "-10000000000000000000000")
1100 PTR_PAIR_TO_INT_BENCHMARK(
1103 "18123456789123456789",
1104 "20000000000000000000")
1105 BENCHMARK_DRAW_LINE();
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)
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
1124 int main(int argc, char** argv) {
1125 gflags::ParseCommandLineFlags(&argc, &argv, true);
1126 folly::runBenchmarks();