This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch] IO performance improvement


This is the first patch to improve the IO performance issues in
libstdc++/8761.  I've added Nathan Myers' format cache back in, slightly
modified, and used it to bypass locale copy constructors and destructors.
I'll be using it more in other spots.

This change brings the runtime of the 8761 testcase from 25 seconds on
my machine to about 21 seconds.

I suspect there are be issues with the patch (i.e., formatting, exporting
globals, etc).  Be gentle :-)

I believe these changes will also have an effect on libstdc++/7076.

Jerry Quinn


2003-01-08  Jerry Quinn  <jlquinn@optonline.net>

        * include/bits/locale_facets.h (_Format_cache<_CharT>):  New class.
	(_Format_cache<char>, _Format_cache<wchar_t>): New specializations.
	* include/bits/locale_facets.tcc (num_put::_M_widen_int):
	Remove __loc.  Fetch ctype facet from cache.  Get grouping and
	thousands_sep info from cache.
	(_Format_cache<_CharT>::_Format_cache): New.
	(_Format_cache<_CharT>::~_Format_cache): New.
	(_Format_cache<_CharT>::_M_populate): New.
	(_Format_cache<_CharT>::_S_callback): New.
	(_Format_cache<_CharT>::_S_get): New.
	(_Format_cache<char>::_Format_cache): New specialization.
	(_Format_cache<wchar_t>::_Format_cache): New specialization.
	* src/locale-inst.cc (_Format_cache<char>, _Format_cache<_char_t>):
	New.
	* src/localenames.cc (_Format_cache<char>::_Format_cache,
	_Format_cache<wchar_t>::_Format_cache): New.
	

diff -r -u libstdc++.orig/include/bits/locale_facets.h libstdc++-v3/include/bits/locale_facets.h
--- libstdc++.orig/include/bits/locale_facets.h	Mon Jan  6 22:54:07 2003
+++ libstdc++-v3/include/bits/locale_facets.h	Wed Jan  8 11:03:07 2003
@@ -1805,6 +1805,131 @@
     inline _CharT 
     tolower(_CharT __c, const locale& __loc)
     { return use_facet<ctype<_CharT> >(__loc).tolower(__c); }
+
+
+  // Cache for formatting data from several facets.
+
+  // _Format_cache holds the information extracted from the numpunct<>
+  // and moneypunct<> facets in a form optimized for parsing and
+  // formatting.  It is stored via a void* pointer in the pword()
+  // array of an iosbase object passed to the _get and _put facets.
+  // pword(0) is reserved for the cache.
+
+  // Its intent is to avoid the cost of creating a locale object and
+  // calling the virtual functions in locale facets.
+  template<typename _CharT>
+    class _Format_cache
+    {
+      // Types:
+      typedef _CharT                    char_type;
+      typedef char_traits<_CharT>       traits_type;
+      typedef basic_string<_CharT>	string_type;
+
+      // Forward decls and Friends:
+      friend class locale;
+      template<typename _Char, typename _InIter>
+        friend class _Numeric_get;
+      friend class num_get<_CharT>;
+      friend class time_get<_CharT>;
+      friend class money_get<_CharT>;
+      friend class num_put<_CharT>;
+      friend class time_put<_CharT>;
+      friend class money_put<_CharT>;
+
+    public: 
+      // Data Members:
+
+      // ios_base::pword() reserved cell
+      static int                _S_pword_ix;
+
+      // True iff data members are consistent with the current locale,
+      // i.e. imbue sets this to false.
+      bool                      _M_valid;
+
+      
+      // A list of valid numeric literals: for the standard "C" locale, this
+      // is "-+xX0123456789abcdef0123456789ABCDEF".  This array contains the
+      // chars after having been passed through the current locale's
+      // ctype<_CharT>.widen().
+      // 
+
+      // NB: code depends on the order of definitions of the names
+      // these are indices into _M_numeric_literals, below.
+      // This string is formatted for putting, not getting. (output, not input)
+      enum 
+      {  
+        _S_minus, 
+        _S_plus, 
+        _S_x, 
+        _S_X, 
+        _S_digits,
+        _S_digits_end = _S_digits + 16,
+        _S_udigits = _S_digits_end,  
+        _S_udigits_end = _S_udigits + 16,
+        _S_ee = _S_digits + 14, // For scientific notation, 'e'
+        _S_Ee = _S_udigits + 14 // For scientific notation, 'E'
+      };
+
+      _CharT                    _M_literals[_S_udigits_end];
+
+     
+      // The sign used to separate decimal values: for standard US
+      // locales, this would usually be: "."
+      // Abstracted from numpunct::decimal_point().
+      _CharT                    _M_decimal_point;
+
+      // The sign used to separate groups of digits into smaller
+      // strings that the eye can parse with less difficulty: for
+      // standard US locales, this would usually be: ","
+      // Abstracted from numpunct::thousands_sep().
+      _CharT                    _M_thousands_sep;
+      
+      // However the US's "false" and "true" are translated.
+      // From numpunct::truename() and numpunct::falsename(), respectively.
+      string_type 		_M_truename;
+      string_type 		_M_falsename;
+
+      // If we are checking groupings. This should be equivalent to 
+      // numpunct::groupings().size() != 0
+      bool                      _M_use_grouping;
+
+      // If we are using numpunct's groupings, this is the current grouping
+      // string in effect (from numpunct::grouping()).
+      string                    _M_grouping;
+
+      // Hangs on to the locale's ctype facet.  Permits avoiding some overhead
+      // in creating and destroying local instances of locale.
+      const ctype<_CharT>*	_M_ctype;
+
+
+      _Format_cache();
+
+      ~_Format_cache();
+
+      // Given a member of the ios heirarchy as an argument, extract
+      // out all the current formatting information into a
+      // _Format_cache object and return a pointer to it.
+      static _Format_cache<_CharT>*
+      _S_get(ios_base& __ios);
+
+    private:
+      void 
+      _M_populate (ios_base&);
+
+      // Used to update the cache when ios_base::imbue(),basic_ios::copyfmt(),
+      // or ios_base::~ios_base() are called.
+      static void
+      _S_callback(ios_base::event __event, ios_base& __ios, int __ix) throw();
+
+    };
+
+  template<> _Format_cache<char>::_Format_cache();
+#ifdef _G_USE_WCHAR_T
+  template<> _Format_cache<wchar_t>::_Format_cache();
+#endif
+
+  
+
 } // namespace std
 
 #endif
