diff options
author | Jason Merrill <jason@redhat.com> | 2002-04-22 16:28:05 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2002-04-22 16:28:05 -0400 |
commit | 5066927d9ebedf0098887901674e576413312848 (patch) | |
tree | a33a1f81577d6fbf44ec2eca41aa87ca71f31743 | |
parent | f942d7a5df511c42fe0af6edb0138bd806684561 (diff) | |
download | gcc-5066927d9ebedf0098887901674e576413312848.zip gcc-5066927d9ebedf0098887901674e576413312848.tar.gz gcc-5066927d9ebedf0098887901674e576413312848.tar.bz2 |
re PR libstdc++/4150 (catastrophic performance decrease in C++ code)
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.
* testsuite/27_io/filebuf_virtuals.cc (test05): Don't overspecify
ungetc test.
From-SVN: r52634
-rw-r--r-- | libstdc++-v3/ChangeLog | 28 | ||||
-rw-r--r-- | libstdc++-v3/config/os/bsd/freebsd/bits/os_defines.h | 2 | ||||
-rw-r--r-- | libstdc++-v3/config/os/mingw32/bits/os_defines.h | 3 | ||||
-rw-r--r-- | libstdc++-v3/config/os/solaris/solaris2.5/bits/os_defines.h | 2 | ||||
-rw-r--r-- | libstdc++-v3/config/os/solaris/solaris2.6/bits/os_defines.h | 2 | ||||
-rw-r--r-- | libstdc++-v3/config/os/solaris/solaris2.7/bits/os_defines.h | 2 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/fstream.tcc | 38 | ||||
-rw-r--r-- | libstdc++-v3/include/std/std_fstream.h | 74 | ||||
-rw-r--r-- | libstdc++-v3/include/std/std_streambuf.h | 42 | ||||
-rw-r--r-- | libstdc++-v3/src/ios.cc | 8 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc | 3 |
11 files changed, 118 insertions, 86 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 3ac23e5..61788e0 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,31 @@ +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. + * testsuite/27_io/filebuf_virtuals.cc (test05): Don't overspecify + ungetc test. + 2002-04-22 Benjamin Kosnik <bkoz@redhat.com> * include/bits/istream.tcc (istream::read): Fix. diff --git a/libstdc++-v3/config/os/bsd/freebsd/bits/os_defines.h b/libstdc++-v3/config/os/bsd/freebsd/bits/os_defines.h index 9e6bbaf..cfc917f 100644 --- a/libstdc++-v3/config/os/bsd/freebsd/bits/os_defines.h +++ b/libstdc++-v3/config/os/bsd/freebsd/bits/os_defines.h @@ -36,6 +36,4 @@ #define __glibcpp_long_double_bits __glibcpp_double_bits -#define _GLIBCPP_AVOID_FSEEK 1 - #endif diff --git a/libstdc++-v3/config/os/mingw32/bits/os_defines.h b/libstdc++-v3/config/os/mingw32/bits/os_defines.h index eb4bb1c..5c99e09 100644 --- a/libstdc++-v3/config/os/mingw32/bits/os_defines.h +++ b/libstdc++-v3/config/os/mingw32/bits/os_defines.h @@ -34,7 +34,4 @@ // System-specific #define, typedefs, corrections, etc, go here. This // file will come before all others. -#define _GLIBCPP_AVOID_FSEEK 1 - - #endif diff --git a/libstdc++-v3/config/os/solaris/solaris2.5/bits/os_defines.h b/libstdc++-v3/config/os/solaris/solaris2.5/bits/os_defines.h index 0edc784..145ae66 100644 --- a/libstdc++-v3/config/os/solaris/solaris2.5/bits/os_defines.h +++ b/libstdc++-v3/config/os/solaris/solaris2.5/bits/os_defines.h @@ -33,8 +33,6 @@ // 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 diff --git a/libstdc++-v3/config/os/solaris/solaris2.6/bits/os_defines.h b/libstdc++-v3/config/os/solaris/solaris2.6/bits/os_defines.h index 3acdf5c..7aa9a7e 100644 --- a/libstdc++-v3/config/os/solaris/solaris2.6/bits/os_defines.h +++ b/libstdc++-v3/config/os/solaris/solaris2.6/bits/os_defines.h @@ -33,8 +33,6 @@ // 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 diff --git a/libstdc++-v3/config/os/solaris/solaris2.7/bits/os_defines.h b/libstdc++-v3/config/os/solaris/solaris2.7/bits/os_defines.h index a0fd243..356c55c 100644 --- a/libstdc++-v3/config/os/solaris/solaris2.7/bits/os_defines.h +++ b/libstdc++-v3/config/os/solaris/solaris2.7/bits/os_defines.h @@ -33,8 +33,6 @@ // 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 diff --git a/libstdc++-v3/include/bits/fstream.tcc b/libstdc++-v3/include/bits/fstream.tcc index fb2f876..235b4a8 100644 --- a/libstdc++-v3/include/bits/fstream.tcc +++ b/libstdc++-v3/include/bits/fstream.tcc @@ -206,7 +206,7 @@ namespace std template<typename _CharT, typename _Traits> typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits>:: - underflow() + _M_underflow_common(bool __bump) { int_type __ret = traits_type::eof(); bool __testin = _M_mode & ios_base::in; @@ -232,12 +232,8 @@ namespace std { 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, + else if (_M_in_cur != _M_filepos) + _M_file.seekoff(_M_in_cur - _M_filepos, ios_base::cur, ios_base::in); } @@ -280,16 +276,16 @@ namespace std 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 + if (__bump) + _M_in_cur_move(1); + else if (_M_buf_size == 1) { -#endif - _M_file.seekoff(-__elen, ios_base::cur, ios_base::in); -#if _GLIBCPP_AVOID_FSEEK + // 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(); } -#endif } } } @@ -464,6 +460,15 @@ namespace std 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) @@ -551,9 +556,8 @@ namespace std _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; + __computed_off += _M_in_cur - _M_filepos; __ret = _M_file.seekoff(__computed_off, __way, __mode); _M_set_indeterminate(); diff --git a/libstdc++-v3/include/std/std_fstream.h b/libstdc++-v3/include/std/std_fstream.h index 4db2594..c0d80da 100644 --- a/libstdc++-v3/include/std/std_fstream.h +++ b/libstdc++-v3/include/std/std_fstream.h @@ -93,6 +93,10 @@ namespace std // 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(); @@ -137,8 +141,21 @@ namespace std // 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 - underflow(); + uflow() { return _M_underflow_common(true); } virtual int_type pbackfail(int_type __c = _Traits::eof()); @@ -189,14 +206,11 @@ namespace std // 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; + // Need to restore current position after the write. + off_type __off = _M_out_cur - _M_out_end; _M_really_overflow(); - _M_file.seekpos(__cur + __off); + if (__off) + _M_file.seekoff(__off, ios_base::cur); } _M_last_overflowed = false; return 0; @@ -235,6 +249,50 @@ namespace std 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; + } }; diff --git a/libstdc++-v3/include/std/std_streambuf.h b/libstdc++-v3/include/std/std_streambuf.h index 53e1e08..012bf4e 100644 --- a/libstdc++-v3/include/std/std_streambuf.h +++ b/libstdc++-v3/include/std/std_streambuf.h @@ -231,48 +231,6 @@ namespace std 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() diff --git a/libstdc++-v3/src/ios.cc b/libstdc++-v3/src/ios.cc index 0aab0a2..1d97bf9 100644 --- a/libstdc++-v3/src/ios.cc +++ b/libstdc++-v3/src/ios.cc @@ -150,14 +150,6 @@ namespace std 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. diff --git a/libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc b/libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc index 2609d26..fb370c3 100644 --- a/libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc +++ b/libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc @@ -444,6 +444,9 @@ void test05() strmsz_1 = fb_03.sputn("because because because. . .", 28); VERIFY( strmsz_1 == 28 ); c1 = fb_03.sungetc(); + // Defect? retval of sungetc is not necessarily the character ungotten. + // So re-get it. + c1 = fb_03.sgetc(); fb_03.pubsync(); c3 = fb_03.sgetc(); VERIFY( c1 == c3 ); |