This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: [RFA] Processing locale::_M_names decently fast
- From: Paolo Carlini <pcarlini at suse dot de>
- To: Paolo Carlini <pcarlini at suse dot de>
- Cc: libstdc++ <libstdc++ at gcc dot gnu dot org>
- Date: Sat, 01 May 2004 14:49:28 +0200
- Subject: Re: [RFA] Processing locale::_M_names decently fast
- References: <40922339.3070502@suse.de> <4092CFFD.1090503@roguewave.com> <4092DA89.6050805@suse.de>
Paolo Carlini wrote:
Now, back to work!
Ok, the below is what I have prepared and tested.
In order to make possible dealing easily with changes to the standard
in this area (thanks again Martin!) I chose to represent an unnamed
locale as, simply, _M_names[0] == 0; all the categories the same name
as _M_names[1] == 0. Of course, we are still able to deal, as a slower
fall back, with all _M_names[i] != 0 and equal - this can be produced
by a sequence of locale functions - a "simple" name() is correctly
returned in this case too. Similarly, in the future will be able to
accomodate possible "complex" unnamed locales, characterized by "*"
in some _M_names[i], actual names in others.
I hope the Changelog and the comments are sufficienlty clear: I like,
besides the performance improvements, the resulting nice cleanup and
simplification of many functions!
Some numbers, now (P4-2400, -O2):
locale loc1("en_US");
locale loc2("en_US");
for (long i = 0; i < 10000000; ++i)
if (loc1 != loc2)
abort();
current
-------
3.280u 0.010s 0:03.28 100.3% 0+0k 0+0io 248pf+0w
patched
-------
0.320u 0.000s 0:00.32 100.0% 0+0k 0+0io 247pf+0w
//-------------------------------------------------
locale loc1("en_US");
locale loc3("fr_FR");
for (long i = 0; i < 10000000; ++i)
if (loc1 == loc3)
abort();
current
-------
0.710u 0.000s 0:00.73 97.2% 0+0k 0+0io 248pf+0w
patched
-------
0.220u 0.000s 0:00.22 100.0% 0+0k 0+0io 247pf+0w
//-------------------------------------------------
locale loc1("en_US");
locale loc2("en_US");
for (long i = 0; i < 10000000; ++i)
if (loc1.name() != loc2.name())
abort();
current
-------
9.950u 0.210s 0:10.18 99.8% 0+0k 0+0io 251pf+0w
patched
-------
5.480u 0.000s 0:05.50 99.6% 0+0k 0+0io 250pf+0w
//-------------------------------------------------
I would commit this, say, tomorrow or monday morning, barring
further comments.
Thanks,
Paolo.
///////////////////////
2004-05-02 Paolo Carlini <pcarlini@suse.de>
Optimize locale::_M_impl->_M_names for the most common cases:
!_M_names[0] means unnamed; !_M_names[1] means all the categories
the same name (_M_names[0] && _M_names[1] means that the full set
of _M_names must be processed, the general case).
* include/bits/locale_classes.h (locale::_Impl::_M_check_same_name):
Tweak, saving work when !_M_names[1].
(locale::locale(const locale&, _Facet*): Simplify: now just setting
_M_names[0] = 0 means unnamed.
* src/locale.cc (locale::operator==): Deal first with the common,
easy cases, otherwise fall back to locale::name().
(locale::name()): Tweak, if !_M_names[0] just return "*".
(locale::_Impl::_Impl(const _Impl&, size_t): Tweak, early stop
copying __imp._M_names if !__imp._M_names[0] or !__imp._M_names[1].
* src/locale_init.cc (locale::_Impl::_Impl(size_t)): Tweak.
* src/localename.cc (locale::_Impl::_Impl(const char*, size_t):
Simplify when !std::strchr, just updating _M_names[0]; clean up.
(locale::_Impl::_M_replace_categories): When !_M_names[1] prepare
for the general case (full set of names), then do the usual work;
clean up.
* src/locale.cc (locale::name()): Reserve space in __ret.
* src/locale_init.cc (locale::global(const locale&)): Save
the name in a temporary.
* src/localename.cc (locale::locale(const char*)): Reserve space
in __str.
diff -prN libstdc++-v3-orig/include/bits/locale_classes.h libstdc++-v3/include/bits/locale_classes.h
*** libstdc++-v3-orig/include/bits/locale_classes.h Fri Feb 27 01:49:49 2004
--- libstdc++-v3/include/bits/locale_classes.h Sat May 1 12:56:27 2004
*************** namespace std
*** 534,541 ****
_M_check_same_name()
{
bool __ret = true;
! for (size_t __i = 0; __ret && __i < _S_categories_size - 1; ++__i)
! __ret = std::strcmp(_M_names[__i], _M_names[__i + 1]) == 0;
return __ret;
}
--- 534,543 ----
_M_check_same_name()
{
bool __ret = true;
! if (_M_names[1])
! // We must actually compare all the _M_names: can be all equal!
! for (size_t __i = 0; __ret && __i < _S_categories_size - 1; ++__i)
! __ret = std::strcmp(_M_names[__i], _M_names[__i + 1]) == 0;
return __ret;
}
*************** namespace std
*** 569,598 ****
{
_M_impl = new _Impl(*__other._M_impl, 1);
- char* _M_tmp_names[_S_categories_size];
- size_t __i = 0;
try
! {
! for (; __i < _S_categories_size; ++__i)
! {
! _M_tmp_names[__i] = new char[2];
! std::strcpy(_M_tmp_names[__i], "*");
! }
! _M_impl->_M_install_facet(&_Facet::id, __f);
! }
catch(...)
{
_M_impl->_M_remove_reference();
- for (size_t __j = 0; __j < __i; ++__j)
- delete [] _M_tmp_names[__j];
__throw_exception_again;
}
!
! for (size_t __k = 0; __k < _S_categories_size; ++__k)
! {
! delete [] _M_impl->_M_names[__k];
! _M_impl->_M_names[__k] = _M_tmp_names[__k];
! }
}
} // namespace std
--- 571,585 ----
{
_M_impl = new _Impl(*__other._M_impl, 1);
try
! { _M_impl->_M_install_facet(&_Facet::id, __f); }
catch(...)
{
_M_impl->_M_remove_reference();
__throw_exception_again;
}
! delete [] _M_impl->_M_names[0];
! _M_impl->_M_names[0] = 0; // Unnamed.
}
} // namespace std
diff -prN libstdc++-v3-orig/src/locale.cc libstdc++-v3/src/locale.cc
*** libstdc++-v3-orig/src/locale.cc Thu Apr 29 00:13:24 2004
--- libstdc++-v3/src/locale.cc Sat May 1 13:47:32 2004
*************** namespace std
*** 70,84 ****
bool
locale::operator==(const locale& __rhs) const throw()
{
! bool __ret = true;
if (_M_impl == __rhs._M_impl)
! ;
! else if (!std::strcmp(_M_impl->_M_names[0], "*"))
__ret = false;
else
! for (size_t __i = 0; __ret && __i < _S_categories_size; ++__i)
! __ret = !std::strcmp(_M_impl->_M_names[__i],
! __rhs._M_impl->_M_names[__i]);
return __ret;
}
--- 70,90 ----
bool
locale::operator==(const locale& __rhs) const throw()
{
! // Deal first with the common cases, fast to process: refcopies,
! // unnamed (i.e., !_M_names[0]), "simple" (!_M_names[1] => all the
! // categories same name, i.e., _M_names[0]). Otherwise fall back
! // to the general locale::name().
! bool __ret;
if (_M_impl == __rhs._M_impl)
! __ret = true;
! else if (!_M_impl->_M_names[0] || !__rhs._M_impl->_M_names[0]
! || std::strcmp(_M_impl->_M_names[0],
! __rhs._M_impl->_M_names[0]) != 0)
__ret = false;
+ else if (!_M_impl->_M_names[1] && !__rhs._M_impl->_M_names[1])
+ __ret = true;
else
! __ret = this->name() == __rhs.name();
return __ret;
}
*************** namespace std
*** 95,104 ****
locale::name() const
{
string __ret;
! if (_M_impl->_M_check_same_name())
__ret = _M_impl->_M_names[0];
else
{
__ret += _S_categories[0];
__ret += '=';
__ret += _M_impl->_M_names[0];
--- 101,113 ----
locale::name() const
{
string __ret;
! if (!_M_impl->_M_names[0])
! __ret = '*';
! else if (_M_impl->_M_check_same_name())
__ret = _M_impl->_M_names[0];
else
{
+ __ret.reserve(128);
__ret += _S_categories[0];
__ret += '=';
__ret += _M_impl->_M_names[0];
*************** namespace std
*** 242,253 ****
for (size_t __i = 0; __i < _S_categories_size; ++__i)
_M_names[__i] = 0;
! // Name all the categories.
! for (size_t __i = 0; __i < _S_categories_size; ++__i)
{
! char* __new = new char[std::strlen(__imp._M_names[__i]) + 1];
! std::strcpy(__new, __imp._M_names[__i]);
! _M_names[__i] = __new;
}
}
catch(...)
--- 251,263 ----
for (size_t __i = 0; __i < _S_categories_size; ++__i)
_M_names[__i] = 0;
! // Name the categories.
! for (size_t __i = 0; (__i < _S_categories_size
! && __imp._M_names[__i]); ++__i)
{
! const size_t __len = std::strlen(__imp._M_names[__i]) + 1;
! _M_names[__i] = new char[__len];
! std::memcpy(_M_names[__i], __imp._M_names[__i], __len);
}
}
catch(...)
*************** namespace std
*** 354,360 ****
}
}
-
// locale::id
// Definitions for static const data members of locale::id
_Atomic_word locale::id::_S_refcount; // init'd to 0 by linker
--- 364,369 ----
diff -prN libstdc++-v3-orig/src/locale_init.cc libstdc++-v3/src/locale_init.cc
*** libstdc++-v3-orig/src/locale_init.cc Sun Mar 7 02:32:43 2004
--- libstdc++-v3/src/locale_init.cc Sat May 1 02:53:35 2004
*************** namespace std
*** 114,122 ****
__glibcxx_mutex_lock(__gnu_internal::locale_global_mutex);
_Impl* __old = _S_global;
__other._M_impl->_M_add_reference();
! _S_global = __other._M_impl;
! if (__other.name() != "*")
! setlocale(LC_ALL, __other.name().c_str());
__glibcxx_mutex_unlock(__gnu_internal::locale_global_mutex);
// Reference count sanity check: one reference removed for the
--- 114,123 ----
__glibcxx_mutex_lock(__gnu_internal::locale_global_mutex);
_Impl* __old = _S_global;
__other._M_impl->_M_add_reference();
! _S_global = __other._M_impl;
! const string __other_name = __other.name();
! if (__other_name != "*")
! setlocale(LC_ALL, __other_name.c_str());
__glibcxx_mutex_unlock(__gnu_internal::locale_global_mutex);
// Reference count sanity check: one reference removed for the
*************** namespace std
*** 255,267 ****
for (size_t __i = 0; __i < _M_facets_size; ++__i)
_M_facets[__i] = _M_caches[__i] = 0;
! // Name all the categories.
_M_names = new (&name_vec) char*[_S_categories_size];
! for (size_t __i = 0; __i < _S_categories_size; ++__i)
! {
! _M_names[__i] = new (&name_c[__i]) char[2];
! std::strcpy(_M_names[__i], locale::facet::_S_get_c_name());
! }
// This is needed as presently the C++ version of "C" locales
// != data in the underlying locale model for __timepunct,
--- 256,267 ----
for (size_t __i = 0; __i < _M_facets_size; ++__i)
_M_facets[__i] = _M_caches[__i] = 0;
! // Name the categories.
_M_names = new (&name_vec) char*[_S_categories_size];
! _M_names[0] = new (&name_c[0]) char[2];
! std::memcpy(_M_names[0], locale::facet::_S_get_c_name(), 2);
! for (size_t __i = 1; __i < _S_categories_size; ++__i)
! _M_names[__i] = 0;
// This is needed as presently the C++ version of "C" locales
// != data in the underlying locale model for __timepunct,
diff -prN libstdc++-v3-orig/src/localename.cc libstdc++-v3/src/localename.cc
*** libstdc++-v3-orig/src/localename.cc Tue Jan 27 01:49:03 2004
--- libstdc++-v3/src/localename.cc Sat May 1 13:48:55 2004
***************
*** 1,4 ****
! // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
// Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
--- 1,4 ----
! // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
// Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
*************** namespace std
*** 34,40 ****
{
using namespace __gnu_cxx;
-
locale::locale(const char* __s)
{
if (__s)
--- 34,39 ----
*************** namespace std
*** 95,100 ****
--- 94,100 ----
if (__i < _S_categories_size)
{
string __str;
+ __str.reserve(128);
for (size_t __j = 0; __j < __i; ++__j)
{
__str += _S_categories[__j];
*************** namespace std
*** 199,213 ****
for (size_t __i = 0; __i < _S_categories_size; ++__i)
_M_names[__i] = 0;
! // Name all the categories.
const size_t __len = std::strlen(__s);
if (!std::strchr(__s, ';'))
{
! for (size_t __i = 0; __i < _S_categories_size; ++__i)
! {
! _M_names[__i] = new char[__len + 1];
! std::strcpy(_M_names[__i], __s);
! }
}
else
{
--- 199,210 ----
for (size_t __i = 0; __i < _S_categories_size; ++__i)
_M_names[__i] = 0;
! // Name the categories.
const size_t __len = std::strlen(__s);
if (!std::strchr(__s, ';'))
{
! _M_names[0] = new char[__len + 1];
! std::memcpy(_M_names[0], __s, __len + 1);
}
else
{
*************** namespace std
*** 218,227 ****
const char* __end = std::strchr(__beg, ';');
if (!__end)
__end = __s + __len;
! char* __new = new char[__end - __beg + 1];
! std::memcpy(__new, __beg, __end - __beg);
! __new[__end - __beg] = '\0';
! _M_names[__i] = __new;
}
}
--- 215,223 ----
const char* __end = std::strchr(__beg, ';');
if (!__end)
__end = __s + __len;
! _M_names[__i] = new char[__end - __beg + 1];
! std::memcpy(_M_names[__i], __beg, __end - __beg);
! _M_names[__i][__end - __beg] = '\0';
}
}
*************** namespace std
*** 271,289 ****
locale::_Impl::
_M_replace_categories(const _Impl* __imp, category __cat)
{
! for (size_t __ix = 0; __ix < _S_categories_size; ++__ix)
{
- const category __mask = 1 << __ix;
if (__mask & __cat)
{
// Need to replace entry in _M_facets with other locale's info.
_M_replace_category(__imp, _S_facet_categories[__ix]);
// If both have names, go ahead and mangle.
! if (std::strcmp(_M_names[__ix], "*") != 0
! && std::strcmp(__imp->_M_names[__ix], "*") != 0)
{
! char* __new = new char[std::strlen(__imp->_M_names[__ix]) + 1];
! std::strcpy(__new, __imp->_M_names[__ix]);
delete [] _M_names[__ix];
_M_names[__ix] = __new;
}
--- 267,301 ----
locale::_Impl::
_M_replace_categories(const _Impl* __imp, category __cat)
{
! category __mask = 1;
! const bool __have_names = _M_names[0] && __imp->_M_names[0];
! for (size_t __ix = 0; __ix < _S_categories_size; ++__ix, __mask <<= 1)
{
if (__mask & __cat)
{
// Need to replace entry in _M_facets with other locale's info.
_M_replace_category(__imp, _S_facet_categories[__ix]);
// If both have names, go ahead and mangle.
! if (__have_names)
{
! if (!_M_names[1])
! {
! // A full set of _M_names must be prepared, all identical
! // to _M_names[0] to begin with. Then, below, a few will
! // be replaced by the corresponding __imp->_M_names. I.e.,
! // not a "simple" locale anymore (see locale::operator==).
! const size_t __len = std::strlen(_M_names[0]) + 1;
! for (size_t __i = 1; __i < _S_categories_size; ++__i)
! {
! _M_names[__i] = new char[__len];
! std::memcpy(_M_names[__i], _M_names[0], __len);
! }
! }
! char* __src = __imp->_M_names[__ix] ? __imp->_M_names[__ix]
! : __imp->_M_names[0];
! const size_t __len = std::strlen(__src) + 1;
! char* __new = new char[__len];
! std::memcpy(__new, __src, __len);
delete [] _M_names[__ix];
_M_names[__ix] = __new;
}