re PR libstdc++/11722 ([3.4 only] Unbuffered filebuf::sgetn is slow)
2004-09-13 Paolo Carlini <pcarlini@suse.de> PR libstdc++/11722 * include/std/std_fstream.h (xsgetn): Declare only. * include/bits/fstream.tcc (xsgetn): Define, optimize for the always_noconv() case: when __n > __buflen, copy the available buffer and issue a direct read. * testsuite/performance/27_io/filebuf_sgetn_unbuf.cc: New. * include/bits/fstream.tcc (xsputn): Minor tweak, reorder a conditional. From-SVN: r87453
This commit is contained in:
parent
90c609e51a
commit
c56e3d82fc
|
@ -1,4 +1,16 @@
|
|||
2004-09-14 Hans-Peter Nilsson <hp@bitrange.com>
|
||||
2004-09-13 Paolo Carlini <pcarlini@suse.de>
|
||||
|
||||
PR libstdc++/11722
|
||||
* include/std/std_fstream.h (xsgetn): Declare only.
|
||||
* include/bits/fstream.tcc (xsgetn): Define, optimize for the
|
||||
always_noconv() case: when __n > __buflen, copy the available
|
||||
buffer and issue a direct read.
|
||||
* testsuite/performance/27_io/filebuf_sgetn_unbuf.cc: New.
|
||||
|
||||
* include/bits/fstream.tcc (xsputn): Minor tweak, reorder a
|
||||
conditional.
|
||||
|
||||
2004-09-13 Hans-Peter Nilsson <hp@bitrange.com>
|
||||
|
||||
* testsuite/lib/libstdc++.exp: Use gcc wrapper.exp and call
|
||||
libstdc++_maybe_build_wrapper instead of using local code.
|
||||
|
|
|
@ -494,6 +494,71 @@ namespace std
|
|||
return __elen == __plen;
|
||||
}
|
||||
|
||||
template<typename _CharT, typename _Traits>
|
||||
streamsize
|
||||
basic_filebuf<_CharT, _Traits>::
|
||||
xsgetn(_CharT* __s, streamsize __n)
|
||||
{
|
||||
// Clear out pback buffer before going on to the real deal...
|
||||
streamsize __ret = 0;
|
||||
if (this->_M_pback_init)
|
||||
{
|
||||
if (__n > 0 && this->gptr() == this->eback())
|
||||
{
|
||||
*__s++ = *this->gptr();
|
||||
this->gbump(1);
|
||||
__ret = 1;
|
||||
--__n;
|
||||
}
|
||||
_M_destroy_pback();
|
||||
}
|
||||
|
||||
// Optimization in the always_noconv() case, to be generalized in the
|
||||
// future: when __n > __buflen we read directly instead of using the
|
||||
// buffer repeatedly.
|
||||
const bool __testin = this->_M_mode & ios_base::in;
|
||||
const streamsize __buflen = this->_M_buf_size > 1 ? this->_M_buf_size - 1
|
||||
: 1;
|
||||
if (__n > __buflen && __check_facet(_M_codecvt).always_noconv()
|
||||
&& __testin && !_M_writing)
|
||||
{
|
||||
// First, copy the chars already present in the buffer.
|
||||
const streamsize __avail = this->egptr() - this->gptr();
|
||||
if (__avail == 1)
|
||||
*__s = *this->gptr();
|
||||
else if (__avail > 1)
|
||||
traits_type::move(__s, this->gptr(), __avail);
|
||||
__s += __avail;
|
||||
this->gbump(__avail);
|
||||
__ret += __avail;
|
||||
__n -= __avail;
|
||||
|
||||
const streamsize __len = _M_file.xsgetn(reinterpret_cast<char*>(__s),
|
||||
__n);
|
||||
if (__len == -1)
|
||||
__throw_ios_failure(__N("basic_filebuf::xsgetn "
|
||||
"error reading the file"));
|
||||
__ret += __len;
|
||||
if (__len == __n)
|
||||
{
|
||||
_M_set_buffer(0);
|
||||
_M_reading = true;
|
||||
}
|
||||
else if (__len == 0)
|
||||
{
|
||||
// If end of file is reached, set 'uncommitted'
|
||||
// mode, thus allowing an immediate write without
|
||||
// an intervening seek.
|
||||
_M_set_buffer(-1);
|
||||
_M_reading = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
__ret += __streambuf_type::xsgetn(__s, __n);
|
||||
|
||||
return __ret;
|
||||
}
|
||||
|
||||
template<typename _CharT, typename _Traits>
|
||||
streamsize
|
||||
basic_filebuf<_CharT, _Traits>::
|
||||
|
@ -504,8 +569,8 @@ namespace std
|
|||
// using the buffer.
|
||||
streamsize __ret = 0;
|
||||
const bool __testout = this->_M_mode & ios_base::out;
|
||||
if (__testout && !_M_reading
|
||||
&& __check_facet(_M_codecvt).always_noconv())
|
||||
if (__check_facet(_M_codecvt).always_noconv()
|
||||
&& __testout && !_M_reading)
|
||||
{
|
||||
// Measurement would reveal the best choice.
|
||||
const streamsize __chunk = 1ul << 10;
|
||||
|
|
|
@ -419,24 +419,7 @@ namespace std
|
|||
|
||||
// [documentation is inherited]
|
||||
virtual streamsize
|
||||
xsgetn(char_type* __s, streamsize __n)
|
||||
{
|
||||
// Clear out pback buffer before going on to the real deal...
|
||||
streamsize __ret = 0;
|
||||
if (this->_M_pback_init)
|
||||
{
|
||||
if (__n && this->gptr() == this->eback())
|
||||
{
|
||||
*__s++ = *this->gptr();
|
||||
this->gbump(1);
|
||||
__ret = 1;
|
||||
}
|
||||
_M_destroy_pback();
|
||||
}
|
||||
if (__ret < __n)
|
||||
__ret += __streambuf_type::xsgetn(__s, __n - __ret);
|
||||
return __ret;
|
||||
}
|
||||
xsgetn(char_type* __s, streamsize __n);
|
||||
|
||||
// [documentation is inherited]
|
||||
virtual streamsize
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 2, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING. If not, write to the Free
|
||||
// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
// USA.
|
||||
|
||||
// As a special exception, you may use this file as part of a free software
|
||||
// library without restriction. Specifically, if other files instantiate
|
||||
// templates or use macros or inline functions from this file, or you compile
|
||||
// this file and link it with other files to produce an executable, this
|
||||
// file does not by itself cause the resulting executable to be covered by
|
||||
// the GNU General Public License. This exception does not however
|
||||
// invalidate any other reasons why the executable file might be covered by
|
||||
// the GNU General Public License.
|
||||
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <testsuite_performance.h>
|
||||
|
||||
// libstdc++/11722
|
||||
int main()
|
||||
{
|
||||
using namespace std;
|
||||
using namespace __gnu_test;
|
||||
|
||||
time_counter time;
|
||||
resource_counter resource;
|
||||
|
||||
const int iterations = 500000;
|
||||
const int chunksize = 100;
|
||||
|
||||
char* chunk = new char[chunksize];
|
||||
const char* name = "/usr/share/dict/linux.words";
|
||||
|
||||
// C
|
||||
FILE* file = fopen(name, "r");
|
||||
setvbuf(file, 0, _IONBF, 0);
|
||||
start_counters(time, resource);
|
||||
for (int i = 0; i < iterations; ++i)
|
||||
if (fread(chunk, 1, chunksize, file) < chunksize)
|
||||
fseek(file, 0, SEEK_SET);
|
||||
stop_counters(time, resource);
|
||||
fclose(file);
|
||||
report_performance(__FILE__, "C", time, resource);
|
||||
clear_counters(time, resource);
|
||||
|
||||
// C unlocked
|
||||
file = fopen(name, "r");
|
||||
setvbuf(file, 0, _IONBF, 0);
|
||||
start_counters(time, resource);
|
||||
for (int i = 0; i < iterations; ++i)
|
||||
if (fread_unlocked(chunk, 1, chunksize, file) < chunksize)
|
||||
fseek(file, 0, SEEK_SET);
|
||||
stop_counters(time, resource);
|
||||
fclose(file);
|
||||
report_performance(__FILE__, "C unlocked", time, resource);
|
||||
clear_counters(time, resource);
|
||||
|
||||
// C++
|
||||
filebuf buf;
|
||||
buf.pubsetbuf(0, 0);
|
||||
buf.open(name, ios_base::in);
|
||||
start_counters(time, resource);
|
||||
for (int i = 0; i < iterations; ++i)
|
||||
if (buf.sgetn(chunk, chunksize) < chunksize)
|
||||
buf.pubseekoff(0, ios::beg);
|
||||
stop_counters(time, resource);
|
||||
report_performance(__FILE__, "C++", time, resource);
|
||||
|
||||
delete [] chunk;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue