/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2016-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <boost/lexical_cast.hpp>
#include <folly/Benchmark.h>
-#include <folly/Foreach.h>
+#include <folly/CppAttributes.h>
+#include <folly/container/Foreach.h>
+#include <array>
#include <limits>
#include <stdexcept>
using namespace std;
using namespace folly;
+// Android doesn't support std::to_string so just use a placeholder there.
+#ifdef __ANDROID__
+#define FOLLY_RANGE_CHECK_TO_STRING(x) std::string("N/A")
+#else
+#define FOLLY_RANGE_CHECK_TO_STRING(x) std::to_string(x)
+#endif
+
+namespace folly {
+namespace conv_bench_detail {
+
+// Keep this data global and non-const, so the compiler cannot make
+// any assumptions about the actual values at compile time
+
+uint64_t uint64Num[] = {
+ 0,
+ 1ULL,
+ 12ULL,
+ 123ULL,
+ 1234ULL,
+ 12345ULL,
+ 123456ULL,
+ 1234567ULL,
+ 12345678ULL,
+ 123456789ULL,
+ 1234567890ULL,
+ 12345678901ULL,
+ 123456789012ULL,
+ 1234567890123ULL,
+ 12345678901234ULL,
+ 123456789012345ULL,
+ 1234567890123456ULL,
+ 12345678901234567ULL,
+ 123456789012345678ULL,
+ 1234567890123456789ULL,
+ 12345678901234567890ULL,
+};
+
+int64_t int64Pos[] = {
+ 0,
+ 1LL,
+ 12LL,
+ 123LL,
+ 1234LL,
+ 12345LL,
+ 123456LL,
+ 1234567LL,
+ 12345678LL,
+ 123456789LL,
+ 1234567890LL,
+ 12345678901LL,
+ 123456789012LL,
+ 1234567890123LL,
+ 12345678901234LL,
+ 123456789012345LL,
+ 1234567890123456LL,
+ 12345678901234567LL,
+ 123456789012345678LL,
+ 1234567890123456789LL,
+};
+
+int64_t int64Neg[] = {
+ 0,
+ -1LL,
+ -12LL,
+ -123LL,
+ -1234LL,
+ -12345LL,
+ -123456LL,
+ -1234567LL,
+ -12345678LL,
+ -123456789LL,
+ -1234567890LL,
+ -12345678901LL,
+ -123456789012LL,
+ -1234567890123LL,
+ -12345678901234LL,
+ -123456789012345LL,
+ -1234567890123456LL,
+ -12345678901234567LL,
+ -123456789012345678LL,
+ -1234567890123456789LL,
+};
+
+#if FOLLY_HAVE_INT128_T
+
+unsigned __int128 uint128Num[] = {
+ 0,
+ static_cast<unsigned __int128>(1) << 0,
+ static_cast<unsigned __int128>(1) << 4,
+ static_cast<unsigned __int128>(1) << 7,
+ static_cast<unsigned __int128>(1) << 10,
+ static_cast<unsigned __int128>(1) << 14,
+ static_cast<unsigned __int128>(1) << 17,
+ static_cast<unsigned __int128>(1) << 20,
+ static_cast<unsigned __int128>(1) << 24,
+ static_cast<unsigned __int128>(1) << 27,
+ static_cast<unsigned __int128>(1) << 30,
+ static_cast<unsigned __int128>(1) << 34,
+ static_cast<unsigned __int128>(1) << 37,
+ static_cast<unsigned __int128>(1) << 40,
+ static_cast<unsigned __int128>(1) << 44,
+ static_cast<unsigned __int128>(1) << 47,
+ static_cast<unsigned __int128>(1) << 50,
+ static_cast<unsigned __int128>(1) << 54,
+ static_cast<unsigned __int128>(1) << 57,
+ static_cast<unsigned __int128>(1) << 60,
+ static_cast<unsigned __int128>(1) << 64,
+ static_cast<unsigned __int128>(1) << 67,
+ static_cast<unsigned __int128>(1) << 70,
+ static_cast<unsigned __int128>(1) << 74,
+ static_cast<unsigned __int128>(1) << 77,
+ static_cast<unsigned __int128>(1) << 80,
+ static_cast<unsigned __int128>(1) << 84,
+ static_cast<unsigned __int128>(1) << 87,
+ static_cast<unsigned __int128>(1) << 90,
+ static_cast<unsigned __int128>(1) << 94,
+ static_cast<unsigned __int128>(1) << 97,
+ static_cast<unsigned __int128>(1) << 100,
+ static_cast<unsigned __int128>(1) << 103,
+ static_cast<unsigned __int128>(1) << 107,
+ static_cast<unsigned __int128>(1) << 110,
+ static_cast<unsigned __int128>(1) << 113,
+ static_cast<unsigned __int128>(1) << 117,
+ static_cast<unsigned __int128>(1) << 120,
+ static_cast<unsigned __int128>(1) << 123,
+ static_cast<unsigned __int128>(1) << 127,
+};
+
+__int128 int128Pos[] = {
+ 0,
+ static_cast<__int128>(1) << 0,
+ static_cast<__int128>(1) << 4,
+ static_cast<__int128>(1) << 7,
+ static_cast<__int128>(1) << 10,
+ static_cast<__int128>(1) << 14,
+ static_cast<__int128>(1) << 17,
+ static_cast<__int128>(1) << 20,
+ static_cast<__int128>(1) << 24,
+ static_cast<__int128>(1) << 27,
+ static_cast<__int128>(1) << 30,
+ static_cast<__int128>(1) << 34,
+ static_cast<__int128>(1) << 37,
+ static_cast<__int128>(1) << 40,
+ static_cast<__int128>(1) << 44,
+ static_cast<__int128>(1) << 47,
+ static_cast<__int128>(1) << 50,
+ static_cast<__int128>(1) << 54,
+ static_cast<__int128>(1) << 57,
+ static_cast<__int128>(1) << 60,
+ static_cast<__int128>(1) << 64,
+ static_cast<__int128>(1) << 67,
+ static_cast<__int128>(1) << 70,
+ static_cast<__int128>(1) << 74,
+ static_cast<__int128>(1) << 77,
+ static_cast<__int128>(1) << 80,
+ static_cast<__int128>(1) << 84,
+ static_cast<__int128>(1) << 87,
+ static_cast<__int128>(1) << 90,
+ static_cast<__int128>(1) << 94,
+ static_cast<__int128>(1) << 97,
+ static_cast<__int128>(1) << 100,
+ static_cast<__int128>(1) << 103,
+ static_cast<__int128>(1) << 107,
+ static_cast<__int128>(1) << 110,
+ static_cast<__int128>(1) << 113,
+ static_cast<__int128>(1) << 117,
+ static_cast<__int128>(1) << 120,
+ static_cast<__int128>(1) << 123,
+ static_cast<__int128>(3) << 125,
+};
+
+__int128 int128Neg[] = {
+ 0,
+ -(static_cast<__int128>(1) << 0),
+ -(static_cast<__int128>(1) << 4),
+ -(static_cast<__int128>(1) << 7),
+ -(static_cast<__int128>(1) << 10),
+ -(static_cast<__int128>(1) << 14),
+ -(static_cast<__int128>(1) << 17),
+ -(static_cast<__int128>(1) << 20),
+ -(static_cast<__int128>(1) << 24),
+ -(static_cast<__int128>(1) << 27),
+ -(static_cast<__int128>(1) << 30),
+ -(static_cast<__int128>(1) << 34),
+ -(static_cast<__int128>(1) << 37),
+ -(static_cast<__int128>(1) << 40),
+ -(static_cast<__int128>(1) << 44),
+ -(static_cast<__int128>(1) << 47),
+ -(static_cast<__int128>(1) << 50),
+ -(static_cast<__int128>(1) << 54),
+ -(static_cast<__int128>(1) << 57),
+ -(static_cast<__int128>(1) << 60),
+ -(static_cast<__int128>(1) << 64),
+ -(static_cast<__int128>(1) << 67),
+ -(static_cast<__int128>(1) << 70),
+ -(static_cast<__int128>(1) << 74),
+ -(static_cast<__int128>(1) << 77),
+ -(static_cast<__int128>(1) << 80),
+ -(static_cast<__int128>(1) << 84),
+ -(static_cast<__int128>(1) << 87),
+ -(static_cast<__int128>(1) << 90),
+ -(static_cast<__int128>(1) << 94),
+ -(static_cast<__int128>(1) << 97),
+ -(static_cast<__int128>(1) << 100),
+ -(static_cast<__int128>(1) << 103),
+ -(static_cast<__int128>(1) << 107),
+ -(static_cast<__int128>(1) << 110),
+ -(static_cast<__int128>(1) << 113),
+ -(static_cast<__int128>(1) << 117),
+ -(static_cast<__int128>(1) << 120),
+ -(static_cast<__int128>(1) << 123),
+ -(static_cast<__int128>(3) << 125),
+};
+
+#endif
+} // namespace conv_bench_detail
+} // namespace folly
+
+using namespace folly::conv_bench_detail;
+
+namespace {
+
+template <typename T>
+void checkArrayIndex(const T& array, size_t index) {
+ DCHECK_LT(index, sizeof(array) / sizeof(array[0]));
+}
+} // namespace
+
////////////////////////////////////////////////////////////////////////////////
// Benchmarks for ASCII to int conversion
////////////////////////////////////////////////////////////////////////////////
switch (*start) {
case '-':
positive = false;
+ FOLLY_FALLTHROUGH;
case '+':
++start;
+ FOLLY_FALLTHROUGH;
default:
- ;
+ break;
}
while (start < end && *start >= '0' && *start <= '9') {
void clibAtoiMeasure(unsigned int n, unsigned int digits) {
auto p = pc1.subpiece(pc1.size() - digits, digits);
assert(*p.end() == 0);
- static_assert(sizeof(long) == 8, "64-bit long assumed");
- FOR_EACH_RANGE(i, 0, n) { doNotOptimizeAway(atol(p.begin())); }
-}
-
-void clibStrtoulMeasure(unsigned int n, unsigned int digits) {
- auto p = pc1.subpiece(pc1.size() - digits, digits);
- assert(*p.end() == 0);
- char* endptr;
- FOR_EACH_RANGE(i, 0, n) {
- doNotOptimizeAway(strtoul(p.begin(), &endptr, 10));
- }
+ FOR_EACH_RANGE(i, 0, n) { doNotOptimizeAway(atoll(p.begin())); }
}
void lexicalCastMeasure(unsigned int n, unsigned int digits) {
return length;
}
-void u64ToAsciiTableBM(unsigned int n, uint64_t value) {
- // This is too fast, need to do 10 times per iteration
+void u64ToAsciiTableBM(unsigned int n, size_t index) {
+ checkArrayIndex(uint64Num, index);
char buf[20];
FOR_EACH_RANGE(i, 0, n) {
- doNotOptimizeAway(u64ToAsciiTable(value + n, buf));
+ doNotOptimizeAway(u64ToAsciiTable(uint64Num[index] + (i % 8), buf));
}
}
return length;
}
-void u64ToAsciiClassicBM(unsigned int n, uint64_t value) {
- // This is too fast, need to do 10 times per iteration
+void u64ToAsciiClassicBM(unsigned int n, size_t index) {
+ checkArrayIndex(uint64Num, index);
char buf[20];
FOR_EACH_RANGE(i, 0, n) {
- doNotOptimizeAway(u64ToAsciiClassic(value + n, buf));
+ doNotOptimizeAway(u64ToAsciiClassic(uint64Num[index] + (i % 8), buf));
}
}
-void u64ToAsciiFollyBM(unsigned int n, uint64_t value) {
- // This is too fast, need to do 10 times per iteration
+void u64ToAsciiFollyBM(unsigned int n, size_t index) {
+ checkArrayIndex(uint64Num, index);
char buf[20];
FOR_EACH_RANGE(i, 0, n) {
- doNotOptimizeAway(uint64ToBufferUnsafe(value + n, buf));
+ doNotOptimizeAway(uint64ToBufferUnsafe(uint64Num[index] + (i % 8), buf));
}
}
// Benchmark unsigned to string conversion
-void u64ToStringClibMeasure(unsigned int n, uint64_t value) {
+void u64ToStringClibMeasure(unsigned int n, size_t index) {
// FOLLY_RANGE_CHECK_TO_STRING expands to std::to_string, except on Android
// where std::to_string is not supported
- FOR_EACH_RANGE(i, 0, n) { FOLLY_RANGE_CHECK_TO_STRING(value + n); }
+ checkArrayIndex(uint64Num, index);
+ FOR_EACH_RANGE (i, 0, n) {
+ doNotOptimizeAway(
+ FOLLY_RANGE_CHECK_TO_STRING(uint64Num[index] + (i % 8)).size());
+ }
}
-void u64ToStringFollyMeasure(unsigned int n, uint64_t value) {
- FOR_EACH_RANGE(i, 0, n) { to<std::string>(value + n); }
+void u64ToStringFollyMeasure(unsigned int n, size_t index) {
+ checkArrayIndex(uint64Num, index);
+ FOR_EACH_RANGE (i, 0, n) {
+ doNotOptimizeAway(to<std::string>(uint64Num[index] + (i % 8)).size());
+ }
+}
+
+// Signed
+
+void i64ToStringFollyMeasurePos(unsigned int n, size_t index) {
+ checkArrayIndex(int64Pos, index);
+ FOR_EACH_RANGE (i, 0, n) {
+ doNotOptimizeAway(to<std::string>(int64Pos[index] + (i % 8)).size());
+ }
+}
+
+void i64ToStringFollyMeasureNeg(unsigned int n, size_t index) {
+ checkArrayIndex(int64Neg, index);
+ FOR_EACH_RANGE (i, 0, n) {
+ doNotOptimizeAway(to<std::string>(int64Neg[index] - (i % 8)).size());
+ }
}
// Benchmark uitoa with string append
-void u2aAppendClassicBM(unsigned int n, uint64_t value) {
+void u2aAppendClassicBM(unsigned int n, size_t index) {
+ checkArrayIndex(uint64Num, index);
string s;
FOR_EACH_RANGE(i, 0, n) {
// auto buf = &s.back() + 1;
char buffer[20];
- s.append(buffer, u64ToAsciiClassic(value, buffer));
+ s.append(buffer, u64ToAsciiClassic(uint64Num[index] + (i % 8), buffer));
doNotOptimizeAway(s.size());
}
}
-void u2aAppendFollyBM(unsigned int n, uint64_t value) {
+void u2aAppendFollyBM(unsigned int n, size_t index) {
+ checkArrayIndex(uint64Num, index);
string s;
FOR_EACH_RANGE(i, 0, n) {
// auto buf = &s.back() + 1;
char buffer[20];
- s.append(buffer, uint64ToBufferUnsafe(value, buffer));
+ s.append(buffer, uint64ToBufferUnsafe(uint64Num[index] + (i % 8), buffer));
doNotOptimizeAway(s.size());
}
}
}
};
-static size_t bigInt = 11424545345345;
-static size_t smallInt = 104;
-static char someString[] = "this is some nice string";
-static char otherString[] = "this is a long string, so it's not so nice";
-static char reallyShort[] = "meh";
-static std::string stdString = "std::strings are very nice";
-static float fValue = 1.2355;
-static double dValue = 345345345.435;
+namespace folly {
+namespace conv_bench_detail {
+
+// Keep this data global and non-const, so the compiler cannot make
+// any assumptions about the actual values at compile time
+
+size_t bigInt = 11424545345345;
+size_t smallInt = 104;
+char someString[] = "this is some nice string";
+char otherString[] = "this is a long string, so it's not so nice";
+char reallyShort[] = "meh";
+std::string stdString = "std::strings are very nice";
+float fValue = 1.2355f;
+double dValue = 345345345.435;
+} // namespace conv_bench_detail
+} // namespace folly
BENCHMARK(preallocateTestNoFloat, n) {
for (size_t i = 0; i < n; ++i) {
- auto val1 = to<std::string>(bigInt, someString, stdString, otherString);
- auto val3 = to<std::string>(reallyShort, smallInt);
- auto val2 = to<std::string>(bigInt, stdString);
- auto val4 = to<std::string>(bigInt, stdString, dValue, otherString);
- auto val5 = to<std::string>(bigInt, someString, reallyShort);
+ doNotOptimizeAway(
+ to<std::string>(bigInt, someString, stdString, otherString).size());
+ doNotOptimizeAway(to<std::string>(reallyShort, smallInt).size());
+ doNotOptimizeAway(to<std::string>(bigInt, stdString).size());
+ doNotOptimizeAway(
+ to<std::string>(bigInt, stdString, dValue, otherString).size());
+ doNotOptimizeAway(to<std::string>(bigInt, someString, reallyShort).size());
}
}
BENCHMARK(preallocateTestFloat, n) {
for (size_t i = 0; i < n; ++i) {
- auto val1 = to<std::string>(stdString, ',', fValue, dValue);
- auto val2 = to<std::string>(stdString, ',', dValue);
+ doNotOptimizeAway(to<std::string>(stdString, ',', fValue, dValue).size());
+ doNotOptimizeAway(to<std::string>(stdString, ',', dValue).size());
+ }
+}
+
+namespace folly {
+namespace conv_bench_detail {
+
+// Keep this data global and non-const, so the compiler cannot make
+// any assumptions about the actual values at compile time
+
+int8_t i8s[] = {
+ -(static_cast<int8_t>(1) << 4),
+ static_cast<int8_t>(1) << 5,
+ -(static_cast<int8_t>(1) << 6),
+};
+
+uint8_t u8s[] = {
+ static_cast<uint8_t>(1) << 4,
+ static_cast<uint8_t>(1) << 5,
+ static_cast<uint8_t>(1) << 7,
+};
+
+int16_t i16s[] = {
+ -(static_cast<int16_t>(1) << 8),
+ static_cast<int16_t>(1) << 12,
+ -(static_cast<int16_t>(1) << 14),
+};
+
+uint16_t u16s[] = {
+ static_cast<uint16_t>(1) << 8,
+ static_cast<uint16_t>(1) << 12,
+ static_cast<uint16_t>(1) << 15,
+};
+
+int32_t i32s[] = {
+ -(static_cast<int32_t>(1) << 16),
+ static_cast<int32_t>(1) << 25,
+ -(static_cast<int32_t>(1) << 30),
+};
+
+uint32_t u32s[] = {
+ static_cast<uint32_t>(1) << 16,
+ static_cast<uint32_t>(1) << 25,
+ static_cast<uint32_t>(1) << 31,
+};
+
+int64_t i64s[] = {
+ -(static_cast<int64_t>(1) << 32),
+ static_cast<int64_t>(1) << 50,
+ -(static_cast<int64_t>(1) << 62),
+};
+
+uint64_t u64s[] = {
+ static_cast<uint64_t>(1) << 32,
+ static_cast<uint64_t>(1) << 50,
+ static_cast<uint64_t>(1) << 63,
+};
+} // namespace conv_bench_detail
+} // namespace folly
+
+BENCHMARK(preallocateTestInt8, n) {
+ for (size_t i = 0; i < n; ++i) {
+ doNotOptimizeAway(to<std::string>(
+ i8s[0],
+ ',',
+ u8s[0],
+ ',',
+ i8s[1],
+ ',',
+ u8s[1],
+ ',',
+ i8s[2],
+ ',',
+ u8s[2])
+ .size());
}
}
+
+BENCHMARK(preallocateTestInt16, n) {
+ for (size_t i = 0; i < n; ++i) {
+ doNotOptimizeAway(to<std::string>(
+ i16s[0],
+ ',',
+ u16s[0],
+ ',',
+ i16s[1],
+ ',',
+ u16s[1],
+ ',',
+ i16s[2],
+ ',',
+ u16s[2])
+ .size());
+ }
+}
+
+BENCHMARK(preallocateTestInt32, n) {
+ for (size_t i = 0; i < n; ++i) {
+ doNotOptimizeAway(to<std::string>(
+ i32s[0],
+ ',',
+ u32s[0],
+ ',',
+ i32s[1],
+ ',',
+ u32s[1],
+ ',',
+ i32s[2],
+ ',',
+ u32s[2])
+ .size());
+ }
+}
+
+BENCHMARK(preallocateTestInt64, n) {
+ for (size_t i = 0; i < n; ++i) {
+ doNotOptimizeAway(to<std::string>(
+ i64s[0],
+ ',',
+ u64s[0],
+ ',',
+ i64s[1],
+ ',',
+ u64s[1],
+ ',',
+ i64s[2],
+ ',',
+ u64s[2])
+ .size());
+ }
+}
+
+#if FOLLY_HAVE_INT128_T
+namespace {
+
+__int128 i128s[] = {
+ -(static_cast<__int128>(1) << 2),
+ static_cast<__int128>(1) << 100,
+ -(static_cast<__int128>(1) << 126),
+};
+
+unsigned __int128 u128s[] = {
+ static_cast<unsigned __int128>(1) << 2,
+ static_cast<unsigned __int128>(1) << 100,
+ static_cast<unsigned __int128>(1) << 127,
+};
+} // namespace
+
+BENCHMARK(preallocateTestInt128, n) {
+ for (size_t i = 0; i < n; ++i) {
+ doNotOptimizeAway(to<std::string>(
+ i128s[0],
+ ',',
+ u128s[0],
+ ',',
+ i128s[1],
+ ',',
+ u128s[1],
+ ',',
+ i128s[2],
+ ',',
+ u128s[2])
+ .size());
+ }
+}
+
+BENCHMARK(preallocateTestNoFloatWithInt128, n) {
+ for (size_t i = 0; i < n; ++i) {
+ doNotOptimizeAway(
+ to<std::string>(bigInt, someString, stdString, otherString).size());
+ doNotOptimizeAway(
+ to<std::string>(reallyShort, u128s[0], smallInt, i128s[2]).size());
+ doNotOptimizeAway(
+ to<std::string>(bigInt, i128s[0], stdString, u128s[1]).size());
+ doNotOptimizeAway(
+ to<std::string>(bigInt, stdString, dValue, otherString).size());
+ doNotOptimizeAway(
+ to<std::string>(bigInt, u128s[2], someString, reallyShort).size());
+ }
+}
+#endif
+
BENCHMARK_DRAW_LINE();
static const StringIdenticalToBM<std::string> stringIdenticalToBM;
BENCHMARK_DRAW_LINE();
DEFINE_BENCHMARK_GROUP(1);
+DEFINE_BENCHMARK_GROUP(2);
+DEFINE_BENCHMARK_GROUP(3);
+DEFINE_BENCHMARK_GROUP(4);
+DEFINE_BENCHMARK_GROUP(5);
+DEFINE_BENCHMARK_GROUP(6);
+DEFINE_BENCHMARK_GROUP(7);
+DEFINE_BENCHMARK_GROUP(8);
+DEFINE_BENCHMARK_GROUP(9);
+DEFINE_BENCHMARK_GROUP(10);
+DEFINE_BENCHMARK_GROUP(11);
+DEFINE_BENCHMARK_GROUP(12);
+DEFINE_BENCHMARK_GROUP(13);
+DEFINE_BENCHMARK_GROUP(14);
+DEFINE_BENCHMARK_GROUP(15);
+DEFINE_BENCHMARK_GROUP(16);
+DEFINE_BENCHMARK_GROUP(17);
+DEFINE_BENCHMARK_GROUP(18);
+DEFINE_BENCHMARK_GROUP(19);
+DEFINE_BENCHMARK_GROUP(20);
+
+#undef DEFINE_BENCHMARK_GROUP
+
+#define DEFINE_BENCHMARK_GROUP(n) \
+ BENCHMARK_PARAM(u64ToStringClibMeasure, n); \
+ BENCHMARK_RELATIVE_PARAM(u64ToStringFollyMeasure, n); \
+ BENCHMARK_RELATIVE_PARAM(i64ToStringFollyMeasurePos, n); \
+ BENCHMARK_RELATIVE_PARAM(i64ToStringFollyMeasureNeg, n); \
+ BENCHMARK_DRAW_LINE();
+
+DEFINE_BENCHMARK_GROUP(1);
+DEFINE_BENCHMARK_GROUP(2);
+DEFINE_BENCHMARK_GROUP(3);
+DEFINE_BENCHMARK_GROUP(4);
+DEFINE_BENCHMARK_GROUP(5);
+DEFINE_BENCHMARK_GROUP(6);
+DEFINE_BENCHMARK_GROUP(7);
+DEFINE_BENCHMARK_GROUP(8);
+DEFINE_BENCHMARK_GROUP(9);
+DEFINE_BENCHMARK_GROUP(10);
+DEFINE_BENCHMARK_GROUP(11);
DEFINE_BENCHMARK_GROUP(12);
-DEFINE_BENCHMARK_GROUP(123);
-DEFINE_BENCHMARK_GROUP(1234);
-DEFINE_BENCHMARK_GROUP(12345);
-DEFINE_BENCHMARK_GROUP(123456);
-DEFINE_BENCHMARK_GROUP(1234567);
-DEFINE_BENCHMARK_GROUP(12345678);
-DEFINE_BENCHMARK_GROUP(123456789);
-DEFINE_BENCHMARK_GROUP(1234567890);
-DEFINE_BENCHMARK_GROUP(12345678901);
-DEFINE_BENCHMARK_GROUP(123456789012);
-DEFINE_BENCHMARK_GROUP(1234567890123);
-DEFINE_BENCHMARK_GROUP(12345678901234);
-DEFINE_BENCHMARK_GROUP(123456789012345);
-DEFINE_BENCHMARK_GROUP(1234567890123456);
-DEFINE_BENCHMARK_GROUP(12345678901234567);
-DEFINE_BENCHMARK_GROUP(123456789012345678);
-DEFINE_BENCHMARK_GROUP(1234567890123456789);
-DEFINE_BENCHMARK_GROUP(12345678901234567890U);
+DEFINE_BENCHMARK_GROUP(13);
+DEFINE_BENCHMARK_GROUP(14);
+DEFINE_BENCHMARK_GROUP(15);
+DEFINE_BENCHMARK_GROUP(16);
+DEFINE_BENCHMARK_GROUP(17);
+DEFINE_BENCHMARK_GROUP(18);
+DEFINE_BENCHMARK_GROUP(19);
+
+// Only for u64
+BENCHMARK_PARAM(u64ToStringClibMeasure, 20);
+BENCHMARK_RELATIVE_PARAM(u64ToStringFollyMeasure, 20);
+BENCHMARK_DRAW_LINE();
#undef DEFINE_BENCHMARK_GROUP
-#define DEFINE_BENCHMARK_GROUP(n) \
- BENCHMARK_PARAM(u64ToStringClibMeasure, n); \
- BENCHMARK_RELATIVE_PARAM(u64ToStringFollyMeasure, n); \
+#if FOLLY_HAVE_INT128_T
+
+void u128ToStringFollyMeasure(unsigned int n, size_t index) {
+ checkArrayIndex(uint128Num, index);
+ FOR_EACH_RANGE (i, 0, n) {
+ doNotOptimizeAway(to<std::string>(uint128Num[index] + (i % 8)).size());
+ }
+}
+
+void i128ToStringFollyMeasurePos(unsigned int n, size_t index) {
+ checkArrayIndex(int128Pos, index);
+ FOR_EACH_RANGE (i, 0, n) {
+ doNotOptimizeAway(to<std::string>(int128Pos[index] + (i % 8)).size());
+ }
+}
+
+void i128ToStringFollyMeasureNeg(unsigned int n, size_t index) {
+ checkArrayIndex(int128Neg, index);
+ FOR_EACH_RANGE (i, 0, n) {
+ doNotOptimizeAway(to<std::string>(int128Neg[index] + (i % 8)).size());
+ }
+}
+
+#define DEFINE_BENCHMARK_GROUP(n) \
+ BENCHMARK_PARAM(u128ToStringFollyMeasure, n); \
+ BENCHMARK_RELATIVE_PARAM(i128ToStringFollyMeasurePos, n); \
+ BENCHMARK_RELATIVE_PARAM(i128ToStringFollyMeasureNeg, n); \
BENCHMARK_DRAW_LINE();
DEFINE_BENCHMARK_GROUP(1);
+DEFINE_BENCHMARK_GROUP(2);
+DEFINE_BENCHMARK_GROUP(3);
+DEFINE_BENCHMARK_GROUP(4);
+DEFINE_BENCHMARK_GROUP(5);
+DEFINE_BENCHMARK_GROUP(6);
+DEFINE_BENCHMARK_GROUP(7);
+DEFINE_BENCHMARK_GROUP(8);
+DEFINE_BENCHMARK_GROUP(9);
+DEFINE_BENCHMARK_GROUP(10);
+DEFINE_BENCHMARK_GROUP(11);
DEFINE_BENCHMARK_GROUP(12);
-DEFINE_BENCHMARK_GROUP(123);
-DEFINE_BENCHMARK_GROUP(1234);
-DEFINE_BENCHMARK_GROUP(12345);
-DEFINE_BENCHMARK_GROUP(123456);
-DEFINE_BENCHMARK_GROUP(1234567);
-DEFINE_BENCHMARK_GROUP(12345678);
-DEFINE_BENCHMARK_GROUP(123456789);
-DEFINE_BENCHMARK_GROUP(1234567890);
-DEFINE_BENCHMARK_GROUP(12345678901);
-DEFINE_BENCHMARK_GROUP(123456789012);
-DEFINE_BENCHMARK_GROUP(1234567890123);
-DEFINE_BENCHMARK_GROUP(12345678901234);
-DEFINE_BENCHMARK_GROUP(123456789012345);
-DEFINE_BENCHMARK_GROUP(1234567890123456);
-DEFINE_BENCHMARK_GROUP(12345678901234567);
-DEFINE_BENCHMARK_GROUP(123456789012345678);
-DEFINE_BENCHMARK_GROUP(1234567890123456789);
-DEFINE_BENCHMARK_GROUP(12345678901234567890U);
+DEFINE_BENCHMARK_GROUP(13);
+DEFINE_BENCHMARK_GROUP(14);
+DEFINE_BENCHMARK_GROUP(15);
+DEFINE_BENCHMARK_GROUP(16);
+DEFINE_BENCHMARK_GROUP(17);
+DEFINE_BENCHMARK_GROUP(18);
+DEFINE_BENCHMARK_GROUP(19);
+DEFINE_BENCHMARK_GROUP(20);
+DEFINE_BENCHMARK_GROUP(21);
+DEFINE_BENCHMARK_GROUP(22);
+DEFINE_BENCHMARK_GROUP(23);
+DEFINE_BENCHMARK_GROUP(24);
+DEFINE_BENCHMARK_GROUP(25);
+DEFINE_BENCHMARK_GROUP(26);
+DEFINE_BENCHMARK_GROUP(27);
+DEFINE_BENCHMARK_GROUP(28);
+DEFINE_BENCHMARK_GROUP(29);
+DEFINE_BENCHMARK_GROUP(30);
+DEFINE_BENCHMARK_GROUP(31);
+DEFINE_BENCHMARK_GROUP(32);
+DEFINE_BENCHMARK_GROUP(33);
+DEFINE_BENCHMARK_GROUP(34);
+DEFINE_BENCHMARK_GROUP(35);
+DEFINE_BENCHMARK_GROUP(36);
+DEFINE_BENCHMARK_GROUP(37);
+DEFINE_BENCHMARK_GROUP(38);
+DEFINE_BENCHMARK_GROUP(39);
+
+BENCHMARK_DRAW_LINE();
#undef DEFINE_BENCHMARK_GROUP
+#endif
+
#define DEFINE_BENCHMARK_GROUP(n) \
BENCHMARK_PARAM(clibAtoiMeasure, n); \
BENCHMARK_RELATIVE_PARAM(lexicalCastMeasure, n); \
#undef DEFINE_BENCHMARK_GROUP
+namespace {
+
+template <typename T>
+inline void stringToTypeClassic(const char* str, uint32_t n) {
+ for (uint32_t i = 0; i < n; ++i) {
+ try {
+ auto val = to<T>(str);
+ doNotOptimizeAway(val);
+ } catch (const std::exception& e) {
+ doNotOptimizeAway(e.what());
+ }
+ doNotOptimizeAway(i);
+ }
+}
+
+template <typename T>
+inline void stringToTypeOptional(const char* str, uint32_t n) {
+ for (uint32_t i = 0; i < n; ++i) {
+ auto val = tryTo<T>(str);
+ if (val.hasValue()) {
+ doNotOptimizeAway(val.value());
+ }
+ }
+}
+
+template <typename T>
+inline void ptrPairToIntClassic(StringPiece sp, uint32_t n) {
+ for (uint32_t i = 0; i < n; ++i) {
+ try {
+ auto val = to<T>(sp.begin(), sp.end());
+ doNotOptimizeAway(val);
+ } catch (const std::exception& e) {
+ doNotOptimizeAway(e.what());
+ }
+ doNotOptimizeAway(i);
+ }
+}
+
+template <typename T>
+inline void ptrPairToIntOptional(StringPiece sp, uint32_t n) {
+ for (uint32_t i = 0; i < n; ++i) {
+ auto val = tryTo<T>(sp.begin(), sp.end());
+ if (val.hasValue()) {
+ doNotOptimizeAway(val.value());
+ }
+ }
+}
+
+constexpr uint32_t kArithNumIter = 10000;
+
+template <typename T, typename U>
+inline size_t arithToArithClassic(const U* in, uint32_t numItems) {
+ for (uint32_t i = 0; i < kArithNumIter; ++i) {
+ for (uint32_t j = 0; j < numItems; ++j) {
+ try {
+ auto val = to<T>(in[j]);
+ doNotOptimizeAway(val);
+ } catch (const std::exception& e) {
+ doNotOptimizeAway(e.what());
+ }
+ doNotOptimizeAway(j);
+ }
+ doNotOptimizeAway(i);
+ }
+
+ return kArithNumIter * numItems;
+}
+
+template <typename T, typename U>
+inline size_t arithToArithOptional(const U* in, uint32_t numItems) {
+ for (uint32_t i = 0; i < kArithNumIter; ++i) {
+ for (uint32_t j = 0; j < numItems; ++j) {
+ auto val = tryTo<T>(*in);
+ doNotOptimizeAway(val.hasValue());
+ if (val.hasValue()) {
+ auto v2 = val.value();
+ doNotOptimizeAway(v2);
+ }
+ doNotOptimizeAway(j);
+ }
+ doNotOptimizeAway(i);
+ }
+
+ return kArithNumIter * numItems;
+}
+
+} // namespace
+
+namespace folly {
+namespace conv_bench_detail {
+
+// Keep this data global and non-const, so the compiler cannot make
+// any assumptions about the actual values at compile time
+
+std::array<int, 4> int2ScharGood{{-128, 127, 0, -50}};
+std::array<int, 4> int2ScharBad{{-129, 128, 255, 10000}};
+std::array<int, 4> int2UcharGood{{0, 1, 254, 255}};
+std::array<int, 4> int2UcharBad{{-128, -1000, 256, -1}};
+
+std::array<long long, 4> ll2SintOrFloatGood{{-2, -1, 0, 1}};
+std::array<long long, 4> ll2SintOrFloatBad{{
+ std::numeric_limits<long long>::min() / 5,
+ std::numeric_limits<long long>::min() / 2,
+ std::numeric_limits<long long>::max() / 2,
+ std::numeric_limits<long long>::max() / 5,
+}};
+std::array<long long, 4> ll2UintGood{{1, 2, 3, 4}};
+std::array<long long, 4> ll2UintBad{{-1, -2, -3, -4}};
+
+std::array<double, 4> double2FloatGood{{1.0, 1.25, 2.5, 1000.0}};
+std::array<double, 4> double2FloatBad{{1e100, 1e101, 1e102, 1e103}};
+std::array<double, 4> double2IntGood{{1.0, 10.0, 100.0, 1000.0}};
+std::array<double, 4> double2IntBad{{1e100, 1.25, 2.5, 100.00001}};
+} // namespace conv_bench_detail
+} // namespace folly
+
+#define STRING_TO_TYPE_BENCHMARK(type, name, pass, fail) \
+ BENCHMARK(stringTo##name##Classic, n) { \
+ stringToTypeClassic<type>(pass, n); \
+ } \
+ BENCHMARK(stringTo##name##ClassicError, n) { \
+ stringToTypeClassic<type>(fail, n); \
+ } \
+ BENCHMARK(stringTo##name##Optional, n) { \
+ stringToTypeOptional<type>(pass, n); \
+ } \
+ BENCHMARK(stringTo##name##OptionalError, n) { \
+ stringToTypeOptional<type>(fail, n); \
+ }
+
+#define PTR_PAIR_TO_INT_BENCHMARK(type, name, pass, fail) \
+ BENCHMARK(ptrPairTo##name##Classic, n) { \
+ ptrPairToIntClassic<type>(pass, n); \
+ } \
+ BENCHMARK(ptrPairTo##name##ClassicError, n) { \
+ ptrPairToIntClassic<type>(fail, n); \
+ } \
+ BENCHMARK(ptrPairTo##name##Optional, n) { \
+ ptrPairToIntOptional<type>(pass, n); \
+ } \
+ BENCHMARK(ptrPairTo##name##OptionalError, n) { \
+ ptrPairToIntOptional<type>(fail, n); \
+ }
+
+#define ARITH_TO_ARITH_BENCHMARK(type, name, pass, fail) \
+ BENCHMARK_MULTI(name##Classic) { \
+ return arithToArithClassic<type>(pass.data(), pass.size()); \
+ } \
+ BENCHMARK_MULTI(name##ClassicError) { \
+ return arithToArithClassic<type>(fail.data(), fail.size()); \
+ } \
+ BENCHMARK_MULTI(name##Optional) { \
+ return arithToArithOptional<type>(pass.data(), pass.size()); \
+ } \
+ BENCHMARK_MULTI(name##OptionalError) { \
+ return arithToArithOptional<type>(fail.data(), fail.size()); \
+ }
+
+#define INT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
+ ARITH_TO_ARITH_BENCHMARK(type, intTo##name, pass, fail)
+
+#define FLOAT_TO_ARITH_BENCHMARK(type, name, pass, fail) \
+ ARITH_TO_ARITH_BENCHMARK(type, floatTo##name, pass, fail)
+
+STRING_TO_TYPE_BENCHMARK(bool, BoolNum, " 1 ", "2")
+STRING_TO_TYPE_BENCHMARK(bool, BoolStr, "true", "xxxx")
+BENCHMARK_DRAW_LINE();
+STRING_TO_TYPE_BENCHMARK(float, FloatNum, " 3.14 ", "3e5000x")
+STRING_TO_TYPE_BENCHMARK(float, FloatStr, "-infinity", "xxxx")
+STRING_TO_TYPE_BENCHMARK(double, DoubleNum, " 3.14 ", "3e5000x")
+STRING_TO_TYPE_BENCHMARK(double, DoubleStr, "-infinity", "xxxx")
+BENCHMARK_DRAW_LINE();
+STRING_TO_TYPE_BENCHMARK(signed char, CharSigned, " -47 ", "1000")
+STRING_TO_TYPE_BENCHMARK(unsigned char, CharUnsigned, " 47 ", "-47")
+STRING_TO_TYPE_BENCHMARK(int, IntSigned, " -4711 ", "-10000000000000000000000")
+STRING_TO_TYPE_BENCHMARK(unsigned int, IntUnsigned, " 4711 ", "-4711")
+STRING_TO_TYPE_BENCHMARK(
+ long long,
+ LongLongSigned,
+ " -8123456789123456789 ",
+ "-10000000000000000000000")
+STRING_TO_TYPE_BENCHMARK(
+ unsigned long long,
+ LongLongUnsigned,
+ " 18123456789123456789 ",
+ "-4711")
+BENCHMARK_DRAW_LINE();
+
+PTR_PAIR_TO_INT_BENCHMARK(signed char, CharSigned, "-47", "1000")
+PTR_PAIR_TO_INT_BENCHMARK(unsigned char, CharUnsigned, "47", "1000")
+PTR_PAIR_TO_INT_BENCHMARK(int, IntSigned, "-4711", "-10000000000000000000000")
+PTR_PAIR_TO_INT_BENCHMARK(
+ unsigned int,
+ IntUnsigned,
+ "4711",
+ "10000000000000000000000")
+PTR_PAIR_TO_INT_BENCHMARK(
+ long long,
+ LongLongSigned,
+ "-8123456789123456789",
+ "-10000000000000000000000")
+PTR_PAIR_TO_INT_BENCHMARK(
+ unsigned long long,
+ LongLongUnsigned,
+ "18123456789123456789",
+ "20000000000000000000")
+BENCHMARK_DRAW_LINE();
+
+INT_TO_ARITH_BENCHMARK(signed char, CharSigned, int2ScharGood, int2ScharBad)
+INT_TO_ARITH_BENCHMARK(unsigned char, CharUnsigned, int2UcharGood, int2UcharBad)
+INT_TO_ARITH_BENCHMARK(int, IntSigned, ll2SintOrFloatGood, ll2SintOrFloatBad)
+INT_TO_ARITH_BENCHMARK(unsigned int, IntUnsigned, ll2UintGood, ll2UintBad)
+BENCHMARK_DRAW_LINE();
+INT_TO_ARITH_BENCHMARK(float, Float, ll2SintOrFloatGood, ll2SintOrFloatBad)
+BENCHMARK_DRAW_LINE();
+FLOAT_TO_ARITH_BENCHMARK(float, Float, double2FloatGood, double2FloatBad)
+BENCHMARK_DRAW_LINE();
+FLOAT_TO_ARITH_BENCHMARK(int, Int, double2IntGood, double2IntBad)
+
+#undef STRING_TO_TYPE_BENCHMARK
+#undef PTR_PAIR_TO_INT_BENCHMARK
+#undef ARITH_TO_ARITH_BENCHMARK
+#undef INT_TO_ARITH_BENCHMARK
+#undef FLOAT_TO_ARITH_BENCHMARK
+
int main(int argc, char** argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
folly::runBenchmarks();