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]

[Patch] Fix libstdc++/11378 (take2) + xsputn optmizations


Hi,

this is the second try, which implements the general
optimization already hinted to: whenever __n is
sufficiently large we issue a direct lower level write.

For the time being, this happens only in the
always_noconv case, but generalizations could be
envisaged. Also, as suggested privately by Nathan, we
can consider exploiting writev, when available.

I had to tweak slightly an existing testcase which
compared (__s, __s + __n) to the content of the buffer
for the latter sized exactly __n: a case currently
optimized to a direct write.

Benjamin, do you like this better?

Tested x86-linux, as usual.

Paolo.

/////////
2003-07-06  Paolo Carlini  <pcarlini@unitus.it>

	PR libstdc++/11378
	* include/std/std_fstream.h (xsputn): Declare only.
	* include/bits/fstream.tcc (xsputn): Define, optimize for the
	always_noconv() case: when __n is sufficiently large bypass
	the buffer and issue a direct write.
	* testsuite/27_io/basic_filebuf/setbuf/char/3.cc: Tweak.
	* testsuite/performance/filebuf_unbuf_sputn.cc: New.

	* include/std/std_fstream.h (sync): Constify a variable.
	
diff -urN libstdc++-v3-orig/include/bits/fstream.tcc libstdc++-v3/include/bits/fstream.tcc
--- libstdc++-v3-orig/include/bits/fstream.tcc	2003-07-05 06:05:34.000000000 +0200
+++ libstdc++-v3/include/bits/fstream.tcc	2003-07-06 19:51:09.000000000 +0200
@@ -439,6 +439,58 @@
     }
 
   template<typename _CharT, typename _Traits>
+    streamsize
+    basic_filebuf<_CharT, _Traits>::
+    xsputn(const _CharT* __s, streamsize __n)
+    { 
+      streamsize __ret = 0;
+      
+      // Optimization in the always_noconv() case, to be generalized in the
+      // future: when __n is sufficiently large we write directly instead of
+      // using the buffer.
+      const bool __testout = this->_M_mode & ios_base::out;
+      if (__testout && !_M_reading
+	  && __check_facet(_M_codecvt).always_noconv())
+	{
+	  // Measurement would reveal the best choice.
+	  const size_t __chunk = 1ul << 10;
+	  size_t __bufavail = this->epptr() - this->pptr();
+
+	  // Don't mistake 'uncommitted' mode buffered with unbuffered.
+	  if (!_M_writing && this->_M_buf_size > 1)
+	    __bufavail = this->_M_buf_size - 1;
+
+	  const size_t __limit = std::min(__chunk, __bufavail);
+	  if (__n >= __limit)
+	    {
+	      // Flush the buffer.
+	      const size_t __bufsize = this->pptr() - this->pbase();
+	      if (__bufsize)
+		{
+		  __ret = _M_file.xsputn(reinterpret_cast<const char*>(this->pbase()),
+					 __bufsize);
+		  if (__ret != __bufsize)
+		    return 0;
+		}
+	      // Output (__s, __s + __n).
+	      __ret = _M_file.xsputn(reinterpret_cast<const char*>(__s),
+				     __n);
+	      if (__ret == __n)
+		{
+		  _M_set_buffer(0);
+		  _M_writing = true;
+		}
+	    }
+	  else
+	    __ret = __streambuf_type::xsputn(__s, __n);
+	}
+      else
+	__ret = __streambuf_type::xsputn(__s, __n);
+      
+      return __ret;
+    }
+
+  template<typename _CharT, typename _Traits>
     typename basic_filebuf<_CharT, _Traits>::__streambuf_type* 
     basic_filebuf<_CharT, _Traits>::
     setbuf(char_type* __s, streamsize __n)
