In !_GLIBCXX_USE_CXX11_ABI implementation, string::clear() calls
_M_mutate(), which could allocate memory as we do COW. This hurts
performance when string::clear() is on the hot path.

This patch improves it by using _S_empty_rep directly when
_GLIBCXX_FULLY_DYNAMIC_STRING is not enabled. And Linux distro like
Fedora doesn't enable this, this is why we caught it.

The copy-and-clear test shows it improves by 50%.

Ran all testsuites on Linux-x64.

2016-09-13  Cong Wang  <xiyou.wangc...@gmail.com>

    PR libstdc++/77582
    * libstdc++-v3/include/bits/basic_string.h: Change inline to a declaration.
    * libstdc++-v3/include/bits/basic_string.tcc: Inline the
implementation based on _M_mutate, and use _S_empty_rep when possible.
    * libstdc++-v3/testsuite/performance/21_strings/copy_and_clear.cc: New.
diff --git a/libstdc++-v3/include/bits/basic_string.h 
b/libstdc++-v3/include/bits/basic_string.h
index e823f13..94d1df2 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -3686,8 +3686,7 @@ _GLIBCXX_END_NAMESPACE_CXX11
        */
       // PR 56166: this should not throw.
       void
-      clear()
-      { _M_mutate(0, this->size(), 0); }
+      clear();
 
       /**
        *  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 0080d2b..935932e 100644
--- a/libstdc++-v3/include/bits/basic_string.tcc
+++ b/libstdc++-v3/include/bits/basic_string.tcc
@@ -966,6 +966,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _CharT, typename _Traits, typename _Alloc>
     void
     basic_string<_CharT, _Traits, _Alloc>::
+    clear()
+    {
+      if (_M_rep()->_M_is_shared())
+        {
+          const allocator_type __a = get_allocator();
+          _Rep* __r;
+
+#if _GLIBCXX_FULLY_DYNAMIC_STRING == 0
+         __r = &_S_empty_rep();
+#else
+         // Must reallocate.
+         __r = _Rep::_S_create(0, this->capacity(), __a);
+#endif
+         _M_rep()->_M_dispose(__a);
+         _M_data(__r->_M_refdata());
+        }
+      _M_rep()->_M_set_length_and_sharable(0);
+    }
+
+  template<typename _CharT, typename _Traits, typename _Alloc>
+    void
+    basic_string<_CharT, _Traits, _Alloc>::
     swap(basic_string& __s)
     {
       if (_M_rep()->_M_is_leaked())
diff --git a/libstdc++-v3/testsuite/performance/21_strings/copy_and_clear.cc 
b/libstdc++-v3/testsuite/performance/21_strings/copy_and_clear.cc
new file mode 100644
index 0000000..708f053
--- /dev/null
+++ b/libstdc++-v3/testsuite/performance/21_strings/copy_and_clear.cc
@@ -0,0 +1,49 @@
+// Copyright (C) 2006-2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+
+#include <string>
+#include <testsuite_performance.h>
+
+void benchmark(long len)
+{
+  using namespace std;
+  using namespace __gnu_test;
+
+  time_counter time;
+  resource_counter resource;
+
+  start_counters(time, resource);
+  for (long i = 0; i < len; ++i)
+    {
+      string ss1("1");
+      string ss2(ss1);
+      ss1.clear();
+    }
+  stop_counters(time, resource);
+
+  report_performance(__FILE__, "", time, resource);
+  clear_counters(time, resource);
+}
+
+int main()
+{
+  benchmark(1000000);
+  benchmark(10000000);
+  benchmark(100000000);
+  return 0;
+}

Reply via email to