This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ 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]

Re: libstdc++/4150: catastrophic performance decrease in C++ code


Here's a more limited patch, which just avoids the seeking.  Rather than
define _M_in_end to indicate the file pointer, it adds another member.

2002-04-20  Jason Merrill  <jason@redhat.com>

	PR libstdc++/4150
	* include/std/std_streambuf.h (basic_streambuf::_M_set_indeterminate): 
	Move to filebuf.
	(basic_streambuf::_M_set_determinate): Likewise.
	(basic_streambuf::_M_is_indeterminate): Likewise.
	* include/bits/std_fstream.h (basic_filebuf::_M_filepos): New 
	non-static data member.
	(basic_filebuf::_M_underflow_common): New non-static member function.
	(basic_filebuf::_M_underflow, _M_uflow): Call it.
	(basic_filebuf::sync): Avoid useless seeking.
	(basic_filebuf::_M_set_indeterminate): Move here from streambuf.
	Set _M_filepos.
	(basic_filebuf::_M_set_determinate): Likewise.
	(basic_filebuf::_M_is_indeterminate): Likewise.
	* include/bits/fstream.tcc (basic_filebuf::_M_really_overflow): Seek
	back to _M_out_beg if necessary.
	(basic_filebuf::seekoff): Likewise.
	(basic_filebuf::_M_underflow_common): Generalization of old 
	underflow().  Don't seek back to _M_in_beg.
	* src/ios.cc: Lose _GLIBCPP_AVOID_FSEEK stuff.
	* config/os/solaris/solaris2.?/bits/os_defines.h: Likewise.
	* config/os/bsd/freebsd/bits/os_defines.h: Likewise.
	* config/os/mingw32/bits/os_defines.h: Likewise.

*** ./config/os/solaris/solaris2.5/bits/os_defines.h.~1~	Fri Nov  2 17:22:15 2001
--- ./config/os/solaris/solaris2.5/bits/os_defines.h	Mon Apr 22 19:15:45 2002
***************
*** 33,40 ****
  // System-specific #define, typedefs, corrections, etc, go here.  This
  // file will come before all others.
  
- #define _GLIBCPP_AVOID_FSEEK 1
- 
  // These are typedefs which libio assumes are already in place (because
  // they really are, under Linux).
  #define __off_t     off_t
--- 33,38 ----
*** ./config/os/solaris/solaris2.6/bits/os_defines.h.~1~	Fri Nov  2 17:22:15 2001
--- ./config/os/solaris/solaris2.6/bits/os_defines.h	Mon Apr 22 19:15:45 2002
***************
*** 33,40 ****
  // System-specific #define, typedefs, corrections, etc, go here.  This
  // file will come before all others.
  
- #define _GLIBCPP_AVOID_FSEEK 1
- 
  // These are typedefs which libio assumes are already in place (because
  // they really are, under Linux).
  #define __off_t     off_t
--- 33,38 ----
*** ./config/os/solaris/solaris2.7/bits/os_defines.h.~1~	Fri Nov  2 17:22:15 2001
--- ./config/os/solaris/solaris2.7/bits/os_defines.h	Mon Apr 22 19:15:45 2002
***************
*** 33,40 ****
  // System-specific #define, typedefs, corrections, etc, go here.  This
  // file will come before all others.
  
- #define _GLIBCPP_AVOID_FSEEK 1
- 
  // These are typedefs which libio assumes are already in place (because
  // they really are, under Linux).
  #define __off_t     off_t
--- 33,38 ----
*** ./config/os/bsd/freebsd/bits/os_defines.h.~1~	Fri Nov  2 17:22:13 2001
--- ./config/os/bsd/freebsd/bits/os_defines.h	Mon Apr 22 19:15:45 2002
***************
*** 36,41 ****
  
  #define __glibcpp_long_double_bits __glibcpp_double_bits
  
- #define _GLIBCPP_AVOID_FSEEK 1
- 
  #endif
