[libcxx-commits] [PATCH] D59178: Speedup to_string and to_wstring for integers using stack buffer and SSO
Afanasyev Ivan via Phabricator via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Mar 9 11:27:58 PST 2019
ivafanas added a comment.
Code correctness was checked via
make llvm-check
Please, let me know if this command doesn't do what is expected according to documentation (I'm newby in clang project).
Performance tests:
http://quick-bench.com/wOBLE4yDNQp0x7RGg7ex32atgQY
In the case of quick-bench cache expired, the testing code is:
#include <string>
#include <type_traits>
namespace ref
{
template<typename S, typename P, typename V >
inline
S
as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a)
{
typedef typename S::size_type size_type;
size_type available = s.size();
while (true)
{
int status = sprintf_like(&s[0], available + 1, fmt, a);
if ( status >= 0 )
{
size_type used = static_cast<size_type>(status);
if ( used <= available )
{
s.resize( used );
break;
}
available = used; // Assume this is advice of how much space we need.
}
else
available = available * 2 + 1;
s.resize(available);
}
return s;
}
template <class S, class V, bool = std::is_floating_point<V>::value>
struct initial_string;
template <class V, bool b>
struct initial_string<std::string, V, b>
{
std::string
operator()() const
{
std::string s;
s.resize(s.capacity());
return s;
}
};
template <class V>
struct initial_string<std::wstring, V, false>
{
std::wstring
operator()() const
{
const size_t n = (std::numeric_limits<unsigned long long>::digits / 3)
+ ((std::numeric_limits<unsigned long long>::digits % 3) != 0)
+ 1;
std::wstring s(n, wchar_t());
s.resize(s.capacity());
return s;
}
};
template <class V>
struct initial_string<std::wstring, V, true>
{
std::wstring
operator()() const
{
std::wstring s(20, wchar_t());
s.resize(s.capacity());
return s;
}
};
typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...);
inline
wide_printf
get_swprintf()
{
#ifndef _LIBCPP_MSVCRT
return swprintf;
#else
return static_cast<int (__cdecl*)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...)>(_snwprintf);
#endif
}
std::string __attribute__ ((noinline)) to_string(int val)
{
return as_string(snprintf, initial_string<std::string, int>()(), "%d", val);
}
std::string __attribute__ ((noinline)) to_string(unsigned val)
{
return as_string(snprintf, initial_string<std::string, unsigned>()(), "%u", val);
}
std::string __attribute__ ((noinline)) to_string(long val)
{
return as_string(snprintf, initial_string<std::string, long>()(), "%ld", val);
}
std::string __attribute__ ((noinline)) to_string(unsigned long val)
{
return as_string(snprintf, initial_string<std::string, unsigned long>()(), "%lu", val);
}
std::string __attribute__ ((noinline)) to_string(long long val)
{
return as_string(snprintf, initial_string<std::string, long long>()(), "%lld", val);
}
std::string __attribute__ ((noinline)) to_string(unsigned long long val)
{
return as_string(snprintf, initial_string<std::string, unsigned long long>()(), "%llu", val);
}
std::wstring __attribute__ ((noinline)) to_wstring(int val)
{
return as_string(get_swprintf(), initial_string<std::wstring, int>()(), L"%d", val);
}
std::wstring __attribute__ ((noinline)) to_wstring(unsigned val)
{
return as_string(get_swprintf(), initial_string<std::wstring, unsigned>()(), L"%u", val);
}
std::wstring __attribute__ ((noinline)) to_wstring(long val)
{
return as_string(get_swprintf(), initial_string<std::wstring, long>()(), L"%ld", val);
}
std::wstring __attribute__ ((noinline)) to_wstring(unsigned long val)
{
return as_string(get_swprintf(), initial_string<std::wstring, unsigned long>()(), L"%lu", val);
}
std::wstring __attribute__ ((noinline)) to_wstring(long long val)
{
return as_string(get_swprintf(), initial_string<std::wstring, long long>()(), L"%lld", val);
}
std::wstring __attribute__ ((noinline)) to_wstring(unsigned long long val)
{
return as_string(get_swprintf(), initial_string<std::wstring, unsigned long long>()(), L"%llu", val);
}
} // ref
///
///
///
namespace tgt
{
template<typename S, typename P, typename V>
inline S as_string(P sprintf_like, const typename S::value_type* fmt, V a)
{
constexpr size_t size = 4 * sizeof(V) + 1; // +1 for null char added by swprintf
typename S::value_type tmp[size] = {};
const int len = sprintf_like(tmp, size, fmt, a);
return S(tmp, tmp + len);
}
typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...);
inline
wide_printf
get_swprintf()
{
#ifndef _LIBCPP_MSVCRT
return swprintf;
#else
return static_cast<int (__cdecl*)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...)>(_snwprintf);
#endif
}
std::string __attribute__ ((noinline)) to_string(int val)
{
return as_string<std::string>(snprintf, "%d", val);
}
std::string __attribute__ ((noinline)) to_string(unsigned val)
{
return as_string<std::string>(snprintf, "%u", val);
}
std::string __attribute__ ((noinline)) to_string(long val)
{
return as_string<std::string>(snprintf, "%ld", val);
}
std::string __attribute__ ((noinline)) to_string(unsigned long val)
{
return as_string<std::string>(snprintf, "%lu", val);
}
std::string __attribute__ ((noinline)) to_string(long long val)
{
return as_string<std::string>(snprintf, "%lld", val);
}
std::string __attribute__ ((noinline)) to_string(unsigned long long val)
{
return as_string<std::string>(snprintf, "%llu", val);
}
std::wstring __attribute__ ((noinline)) to_wstring(int val)
{
return as_string<std::wstring>(get_swprintf(), L"%d", val);
}
std::wstring __attribute__ ((noinline)) to_wstring(unsigned val)
{
return as_string<std::wstring>(get_swprintf(), L"%u", val);
}
std::wstring __attribute__ ((noinline)) to_wstring(long val)
{
return as_string<std::wstring>(get_swprintf(), L"%ld", val);
}
std::wstring __attribute__ ((noinline)) to_wstring(unsigned long val)
{
return as_string<std::wstring>(get_swprintf(), L"%lu", val);
}
std::wstring __attribute__ ((noinline)) to_wstring(long long val)
{
return as_string<std::wstring>(get_swprintf(), L"%lld", val);
}
std::wstring __attribute__ ((noinline)) to_wstring(unsigned long long val)
{
return as_string<std::wstring>(get_swprintf(), L"%llu", val);
}
} // tgt
const unsigned long long one = 1;
const unsigned long long ullmax = std::numeric_limits<unsigned long long>::max();
static void to_string_ref_1(benchmark::State& state) {
for (auto _ : state) {
const auto x = ref::to_string(one);
benchmark::DoNotOptimize(x);
}
}
BENCHMARK(to_string_ref_1);
static void to_string_tgt_1(benchmark::State& state) {
for (auto _ : state) {
const auto x = tgt::to_string(one);
benchmark::DoNotOptimize(x);
}
}
BENCHMARK(to_string_tgt_1);
static void to_string_ref_max(benchmark::State& state) {
for (auto _ : state) {
const auto x = ref::to_string(ullmax);
benchmark::DoNotOptimize(x);
}
}
BENCHMARK(to_string_ref_max);
static void to_string_tgt_max(benchmark::State& state) {
for (auto _ : state) {
const auto x = tgt::to_string(ullmax);
benchmark::DoNotOptimize(x);
}
}
BENCHMARK(to_string_tgt_max);
static void to_wstring_ref_1(benchmark::State& state) {
for (auto _ : state) {
const auto x = ref::to_wstring(one);
benchmark::DoNotOptimize(x);
}
}
BENCHMARK(to_wstring_ref_1);
static void to_wstring_tgt_1(benchmark::State& state) {
for (auto _ : state) {
const auto x = tgt::to_wstring(one);
benchmark::DoNotOptimize(x);
}
}
BENCHMARK(to_wstring_tgt_1);
static void to_wstring_ref_max(benchmark::State& state) {
for (auto _ : state) {
const auto x = ref::to_wstring(ullmax);
benchmark::DoNotOptimize(x);
}
}
BENCHMARK(to_wstring_ref_max);
static void to_wstring_tgt_max(benchmark::State& state) {
for (auto _ : state) {
const auto x = tgt::to_wstring(ullmax);
benchmark::DoNotOptimize(x);
}
}
BENCHMARK(to_wstring_tgt_max);
Repository:
rCXX libc++
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D59178/new/
https://reviews.llvm.org/D59178
More information about the libcxx-commits
mailing list