diff -r -u libstdc++.orig/include/bits/locale_facets.tcc libstdc++-v3/include/bits/locale_facets.tcc
--- libstdc++.orig/include/bits/locale_facets.tcc	Mon Jan  6 22:54:07 2003
+++ libstdc++-v3/include/bits/locale_facets.tcc	Wed Jan  8 11:28:09 2003
@@ -784,22 +784,24 @@
     {
       // [22.2.2.2.2] Stage 2, convert to char_type, using correct
       // numpunct.decimal_point() values for '.' and adding grouping.
-      const locale __loc = __io.getloc();
-      const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
       _CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) 
 							   * __len));
       // Grouping can add (almost) as many separators as the number of
       // digits, but no more.
       _CharT* __ws2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) 
 							    * __len * 2));
-      __ctype.widen(__cs, __cs + __len, __ws);
+
+      _Format_cache<_CharT>* __fc = _Format_cache<_CharT>::_S_get(__io);
+
+      __fc->_M_ctype->widen(__cs, __cs + __len, __ws);
+
+      
 
       // Add grouping, if necessary. 
-      const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__loc);
-      const string __grouping = __np.grouping();
-      const ios_base::fmtflags __basefield = __io.flags() & ios_base::basefield;
-      if (__grouping.size())
+      if (__fc->_M_use_grouping)
 	{
+	  const ios_base::fmtflags __basefield = __io.flags() & ios_base::basefield;
+
 	  // By itself __add_grouping cannot deal correctly with __ws when
 	  // ios::showbase is set and ios_base::oct || ios_base::hex.
 	  // Therefore we take care "by hand" of the initial 0, 0x or 0X.
@@ -819,9 +821,9 @@
 		*(__ws2 + 1) = *(__ws + 1);
 	      }
 	  _CharT* __p;