--- 36,39 ----
*** ./config/os/mingw32/bits/os_defines.h.~1~	Thu Nov  8 20:52:28 2001
--- ./config/os/mingw32/bits/os_defines.h	Mon Apr 22 19:15:45 2002
***************
*** 34,40 ****
  // System-specific #define, typedefs, corrections, etc, go here.  This
  // file will come before all others.
  
- #define _GLIBCPP_AVOID_FSEEK 1
- 
- 
  #endif
--- 34,37 ----
*** ./include/bits/fstream.tcc.~1~	Fri Apr 19 17:39:29 2002
--- ./include/bits/fstream.tcc	Mon Apr 22 19:21:07 2002
*************** namespace std
*** 206,212 ****
    template<typename _CharT, typename _Traits>
      typename basic_filebuf<_CharT, _Traits>::int_type 
      basic_filebuf<_CharT, _Traits>::
!     underflow()
      {
        int_type __ret = traits_type::eof();
        bool __testin = _M_mode & ios_base::in;
--- 206,212 ----
    template<typename _CharT, typename _Traits>
      typename basic_filebuf<_CharT, _Traits>::int_type 
      basic_filebuf<_CharT, _Traits>::
!     _M_underflow_common(bool __bump)
      {
        int_type __ret = traits_type::eof();
        bool __testin = _M_mode & ios_base::in;
*************** namespace std
*** 232,243 ****
  	    {
  	      if (__testout)
  		_M_really_overflow();
! #if _GLIBCPP_AVOID_FSEEK
! 	      else if ((_M_in_cur - _M_in_beg) == 1)
! 		_M_file.sys_getc();
! #endif
! 	      else 
! 		_M_file.seekoff(_M_in_cur - _M_in_beg, 
  				ios_base::cur, ios_base::in);
  	    }
  
--- 232,239 ----
  	    {
  	      if (__testout)
  		_M_really_overflow();
! 	      else if (_M_in_cur != _M_filepos)
! 		_M_file.seekoff(_M_in_cur - _M_filepos,
  				ios_base::cur, ios_base::in);
  	    }
  
*************** namespace std
*** 280,295 ****
  		  if (__testout)
  		    _M_out_cur = _M_in_cur;
  		  __ret = traits_type::to_int_type(*_M_in_cur);
! #if _GLIBCPP_AVOID_FSEEK
! 		  if (__elen == 1)
! 		    _M_file.sys_ungetc(*_M_in_cur);
! 		  else
  		    {
! #endif
! 		      _M_file.seekoff(-__elen, ios_base::cur, ios_base::in);
! #if _GLIBCPP_AVOID_FSEEK
  		    }
- #endif
  		}	   
  	    }
  	}
--- 276,291 ----
  		  if (__testout)
  		    _M_out_cur = _M_in_cur;
  		  __ret = traits_type::to_int_type(*_M_in_cur);
! 		  if (__bump)
! 		    _M_in_cur_move(1);
! 		  else if (_M_buf_size == 1)
  		    {
! 		      // If we are synced with stdio, we have to unget the
! 		      // character we just read so that the file pointer
! 		      // doesn't move.
! 		      _M_file.sys_ungetc(*_M_in_cur);
! 		      _M_set_indeterminate();
  		    }
  		}	   
  	    }
  	}
*************** namespace std
*** 464,469 ****
--- 460,474 ----
  	  streamsize __elen = 0;
  	  streamsize __plen = 0;
  
+ 	  // Need to restore current position. The position of the external
+ 	  // byte sequence (_M_file) corresponds to _M_filepos, and we need
+ 	  // to move it to _M_out_beg for the write.
+ 	  if (_M_filepos && _M_filepos != _M_out_beg)
+ 	    {
+ 	      off_type __off = _M_out_beg - _M_filepos;
+ 	      _M_file.seekoff(__off, ios_base::cur);
+ 	    }
+ 
  	  // Convert internal buffer to external representation, output.
  	  // NB: In the unbuffered case, no internal buffer exists. 
  	  if (!__testunbuffered)
*************** namespace std
*** 551,559 ****
  		  _M_output_unshift();
  		}
  	      //in
