/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2011-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>
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, size_t index) {
+ checkArrayIndex(uint64Num, index);
+ FOR_EACH_RANGE (i, 0, n) {
+ doNotOptimizeAway(to<std::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); }
+// 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(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);
#undef DEFINE_BENCHMARK_GROUP
-#define DEFINE_BENCHMARK_GROUP(n) \
- BENCHMARK_PARAM(u64ToStringClibMeasure, n); \
- BENCHMARK_RELATIVE_PARAM(u64ToStringFollyMeasure, n); \
+#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
+#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(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); \
}
}
+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) {
}
}
+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>
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 conv {
+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<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}};
-}
-
-using namespace conv;
+} // namespace conv_bench_detail
+} // namespace folly
#define STRING_TO_TYPE_BENCHMARK(type, name, pass, fail) \
BENCHMARK(stringTo##name##Classic, 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##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()); \
+#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) \