Reduce libstdc++-v3 locale::locale() lock contention

Jimmy Guo jguo@yahoo-inc.com
Wed Dec 16 23:24:00 GMT 2009


Hi this is a patch to libstdc++-v3 to reduce locale::locale() lock
contention for applications that only use C locale.  Through lock contention
analysis we found that one of our apps has high contention involving
istringstream and the underlying ios_base locale() construction.  Since we
don't change our default / global locale, one solution is to apply this
patch to our gcc.  Would like your review of this patch, which I think is
still applicable to gcc trunk.

Some timing data on my 8 core (Core2Quad) node running RHEL4:

Using current libstdc++.so:
nthreads = 1: 1725 cycles
nthreads = 2: 6968 cycles
nthreads = 4: 27381 cycles
nthreads = 8: 36594 cycles

Using patched libstdc++.so:
nthreads = 1: 1392 cycles
nthreads = 2: 2746 cycles
nthreads = 4: 7854 cycles
nthreads = 8: 21114 cycles

Test code for the above basically measures clock cycles (rdtsc) around
thread func that does the following:
    for (int i = 0; i < NITERS; ++i) {
        std::ostringstream bufStream;
        bufStream << i;
    }

In the locale::locale() constructor, the patch optimizes away the mutex lock
when _S_global Impl* is still _S_classic.  If it's not, it falls back to the
original behavior of using the mutex to protect access to _S_global and its
reference count.  I've added some inline comments in the patch as well.

I'd appreciate your review and thoughts on how to address this, if
alternatives exist, or if you have considered this already but decided not
to adopt similar patches ... thanks!

- Jimmy Guo

Index: libstdc++-v3/src/locale_init.cc
===================================================================
--- libstdc++-v3/src/locale_init.cc     (revision 155291)
+++ libstdc++-v3/src/locale_init.cc     (working copy)
@@ -208,9 +208,27 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
   locale::locale() throw() : _M_impl(0)
   { 
     _S_initialize();
-    __gnu_cxx::__scoped_lock sentry(get_locale_mutex());
-    _S_global->_M_add_reference();
+
+    // Checked locking to optimize the common case where _S_global
+    // still points to _S_classic (locale::_S_initialize_once()):
+    // - If they are the same, just increment the reference count and
+    //   we are done.  This effectively constructs a C locale object
+    //   identical to the static c_locale.
+    // - Otherwise, _S_global can and may be destroyed due to
+    //   locale::global() call on another thread, in which case we
+    //   fall back to lock protected access to both _S_global and
+    //   its reference count.
     _M_impl = _S_global;
+    if (_M_impl == _S_classic)
+      {
+        _M_impl->_M_add_reference();
+      }
+    else
+      {
+        __gnu_cxx::__scoped_lock sentry(get_locale_mutex());
+        _S_global->_M_add_reference();
+        _M_impl = _S_global;
+      }
   }
 
   locale



More information about the Libstdc++ mailing list