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