-	  __p = __add_grouping(__ws2 + __off, __np.thousands_sep(), 
-			       __grouping.c_str(),
-			       __grouping.c_str() + __grouping.size(),
+	  __p = __add_grouping(__ws2 + __off, __fc->_M_thousands_sep, 
+			       __fc->_M_grouping.c_str(),
+			       __fc->_M_grouping.c_str() + __fc->_M_grouping.size(),
 			       __ws + __off, __ws + __len);
 	  __len = __p - __ws2;
 	  // Switch strings.
@@ -2392,6 +2394,92 @@
     bool
     has_facet<messages<wchar_t> >(const locale&);
 #endif
+
+  template<typename _CharT>
+    _Format_cache<_CharT>::_Format_cache()
+    : _M_valid(false), _M_use_grouping(false)
+    { }
+
+  template<>
+    _Format_cache<char>::_Format_cache();
+ 
+  template<>
+    _Format_cache<wchar_t>::_Format_cache();
+
+  template<typename _CharT>
+    _Format_cache<_CharT>::~_Format_cache()
+    { }
+
+  template<typename _CharT>
+    void
+    _Format_cache<_CharT>::_M_populate(ios_base& __io)
+    {
+      static const char _S_numeric_literals[] = "-+xX0123456789abcdef0123456789ABCDEF";
+      static const int _S_literal_count = sizeof(_S_numeric_literals) - 1;
+
+      locale __loc = __io.getloc();
+      numpunct<_CharT> const& __np = use_facet<numpunct<_CharT> >(__loc);
+      _M_falsename = __np.falsename();
+      _M_truename = __np.truename();
+
+      ctype<_CharT> const& __ct = use_facet< ctype<_CharT> >(__loc);
+      __ct.widen(_S_numeric_literals, 
+                 _S_numeric_literals + _S_literal_count, _M_literals);
+      _M_thousands_sep = __np.thousands_sep();
+      _M_decimal_point = __np.decimal_point();
+      _M_grouping = __np.grouping();
+      _M_use_grouping = _M_grouping.size() != 0 && _M_grouping.data()[0] != 0;
+      _M_valid = true;
+      _M_ctype = &__ct;
+    }
+
+  // This function is always called via a pointer installed in
+  // an ios_base by ios_base::register_callback.
+  template<typename _CharT>
+    void
+    _Format_cache<_CharT>::_S_callback(ios_base::event __ev,
+                                       ios_base& __ios, int __ix) throw()
+    {
+      void*& __p = __ios.pword(__ix);
+      switch (__ev)
+	{
+	case ios_base::erase_event:
+	  delete static_cast<_Format_cache<_CharT>*> (__p); __p = 0;   
+	  break;
+	case ios_base::copyfmt_event:
+	  // if just stored zero, the callback would get registered again
+	  try
+	    { 
+	      __p = new _Format_cache<_CharT>; 
+	    } 
+	  catch(...)
+	    { }      
+	  break;
+	case ios_base::imbue_event:
+	  static_cast<_Format_cache<_CharT>*>(__p)->_M_valid = false; 
+	  break;
+	}
+    }
+
+  template<typename _CharT>
+    _Format_cache<_CharT>*
+    _Format_cache<_CharT>::_S_get(ios_base& __ios)
+    {
+      const int format_cache_slot = 0; // Does this belong in ios_base?
+      void*& __p = __ios.pword(format_cache_slot);
+
+      if (__p == 0)  // XXX MT?  maybe sentry takes care of it
+	{
+	  auto_ptr<_Format_cache<_CharT> > __ap(new _Format_cache<_CharT>);
+	  __ios.register_callback (&_Format_cache<_CharT>::_S_callback,
+				   format_cache_slot);
+	  __p = __ap.release();
+	}
+      _Format_cache<_CharT>* __ncp = static_cast<_Format_cache<_CharT>*>(__p);
+      if (!__ncp->_M_valid) __ncp->_M_populate(__ios);
+      return __ncp;
+    }
+
 } // namespace std
 
 #endif
diff -r -u libstdc++.orig/src/locale-inst.cc libstdc++-v3/src/locale-inst.cc
--- libstdc++.orig/src/locale-inst.cc	Mon Jan  6 22:54:07 2003
+++ libstdc++-v3/src/locale-inst.cc	Tue Jan  7 00:21:50 2003
@@ -46,6 +46,7 @@
   template class moneypunct_byname<char, true>;
   template class money_get<char, istreambuf_iterator<char> >;
   template class money_put<char, ostreambuf_iterator<char> >;
+  template class _Format_cache<char>;
 
 #ifdef _GLIBCPP_USE_WCHAR_T
   template class moneypunct<wchar_t, false>;
@@ -54,6 +55,7 @@
   template class moneypunct_byname<wchar_t, true>;
   template class money_get<wchar_t, istreambuf_iterator<wchar_t> >;
   template class money_put<wchar_t, ostreambuf_iterator<wchar_t> >;
+  template class _Format_cache<wchar_t>;
 #endif
 
   // numpunct, numpunct_byname, num_get, and num_put
diff -r -u libstdc++.orig/src/localename.cc libstdc++-v3/src/localename.cc
--- libstdc++.orig/src/localename.cc	Mon Jan  6 22:54:07 2003
+++ libstdc++-v3/src/localename.cc	Wed Jan  8 10:17:30 2003
@@ -350,4 +350,30 @@
 	  }
       }
   }
+
+  template<>
+    _Format_cache<char>::_Format_cache()
+    : _M_valid(true), _M_decimal_point('.'), _M_thousands_sep(','),
+      _M_truename("true"), _M_falsename("false"), _M_use_grouping(false),
+      _M_ctype(&ctype_c)
+    {
+      static const char _S_numeric_literals[] = "-+xX0123456789abcdef0123456789ABCDEF";
+      static const int _S_literal_count = sizeof(_S_numeric_literals) - 1;
+
+      memcpy(_M_literals, _S_numeric_literals, _S_literal_count);
+    }
+ 
+#ifdef  _GLIBCPP_USE_WCHAR_T
+  template<>
+    _Format_cache<wchar_t>::_Format_cache()
+    : _M_valid(true), _M_decimal_point(L'.'), _M_thousands_sep(L','),
+      _M_truename(L"true"), _M_falsename(L"false"), _M_use_grouping(false),
+      _M_ctype(&ctype_w)
+    {
+      static const wchar_t _S_numeric_literals[] = L"-+xX0123456789abcdef0123456789ABCDEF";
+      static const int _S_literal_count = sizeof(_S_numeric_literals) - 1;
+
+      memcpy(_M_literals, _S_numeric_literals, _S_literal_count * sizeof(wchar_t));
+    }
+#endif
 } // namespace std


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]