[libcxx-commits] [PATCH] D101752: Speedup to_string for integers using zero-copy.

Roman Koshelev via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Thu May 6 22:12:36 PDT 2021


Roman-Koshelev added a comment.

Source

  #include <algorithm>
  #include <vector>
  #include <charconv>
  #include <random>
  
  #include <benchmark/benchmark.h>
  
  template <typename V>
  std::string i_to_stringN(const V v)
  {
      std::string buf;
      buf.resize(buf.capacity());
      const auto res = std::to_chars(buf.data(), buf.data() + buf.size(), v);
      buf.resize(res.ptr - buf.data());
      return buf;
  }
  
  std::string  to_stringN (int val)                { return i_to_stringN(val); }
  std::string  to_stringN (long val)               { return i_to_stringN(val); }
  std::string  to_stringN (long long val)          { return i_to_stringN(val); }
  std::string  to_stringN (unsigned val)           { return i_to_stringN(val); }
  std::string  to_stringN (unsigned long val)      { return i_to_stringN(val); }
  std::string  to_stringN (unsigned long long val) { return i_to_stringN(val); }
  
  template <typename V>
  std::string i_to_stringO(const V v)
  {
      constexpr size_t bufsize = std::numeric_limits<V>::digits10 + 2;
      char buf[bufsize];
      const auto res = std::to_chars(buf, buf + bufsize, v);
      return std::string(buf, res.ptr);
  }
  
  std::string  to_stringO (int val)                { return i_to_stringO(val); }
  std::string  to_stringO (long val)               { return i_to_stringO(val); }
  std::string  to_stringO (long long val)          { return i_to_stringO(val); }
  std::string  to_stringO (unsigned val)           { return i_to_stringO(val); }
  std::string  to_stringO (unsigned long val)      { return i_to_stringO(val); }
  std::string  to_stringO (unsigned long long val) { return i_to_stringO(val); }
  
  	template <unsigned N>
  	struct make_mem
  	{
  		using type = std::conditional_t<
  			N <= sizeof(std::uint8_t), std::uint8_t,
  			std::conditional_t<
  				N <= sizeof(std::uint16_t), std::uint16_t,
  				std::conditional_t<
  					N <= sizeof(std::uint32_t), std::uint32_t, std::uint64_t>>>;
  	};
  
  	template <unsigned N>
  	using make_mem_t = typename make_mem<N>::type;
  
  std::random_device rd;
  std::mt19937 gen(rd());
  
  template<unsigned N, bool IsNew>
  static void to_stringD(benchmark::State& state) {
      using Ty = make_mem_t<N>;
      std::uniform_int_distribution<Ty> distrib(std::numeric_limits<Ty>::min(), std::numeric_limits<Ty>::max());
      std::vector<Ty> vec;
      vec.reserve(128);
      for(int i=0; i<128; ++i) {
          vec.push_back(distrib(gen));
      }
   for (auto _ : state) {
       for(Ty i : vec) {
           if constexpr (IsNew) {
              std::string res = to_stringN(i);
              benchmark::DoNotOptimize(res);
           } else {
               std::string res = to_stringO(i);
              benchmark::DoNotOptimize(res);
           }
       }
    }
  }
  
  static void to_stringNewBench(benchmark::State& state) {
      switch(state.range(0)) {
          case 1: { to_stringD<1, true>(state); return; }
          case 2: { to_stringD<2, true>(state); return; }
          case 3: { to_stringD<3, true>(state); return; }
          case 4: { to_stringD<4, true>(state); return; }
          case 5: { to_stringD<5, true>(state); return; }
          case 6: { to_stringD<6, true>(state); return; }
          case 7: { to_stringD<7, true>(state); return; }
          case 8: { to_stringD<8, true>(state); return; }
          case 9: { to_stringD<9, true>(state); return; }
          case 10: { to_stringD<10, true>(state); return; }
          case 11: { to_stringD<11, true>(state); return; }
          case 12: { to_stringD<12, true>(state); return; }
          case 13: { to_stringD<13, true>(state); return; }
          case 14: { to_stringD<14, true>(state); return; }
          case 15: { to_stringD<15, true>(state); return; }
          case 16: { to_stringD<16, true>(state); return; }
  
          default: assert(false);
      }
      
  }
  
  BENCHMARK(to_stringNewBench)->DenseRange(1, 16);
  
  static void to_stringOldBench(benchmark::State& state) {
      switch(state.range(0)) {
          case 1: { to_stringD<1, false>(state); return; }
          case 2: { to_stringD<2, false>(state); return; }
          case 3: { to_stringD<3, false>(state); return; }
          case 4: { to_stringD<4, false>(state); return; }
          case 5: { to_stringD<5, false>(state); return; }
          case 6: { to_stringD<6, false>(state); return; }
          case 7: { to_stringD<7, false>(state); return; }
          case 8: { to_stringD<8, false>(state); return; }
          case 9: { to_stringD<9, false>(state); return; }
          case 10: { to_stringD<10, false>(state); return; }
          case 11: { to_stringD<11, false>(state); return; }
          case 12: { to_stringD<12, false>(state); return; }
          case 13: { to_stringD<13, false>(state); return; }
          case 14: { to_stringD<14, false>(state); return; }
          case 15: { to_stringD<15, false>(state); return; }
          case 16: { to_stringD<16, false>(state); return; }
          default: assert(false);
      } 
  }
  
  BENCHMARK(to_stringOldBench)->DenseRange(1, 16);
  
  BENCHMARK_MAIN();


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D101752/new/

https://reviews.llvm.org/D101752



More information about the libcxx-commits mailing list