This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [1/2] Add option to disable c++11 std::string small-size
- From: Mikhail Kashkarov <m dot kashkarov at partner dot samsung dot com>
- To: "libstdc++ at gcc dot gnu dot org" <libstdc++ at gcc dot gnu dot org>
- Cc: Vyacheslav Barinov <v dot barinov at samsung dot com>, Ivan Baravy <i dot baravy at samsung dot com>, Jonathan Wakely <jwakely at redhat dot com>, gcc-patches <gcc-patches at gcc dot gnu dot org>
- Date: Fri, 8 Jun 2018 17:55:40 +0300
- Subject: Re: [1/2] Add option to disable c++11 std::string small-size
- Cms-type: 201P
- Dkim-filter: OpenDKIM Filter v2.11.0 mailout2.w1.samsung.com 20180608145548euoutp02f81c854b7fc44d9684dd4cb574f035f5~2NyNBWxuL2814628146euoutp02G
- References: <c8b18d2a-d5c7-e3a2-53be-30b39eadeb49@partner.samsung.com> <CGME20180529065338eucas1p127354210f72c34ce750608240d909a32@eucas1p1.samsung.com> <20180529065338eucas1p127354210f72c34ce750608240d909a32~zCwXQAEvv2929429294eucas1p1O@eucas1p1.samsung.com>
Updated.
On 05/29/2018 09:53 AM, Mikhail Kashkarov wrote:
> Add option to disable c++11 std::string small-sizeoptimization usage.
>
> * include/bits/basic_string.h [_GLIBCXX_DISABLE_STRING_SSO_USAGE]:
> (basic_string::_M_is_local, basic_string::_M_destroy)
> (basic_string::basic_string, basic_string::basic_string(const _Alloc&))
> (basic_string::basic_string(basic_string&&))
> (basic_string::basic_string(basic_string&&, const _Alloc&))
> (basic_string::operator=(const basic_string&))
> (basic_string::operator=(basic_string&&))
> (basic_string::clear()): Disable usage of _M_local_buf if
> _GLIBCXX_DISABLE_STRING_SSO_USAGE is defined.
> * include/bits/basic_string.tcc [_GLIBCXX_DISABLE_STRING_SSO_USAGE]:
> (basic_string::_M_construct, basic_string::reserve)
> (basic_string::_M_replace): Disable usage of _M_local_buf if
> _GLIBCXX_DISABLE_STRING_SSO_USAGE is defined.
> * testsuite/basic_string/allocator/char/copy_assign.cc: Support for
> std::string without SSO.
> * testsuite/basic_string/allocator/wchar_t/copy_assign.cc: Likewise.
> * testsuite/21_strings/basic_string/init-list.cc: Likewise.
> * testsuite/rand/assoc/rand_regression_test.hpp: Likewise.
> * testsuite/rand/priority_queue/rand_regression_test.hpp: Likewise.
>
--
Best regards,
Kashkarov Mikhail
Samsung R&D Institute Russia
From 49c34919fba3000d751ac505b498eb6b21b0f4b3 Mon Sep 17 00:00:00 2001
From: Mikhail Kashkarov <m.kashkarov@partner.samsung.com>
Date: Fri, 8 Jun 2018 12:22:33 +0300
Subject: [PATCH 1/2] Add option to disable c++11 std::basic_string SSO
optimization.
* include/bits/basic_string.h [_GLIBCXX_DISABLE_STRING_SSO_USAGE]:
(basic_string::_M_is_local())
(basic_string::_M_destroy(size_type __size))
(basic_string::basic_string())
(basic_string::basic_string(const _Alloc& __a))
(basic_string::basic_string(basic_string&& __str))
(basic_string::basic_string(basic_string&& __str, const _Alloc& __a))
(basic_string::operator=(const basic_string& __str))
(basic_string::operator=(basic_string&& __str))
(basic_string::clear()): Disable usage of _M_local_buf if
_GLIBCXX_DISABLE_STRING_SSO_USAGE is defined.
* include/bits/basic_string.tcc [_GLIBCXX_DISABLE_STRING_SSO_USAGE]:
(basic_string::_M_construct, basic_string::reserve)
(basic_string::_M_replace): Disable usage of _M_local_buf if
_GLIBCXX_DISABLE_STRING_SSO_USAGE is defined.
* testsuite/basic_string/allocator/char/copy_assign.cc: Support for
std::string without SSO.
* testsuite/basic_string/allocator/wchar_t/copy_assign.cc: Likewise.
* testsuite/21_strings/basic_string/init-list.cc: Likewise.
* testsuite/rand/assoc/rand_regression_test.hpp: Likewise.
* testsuite/rand/priority_queue/rand_regression_test.hpp: Likewise.
---
libstdc++-v3/include/bits/basic_string.h | 104 +++++++++++++++++++--
libstdc++-v3/include/bits/basic_string.tcc | 46 ++++++++-
.../basic_string/allocator/char/copy_assign.cc | 4 +
.../basic_string/allocator/wchar_t/copy_assign.cc | 4 +
.../testsuite/21_strings/basic_string/init-list.cc | 2 +
.../regression/rand/assoc/rand_regression_test.hpp | 5 +
.../rand/priority_queue/rand_regression_test.hpp | 5 +
7 files changed, 156 insertions(+), 14 deletions(-)
diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h
index 5bffa1c..9d971c0 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -208,7 +208,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
bool
_M_is_local() const
- { return _M_data() == _M_local_data(); }
+ {
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ return false;
+#else
+ return _M_data() == _M_local_data();
+#endif
+ }
// Create & Destroy
pointer
@@ -223,7 +229,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
void
_M_destroy(size_type __size) throw()
- { _Alloc_traits::deallocate(_M_get_allocator(), _M_data(), __size + 1); }
+ {
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ if (!_M_allocated_capacity)
+ return;
+#endif
+ _Alloc_traits::deallocate(_M_get_allocator(), _M_data(), __size + 1);
+ }
// _M_construct_aux is used to implement the 21.3.1 para 15 which
// requires special behaviour if _InIterator is an integral type
@@ -420,7 +432,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
basic_string()
_GLIBCXX_NOEXCEPT_IF(is_nothrow_default_constructible<_Alloc>::value)
: _M_dataplus(_M_local_data())
- { _M_set_length(0); }
+ {
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ _M_length(0);
+ _M_capacity(0);
+#else
+ _M_set_length(0);
+#endif
+ }
/**
* @brief Construct an empty string using allocator @a a.
@@ -428,7 +447,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
explicit
basic_string(const _Alloc& __a) _GLIBCXX_NOEXCEPT
: _M_dataplus(_M_local_data(), __a)
- { _M_set_length(0); }
+ {
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ _M_length(0);
+ _M_capacity(0);
+#else
+ _M_set_length(0);
+#endif
+ }
/**
* @brief Construct string with copy of value of @a __str.
@@ -531,12 +557,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
basic_string(basic_string&& __str) noexcept
: _M_dataplus(_M_local_data(), std::move(__str._M_get_allocator()))
{
+#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE
if (__str._M_is_local())
{
traits_type::copy(_M_local_buf, __str._M_local_buf,
_S_local_capacity + 1);
}
else
+#endif
{
_M_data(__str._M_data());
_M_capacity(__str._M_allocated_capacity);
@@ -546,8 +574,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
// basic_stringbuf relies on writing into unallocated capacity so
// we mess up the contents if we put a '\0' in the string.
_M_length(__str.length());
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ __str._M_data(nullptr);
+ __str._M_length(0);
+ __str._M_capacity(0);
+#else
__str._M_data(__str._M_local_data());
__str._M_set_length(0);
+#endif
}
/**
@@ -567,6 +601,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
noexcept(_Alloc_traits::_S_always_equal())
: _M_dataplus(_M_local_data(), __a)
{
+#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE
if (__str._M_is_local())
{
traits_type::copy(_M_local_buf, __str._M_local_buf,
@@ -574,14 +609,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
_M_length(__str.length());
__str._M_set_length(0);
}
- else if (_Alloc_traits::_S_always_equal()
+ else
+#endif
+ if (_Alloc_traits::_S_always_equal()
|| __str.get_allocator() == __a)
{
_M_data(__str._M_data());
_M_length(__str.length());
_M_capacity(__str._M_allocated_capacity);
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ __str._M_data(nullptr);
+ __str._M_length(0);
+ __str._M_capacity(0);
+#else
__str._M_data(__str._M_local_buf);
__str._M_set_length(0);
+#endif
+
}
else
_M_construct(__str.begin(), __str.end());
@@ -661,6 +705,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
{
// Propagating allocator cannot free existing storage so must
// deallocate it before replacing current allocator.
+#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE
if (__str.size() <= _S_local_capacity)
{
_M_destroy(_M_allocated_capacity);
@@ -668,14 +713,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
_M_set_length(0);
}
else
+#endif
{
const auto __len = __str.size();
auto __alloc = __str._M_get_allocator();
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ const auto __new_cap = __len > size_type(_S_local_capacity)
+ ? __len : size_type(_S_local_capacity);
+#else
+ const auto __new_cap = __len;
+#endif
// If this allocation throws there are no effects:
- auto __ptr = _Alloc_traits::allocate(__alloc, __len + 1);
+ auto __ptr = _Alloc_traits::allocate(__alloc, __new_cap + 1);
_M_destroy(_M_allocated_capacity);
_M_data(__ptr);
- _M_capacity(__len);
+ _M_capacity(__new_cap);
_M_set_length(__len);
}
}
@@ -728,8 +780,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
{
// Destroy existing storage before replacing allocator.
_M_destroy(_M_allocated_capacity);
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ _M_length(0);
+ _M_capacity(0);
+#else
_M_data(_M_local_data());
_M_set_length(0);
+#endif
}
// Replace allocator if POCMA is true.
std::__alloc_on_move(_M_get_allocator(), __str._M_get_allocator());
@@ -740,15 +797,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
{
pointer __data = nullptr;
size_type __capacity;
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ size_type __length;
+#endif
if (!_M_is_local())
{
if (_Alloc_traits::_S_always_equal())
{
__data = _M_data();
__capacity = _M_allocated_capacity;
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ __length = _M_string_length;
+#endif
}
- else
+ else {
_M_destroy(_M_allocated_capacity);
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ _M_length(0);
+ _M_capacity(0);
+#endif
+ }
}
_M_data(__str._M_data());
@@ -758,9 +826,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
{
__str._M_data(__data);
__str._M_capacity(__capacity);
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ __str._M_length(__length);
+#endif
}
- else
+ else {
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ __str._M_data(nullptr);
+ __str._M_length(0);
+ __str._M_capacity(0);
+#else
__str._M_data(__str._M_local_buf);
+#endif
+ }
}
else
assign(__str);
@@ -1002,7 +1080,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
*/
void
clear() _GLIBCXX_NOEXCEPT
- { _M_set_length(0); }
+ {
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ _M_allocated_capacity ? _M_set_length(0) : _M_length(0);
+#else
+ _M_set_length(0);
+#endif
+ }
/**
* Returns true if the %string is empty. Equivalent to
diff --git a/libstdc++-v3/include/bits/basic_string.tcc b/libstdc++-v3/include/bits/basic_string.tcc
index be8815c..6b6c7eb 100644
--- a/libstdc++-v3/include/bits/basic_string.tcc
+++ b/libstdc++-v3/include/bits/basic_string.tcc
@@ -137,6 +137,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__capacity > max_size())
std::__throw_length_error(__N("basic_string::_M_create"));
+
// The below implements an exponential growth policy, necessary to
// meet amortized linear time requirements of the library: see
// http://gcc.gnu.org/ml/libstdc++/2001-07/msg00085.html.
@@ -165,7 +166,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
std::input_iterator_tag)
{
size_type __len = 0;
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ size_type __capacity = size_type(0);
+ _M_capacity(0);
+#else
size_type __capacity = size_type(_S_local_capacity);
+#endif
while (__beg != __end && __len < __capacity)
{
@@ -181,6 +187,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
// Allocate more space.
__capacity = __len + 1;
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ if (__capacity < size_type(_S_local_capacity))
+ __capacity = size_type(_S_local_capacity);
+#endif
pointer __another = _M_create(__capacity, __len);
this->_S_copy(__another, _M_data(), __len);
_M_dispose();
@@ -213,11 +223,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
"_M_construct null not valid"));
size_type __dnew = static_cast<size_type>(std::distance(__beg, __end));
+ size_type __new_capacity = __dnew;
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ if (__new_capacity < size_type(_S_local_capacity))
+ __new_capacity = size_type(_S_local_capacity);
+#endif
+#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE
if (__dnew > size_type(_S_local_capacity))
+#endif
{
- _M_data(_M_create(__dnew, size_type(0)));
- _M_capacity(__dnew);
+ _M_data(_M_create(__new_capacity, size_type(0)));
+ _M_capacity(__new_capacity);
}
// Check for out_of_range and length_error exceptions.
@@ -237,10 +254,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
basic_string<_CharT, _Traits, _Alloc>::
_M_construct(size_type __n, _CharT __c)
{
+ size_type __new_capacity = __n;
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ if (__new_capacity < size_type(_S_local_capacity))
+ __new_capacity = size_type(_S_local_capacity);
+#endif
+
+#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE
if (__n > size_type(_S_local_capacity))
+#endif
{
- _M_data(_M_create(__n, size_type(0)));
- _M_capacity(__n);
+ _M_data(_M_create(__new_capacity, size_type(0)));
+ _M_capacity(__new_capacity);
}
if (__n)
@@ -271,7 +296,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__rsize)
this->_S_copy(_M_data(), __str._M_data(), __rsize);
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ _M_allocated_capacity ? _M_set_length(__rsize) : _M_length(__rsize);
+#else
_M_set_length(__rsize);
+#endif
}
}
@@ -287,8 +316,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
const size_type __capacity = capacity();
if (__res != __capacity)
{
+#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE
if (__res > __capacity
|| __res > size_type(_S_local_capacity))
+#endif
{
pointer __tmp = _M_create(__res, __capacity);
this->_S_copy(__tmp, _M_data(), length() + 1);
@@ -296,12 +327,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_data(__tmp);
_M_capacity(__res);
}
+#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE
else if (!_M_is_local())
{
this->_S_copy(_M_local_data(), _M_data(), length() + 1);
_M_destroy(__capacity);
_M_data(_M_local_data());
}
+#endif
}
}
@@ -465,7 +498,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
else
this->_M_mutate(__pos, __len1, __s, __len2);
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ this->_M_allocated_capacity ? this->_M_set_length(__new_size) :
+ this->_M_length(__new_size);
+#else
this->_M_set_length(__new_size);
+#endif
return *this;
}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/copy_assign.cc b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/copy_assign.cc
index 2e4a71e..91a8f88 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/copy_assign.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/copy_assign.cc
@@ -122,7 +122,11 @@ void test03()
VERIFY( v1 == s1 );
VERIFY( v1.get_allocator() == a1 );
+#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE
throw_alloc::set_limit(1); // Allow one more allocation (and no more).
+#else
+ throw_alloc::set_limit(2); // Allow allocations if sso is disabled
+#endif
test_type v3(s1, a1);
// No allocation when allocators are equal and capacity is sufficient:
VERIFY( v1.capacity() >= v3.size() );
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/copy_assign.cc b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/copy_assign.cc
index 5de9c9e..70c1461 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/copy_assign.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/copy_assign.cc
@@ -122,7 +122,11 @@ void test03()
VERIFY( v1 == s1 );
VERIFY( v1.get_allocator() == a1 );
+#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE
throw_alloc::set_limit(1); // Allow one more allocation (and no more).
+#else
+ throw_alloc::set_limit(2); // Allow allocations if sso is disabled
+#endif
test_type v3(s1, a1);
// No allocation when allocators are equal and capacity is sufficient:
VERIFY( v1.capacity() >= v3.size() );
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/init-list.cc b/libstdc++-v3/testsuite/21_strings/basic_string/init-list.cc
index 2cc9cff..b1e0333 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/init-list.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/init-list.cc
@@ -62,7 +62,9 @@ void test01(void)
int main()
{
+#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE
__gnu_test::set_memory_limits();
+#endif
test01();
return 0;
}
diff --git a/libstdc++-v3/testsuite/util/regression/rand/assoc/rand_regression_test.hpp b/libstdc++-v3/testsuite/util/regression/rand/assoc/rand_regression_test.hpp
index 274a70c..c645d19 100644
--- a/libstdc++-v3/testsuite/util/regression/rand/assoc/rand_regression_test.hpp
+++ b/libstdc++-v3/testsuite/util/regression/rand/assoc/rand_regression_test.hpp
@@ -105,7 +105,12 @@ namespace detail
size_t n = iter;
size_t m = keys;
size_t sd = twister_rand_gen::get_time_determined_seed();
+ // Without SSO string can allocate memory when sso-string would not.
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ double tp = 0.0;
+#else
double tp = 0.2;
+#endif
double ip = 0.6;
double ep = 0.2;
double cp = 0.001;
diff --git a/libstdc++-v3/testsuite/util/regression/rand/priority_queue/rand_regression_test.hpp b/libstdc++-v3/testsuite/util/regression/rand/priority_queue/rand_regression_test.hpp
index 62eb19a..ca6e197 100644
--- a/libstdc++-v3/testsuite/util/regression/rand/priority_queue/rand_regression_test.hpp
+++ b/libstdc++-v3/testsuite/util/regression/rand/priority_queue/rand_regression_test.hpp
@@ -104,7 +104,12 @@ namespace detail
size_t n = iter;
size_t m = keys;
size_t sd = twister_rand_gen::get_time_determined_seed();
+ // Without SSO string can allocate memory when sso-string would not.
+#if _GLIBCXX_DISABLE_STRING_SSO_USAGE
+ double tp = 0.0;
+#else
double tp = 0.2;
+#endif
double ip = 0.6;
double dp = 0.1;
double ep = 0.2;
--
2.7.4