- 	      // NB: underflow() rewinds the external buffer.
  	      else if (__testget && __way == ios_base::cur)
! 		__computed_off += _M_in_cur - _M_in_beg;
  	  
  	      __ret = _M_file.seekoff(__computed_off, __way, __mode);
  	      _M_set_indeterminate();
--- 556,563 ----
  		  _M_output_unshift();
  		}
  	      //in
  	      else if (__testget && __way == ios_base::cur)
! 		__computed_off += _M_in_cur - _M_filepos;
  	  
  	      __ret = _M_file.seekoff(__computed_off, __way, __mode);
  	      _M_set_indeterminate();
*** ./include/std/std_fstream.h.~1~	Fri Apr 19 17:39:29 2002
--- ./include/std/std_fstream.h	Mon Apr 22 20:08:53 2002
*************** namespace std
*** 93,98 ****
--- 93,102 ----
        // XXX Needed?
        bool			_M_last_overflowed;
  
+       // The position in the buffer corresponding to the external file
+       // pointer.
+       char_type*		_M_filepos;
+ 
      public:
        // Constructors/destructor:
        basic_filebuf();
*************** namespace std
*** 137,144 ****
        // underflow() and uflow() functions are called to get the next
        // charater from the real input source when the buffer is empty.
        // Buffered input uses underflow()
        virtual int_type
!       underflow();
  
        virtual int_type
        pbackfail(int_type __c = _Traits::eof());
--- 141,161 ----
        // underflow() and uflow() functions are called to get the next
        // charater from the real input source when the buffer is empty.
        // Buffered input uses underflow()
+ 
+       // The only difference between underflow() and uflow() is that the
+       // latter bumps _M_in_cur after the read.  In the sync_with_stdio
+       // case, this is important, as we need to unget the read character in
+       // the underflow() case in order to maintain synchronization.  So
+       // instead of calling underflow() from uflow(), we create a common
+       // subroutine to do the real work.
+       int_type
+       _M_underflow_common(bool __bump);
+ 
+       virtual int_type
+       underflow() { return _M_underflow_common(false); }
+ 
        virtual int_type
!       uflow() { return _M_underflow_common(true); }
  
        virtual int_type
        pbackfail(int_type __c = _Traits::eof());
*************** namespace std
*** 189,202 ****
  	// the file position with the external file.
  	if (__testput && !_M_file.sync())
  	  {
! 	    // Need to restore current position. This interpreted as
! 	    // the position of the external byte sequence (_M_file)
! 	    // plus the offset in the current internal buffer
! 	    // (_M_out_beg - _M_out_cur)
! 	    streamoff __cur = _M_file.seekoff(0, ios_base::cur);
! 	    off_type __off = _M_out_cur - _M_out_beg;
  	    _M_really_overflow();
! 	    _M_file.seekpos(__cur + __off);
  	  }
  	_M_last_overflowed = false;
  	return 0;
--- 206,216 ----
  	// the file position with the external file.
  	if (__testput && !_M_file.sync())
  	  {
! 	    // Need to restore current position after the write.
! 	    off_type __off = _M_out_cur - _M_out_end;
  	    _M_really_overflow();
! 	    if (__off)
! 	      _M_file.seekoff(__off, ios_base::cur);
  	  }
  	_M_last_overflowed = false;
  	return 0;
*************** namespace std
*** 235,240 ****
--- 249,298 ----
  
        void
        _M_output_unshift();
