Cut the ScopeGuard alias now that we have auto
[folly.git] / folly / test / ConvBenchmark.cpp
index 8a805cc46eca02e8bed118cd6c86427f6ba1d979..901004570c17a5540db439edab7c92f06812b1df 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -19,7 +19,8 @@
 #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
 ////////////////////////////////////////////////////////////////////////////////
@@ -49,10 +278,12 @@ static int64_t handwrittenAtoi(const char* start, const char* end) {
   switch (*start) {
     case '-':
       positive = false;
+      FOLLY_FALLTHROUGH;
     case '+':
       ++start;
+      FOLLY_FALLTHROUGH;
     default:
-      ;
+      break;
   }
 
   while (start < end && *start >= '0' && *start <= '9') {
@@ -89,17 +320,7 @@ void follyAtoiMeasure(unsigned int n, unsigned int digits) {
 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) {
@@ -145,11 +366,11 @@ unsigned u64ToAsciiTable(uint64_t value, char* dst) {
   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));
   }
 }
 
@@ -175,52 +396,77 @@ unsigned u64ToAsciiClassic(uint64_t value, char* dst) {
   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());
   }
 }
@@ -251,31 +497,220 @@ struct StringVariadicToBM {
   }
 };
 
-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;
@@ -290,56 +725,137 @@ static const StringVariadicToBM<fbstring> fbstringVariadicToBM;
   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);     \
@@ -398,6 +914,16 @@ inline void stringToTypeClassic(const char* str, uint32_t 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) {
@@ -411,6 +937,16 @@ inline void ptrPairToIntClassic(StringPiece sp, uint32_t n) {
   }
 }
 
+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>
@@ -431,9 +967,31 @@ inline size_t arithToArithClassic(const U* in, uint32_t numItems) {
   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}};
@@ -454,9 +1012,8 @@ 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}};
-}
-
-using namespace conv;
+} // namespace conv_bench_detail
+} // namespace folly
 
 #define STRING_TO_TYPE_BENCHMARK(type, name, pass, fail) \
   BENCHMARK(stringTo##name##Classic, n) {                \
@@ -464,6 +1021,12 @@ using namespace conv;
   }                                                      \
   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) \
@@ -472,14 +1035,26 @@ using namespace conv;
   }                                                       \
   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) \