[PATCH] Optimize __convert_from_v when locale is already set

Brad Spencer spencer@infointeractive.com
Tue Oct 8 14:33:00 GMT 2002


While debugging recently, I noticed that every time __convert_from_v
is called, there are expensive calls to malloc, free, strlen, strcpy,
and two possibly unnecessary extra calls to setlocale.  I've added a
cheap check to see if the locale is already "C" before we get out the
hammers.  I haven't address the exception safety issues raised
earlier.

I used a simple test to see if it is actually faster:

#include <iostream>

using std::cout;

int
main()
{
  const int x = 12345;

  for(unsigned int i = 0; i < 1000000; ++i) {
    cout << x;
  }

  return 0;
}

$ locale
LANG=C
LC_CTYPE="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_PAPER="C"
LC_NAME="C"
LC_ADDRESS="C"
LC_TELEPHONE="C"
LC_MEASUREMENT="C"
LC_IDENTIFICATION="C"
LC_ALL=

$ test-gcc/i686-pc-linux-gnu/bin/g++ -Wall -g -O6 -o loc main.cc
$ time ./loc >/dev/null

real    0m3.066s
user    0m3.070s
sys     0m0.000s

$ g++ -Wall -g -O6 -o loc-stock main.cc
$ time ./loc-stock >/dev/null

real    0m3.416s
user    0m3.410s
sys     0m0.000s

This seems to be harmless... Is it not?  I couldn't seem to set my
locale (inside the application) no matter what I tried, so I haven't 
tested opposite case to see how much it slows down (if it is at all
noticable). 

I'm also curious as to whether the entire locale needs to be changed.
I take it that the character set is what is preventing just LC_NUMERIC
from being modified?  Or am I just naive? :)

Patch attached.
        
-- 
------------------------------------------------------------------
Brad Spencer - spencer@infointeractive.com - "It's quite nice..."
Systems Architect | InfoInterActive Corp. | A Canadian AOL Company
-------------- next part --------------
ChangeLog
        
2002-10-08    <spencer@infointeractive.com>

	* include/bits/locale_facets.tcc (__convert_from_v): Avoid
	expensive operations when C locale is already set.
        
*** ../../../../reference_gcc/gcc-3.2/libstdc++-v3/include/bits/locale_facets.tcc	Tue Oct  8 17:48:11 2002
--- locale_facets.tcc	Tue Oct  8 17:53:41 2002
*************** namespace std
*** 1977,1992 ****
      {
        int __ret;
        char* __old = setlocale(LC_ALL, NULL);
!       char* __sav = static_cast<char*>(malloc(strlen(__old) + 1));
!       if (__sav)
!         strcpy(__sav, __old);
!       setlocale(LC_ALL, "C");
        if (__prec >= 0)
          __ret = snprintf(__out, __size, __fmt, __prec, __v);
        else
          __ret = snprintf(__out, __size, __fmt, __v);
!       setlocale(LC_ALL, __sav);
!       free(__sav);
        return __ret;
      }
  #else
--- 1977,2007 ----
      {
        int __ret;
        char* __old = setlocale(LC_ALL, NULL);
! 
!       // Only do all this expensive malloc/free, string copy and locale
!       // setting if the locale is not already what we want.
!       char* __sav;
!       if (!(__old[0] == 'C' && __old[1] == '\0'))
!         {
!           __sav = static_cast<char*>(malloc(strlen(__old) + 1));
!           if (__sav)
!             strcpy(__sav, __old);
!           setlocale(LC_ALL, "C");
!         }
!       else
!         __sav = 0;
! 
        if (__prec >= 0)
          __ret = snprintf(__out, __size, __fmt, __prec, __v);
        else
          __ret = snprintf(__out, __size, __fmt, __v);
! 
!       // Do we need to clean up?
!       if(__sav)
!         {        
!           setlocale(LC_ALL, __sav);
!           free(__sav);
!         }
        return __ret;
      }
  #else
*************** namespace std
*** 1997,2012 ****
      {
        int __ret;
        char* __old = setlocale(LC_ALL, NULL);
!       char* __sav = static_cast<char*>(malloc(strlen(__old) + 1));
!       if (__sav)
!         strcpy(__sav, __old);
!       setlocale(LC_ALL, "C");
        if (__prec >= 0)
          __ret = sprintf(__out, __fmt, __prec, __v);
        else
          __ret = sprintf(__out, __fmt, __v);
!       setlocale(LC_ALL, __sav);
!       free(__sav);
        return __ret;
      }
  #endif
--- 2012,2042 ----
      {
        int __ret;
        char* __old = setlocale(LC_ALL, NULL);
! 
!       // Only do all this expensive malloc/free, string copy and locale
!       // setting if the locale is not already what we want.
!       char* __sav;
!       if (!(__old[0] == 'C' && __old[1] == '\0'))
!         {
!           __sav = static_cast<char*>(malloc(strlen(__old) + 1));
!           if (__sav)
!             strcpy(__sav, __old);
!           setlocale(LC_ALL, "C");
!         }
!       else
!         __sav = 0;
! 
        if (__prec >= 0)
          __ret = sprintf(__out, __fmt, __prec, __v);
        else
          __ret = sprintf(__out, __fmt, __v);
! 
!       // Do we need to clean up?
!       if(__sav)
!         {        
!           setlocale(LC_ALL, __sav);
!           free(__sav);
!         }
        return __ret;
      }
  #endif


More information about the Libstdc++ mailing list