diff -urN libstdc++-v3-orig/include/std/std_fstream.h libstdc++-v3/include/std/std_fstream.h
--- libstdc++-v3-orig/include/std/std_fstream.h	2003-07-06 13:03:53.000000000 +0200
+++ libstdc++-v3/include/std/std_fstream.h	2003-07-06 18:48:02.000000000 +0200
@@ -365,7 +365,7 @@
 	// NB: _M_file.sync() will be called within.
 	if (this->pbase() < this->pptr())
 	  {
-	    int_type __tmp = this->overflow();
+	    const int_type __tmp = this->overflow();
 	    if (traits_type::eq_int_type(__tmp, traits_type::eof()))
 	      __ret = -1;
 	    else
@@ -407,8 +407,7 @@
 
       // [documentation is inherited]
       virtual streamsize
-      xsputn(const char_type* __s, streamsize __n)
-      { return __streambuf_type::xsputn(__s, __n); }
+      xsputn(const char_type* __s, streamsize __n);
 
       /**
        *  @if maint
diff -urN libstdc++-v3-orig/testsuite/27_io/basic_filebuf/setbuf/char/3.cc libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/3.cc
--- libstdc++-v3-orig/testsuite/27_io/basic_filebuf/setbuf/char/3.cc	2003-04-10 09:15:28.000000000 +0200
+++ libstdc++-v3/testsuite/27_io/basic_filebuf/setbuf/char/3.cc	2003-07-06 19:47:23.000000000 +0200
@@ -34,7 +34,9 @@
   filebuf fbuf01;
   fbuf01.open("tmp", ios_base::out);
 
-  fbuf01.pubsetbuf(buf, strlitsize);
+  // NB: +2 otherwise sputn is optimized to a direct write,
+  // bypassing the buffer.
+  fbuf01.pubsetbuf(buf, strlitsize + 2);
   fbuf01.sputn(strlit, strlitsize);
   VERIFY( std::strncmp(strlit, buf, strlitsize) == 0 );
 }
diff -urN libstdc++-v3-orig/testsuite/performance/filebuf_unbuf_sputn.cc libstdc++-v3/testsuite/performance/filebuf_unbuf_sputn.cc
--- libstdc++-v3-orig/testsuite/performance/filebuf_unbuf_sputn.cc	1970-01-01 01:00:00.000000000 +0100
+++ libstdc++-v3/testsuite/performance/filebuf_unbuf_sputn.cc	2003-07-06 19:21:59.000000000 +0200
@@ -0,0 +1,130 @@
+// 2003-07-06  Petur Runolfsson  <peturr02@ru.is>
+//
+// Copyright (C) 2003 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 <cstring>
+#include <fstream>
+#include <iostream>
+
+// From libstdc++/11378.
+int main(int argc, char** argv)
+{
+  using namespace std;
+  
+  if (argc < 3)
+    {
+      cerr << "Usage: " << argv[0] << " type iters [chunksize]\n";
+      return -1;
+    }
+  
+  enum { type_stdio, type_iostream } type;
+  
+  if (!strcmp(argv[1], "stdio"))
+    type = type_stdio;
+  else if (!strcmp(argv[1], "iostream"))
+    type = type_iostream;
+  else
+    {
+      cerr << "Type must be one of {stdio, iostream}\n";
+      return -1;
+    }
+  
+  int iters = atoi(argv[2]);
+  if (iters < 1)
+    {
+      cerr << "Iters must be an positive integer\n";
+      return -1;
+    }
+  
+  int chunksize = 1;
+  if (argc > 3)
+    chunksize = atoi(argv[3]);
+  
+  if (iters < 1)
+    {
+      cerr << "Chunksize must be an positive integer\n";
+      return -1;
+    }
+  
+  char* chunk = 0;
+  if (chunksize > 1)
+    {
+      chunk = new char[chunksize];
+      memset(chunk, 'a', chunksize);
+    }
+  
+  switch (type)
+    {
+    case type_stdio:
+      {
+	FILE* f = fopen("tmp", "w");
+	setvbuf(f, 0, _IONBF, 0);
+	
+	if (chunksize > 1)
+	  {
+	    for (int i = 0; i < iters; ++i)
+	      fwrite_unlocked(chunk, 1, chunksize, f);
+	  }
+	else
+	  {
+			for (int i = 0; i < iters; ++i)
+			  putc_unlocked('a', f);
+	  }
+	
+	fclose(f);
+	break;
+      }
+      
+    case type_iostream:
+      {
+	filebuf f;
+	f.pubsetbuf(0, 0);
+	
+	f.open("tmp", ios_base::out);
+	
+	if (chunksize > 1)
+	  {
+	    for (int i = 0; i < iters; ++i)
+	      f.sputn(chunk, chunksize);
+	  }
+	else
+	  {
+	    for (int i = 0; i < iters; ++i)
+	      f.sputc('a');
+	  }
+	
+	f.close();
+	
+	break;
+      }
+    }
+  
+  delete[] chunk;
+  return 0;
+}

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