+ 
+       // These three functions are used to clarify internal buffer
+       // maintenance. After an overflow, or after a seekoff call that
+       // started at beg or end, or possibly when the stream becomes
+       // unbuffered, and a myrid other obscure corner cases, the
+       // internal buffer does not truly reflect the contents of the
+       // external buffer. At this point, for whatever reason, it is in
+       // an indeterminate state.
+       void
+       _M_set_indeterminate(void)
+       {
+ 	if (_M_mode & ios_base::in)
+ 	  this->setg(_M_buf, _M_buf, _M_buf);
+ 	if (_M_mode & ios_base::out)
+ 	  this->setp(_M_buf, _M_buf);
+ 	_M_filepos = _M_in_end;
+       }
+ 
+       void
+       _M_set_determinate(off_type __off)
+       {
+ 	bool __testin = _M_mode & ios_base::in;
+ 	bool __testout = _M_mode & ios_base::out;
+ 	if (__testin)
+ 	  this->setg(_M_buf, _M_buf, _M_buf + __off);
+ 	if (__testout)
+ 	  this->setp(_M_buf, _M_buf + __off);
+ 	_M_filepos = _M_in_end;
+       }
+ 
+       bool
+       _M_is_indeterminate(void)
+       { 
+ 	bool __ret = false;
+ 	// Don't return true if unbuffered.
+ 	if (_M_buf)
+ 	  {
+ 	    if (_M_mode & ios_base::in)
+ 	      __ret = _M_in_beg == _M_in_cur && _M_in_cur == _M_in_end;
+ 	    if (_M_mode & ios_base::out)
+ 	      __ret = _M_out_beg == _M_out_cur && _M_out_cur == _M_out_end;
+ 	  }
+ 	return __ret;
+       }
      };
  
  
*** ./include/std/std_streambuf.h.~1~	Fri Apr 19 17:39:29 2002
--- ./include/std/std_streambuf.h	Mon Apr 22 18:42:11 2002
*************** namespace std
*** 231,278 ****
  	return __ret;
        }
  
-       // These three functions are used to clarify internal buffer
-       // maintenance. After an overflow, or after a seekoff call that
-       // started at beg or end, or possibly when the stream becomes
-       // unbuffered, and a myrid other obscure corner cases, the
-       // internal buffer does not truly reflect the contents of the
-       // external buffer. At this point, for whatever reason, it is in
-       // an indeterminate state.
-       void
-       _M_set_indeterminate(void)
-       {
- 	if (_M_mode & ios_base::in)
- 	  this->setg(_M_buf, _M_buf, _M_buf);
- 	if (_M_mode & ios_base::out)
- 	  this->setp(_M_buf, _M_buf);
-       }
- 
-       void
-       _M_set_determinate(off_type __off)
-       {
- 	bool __testin = _M_mode & ios_base::in;
- 	bool __testout = _M_mode & ios_base::out;
- 	if (__testin)
- 	  this->setg(_M_buf, _M_buf, _M_buf + __off);
- 	if (__testout)
- 	  this->setp(_M_buf, _M_buf + __off);
-       }
- 
-       bool
-       _M_is_indeterminate(void)
-       { 
- 	bool __ret = false;
- 	// Don't return true if unbuffered.
- 	if (_M_buf)
- 	  {
- 	    if (_M_mode & ios_base::in)
- 	      __ret = _M_in_beg == _M_in_cur && _M_in_cur == _M_in_end;
- 	    if (_M_mode & ios_base::out)
- 	      __ret = _M_out_beg == _M_out_cur && _M_out_cur == _M_out_end;
- 	  }
- 	return __ret;
-       }
- 
    public:
        virtual 
        ~basic_streambuf() 
--- 231,236 ----
*** ./src/ios.cc.~1~	Fri Apr 19 17:39:29 2002
--- ./src/ios.cc	Mon Apr 22 18:41:20 2002
*************** namespace std 
*** 150,163 ****
      int __out_bufsize = __sync ? 0 : static_cast<int>(BUFSIZ);
      int __in_bufsize = __sync ? 1 : static_cast<int>(BUFSIZ);
  
- #if _GLIBCPP_AVOID_FSEEK
-     // Platforms that prefer to avoid fseek() calls on streams only
-     // get their desire when the C++-layer input buffer size is 1.
-     // This hack hurts performance but keeps correctness across
-     // all types of streams that might be attached to (e.g.) cin.
-     __in_bufsize = 1;
- #endif
- 
      // NB: The file globals.cc creates the four standard files
      // with NULL buffers. At this point, we swap out the dummy NULL
      // [io]stream objects and buffers with the real deal.
--- 150,155 ----

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