gcj's IO performance vs blackdown JDK

Mohan Embar gnustuff@thisiscool.com
Fri Dec 26 18:07:00 GMT 2003


Hi Bryce,

>...Solution: fix InputSreamReader to decode characters directly into the
>array given to it in the read() method. This brought us up to about or slightly
>faster than the JRE 1.4.2 on Chris's test.

>From memory, my readLine() implementation only creates a StringBuffer 
>in the event that the line crosses a boundary between buffers (ie the 
>StringBuffer is used to store the start of a line when the buffer needs 
>to be refilled), so given a full 8192 char buffer, the need to create a 
>StringBuffer should be rare at least for input with "normal" sized 
>lines.

>Unfortunately I don't have access to my development machine right now 
>and I didn't think to grab a copy of my tree on my laptop, otherwise 
>I'd post a copy. I'll post it next week.

I was too eager to try this out to wait 'til next week :)

Here are my timings for successive iterations of this. And attached is
my informal patch for the (direct read into buffer + StringBuffer member
variable + String.valueOf() + lineEnd() native) fix.

I am going to stop here and leave this alone unless someone wants me
to follow up on this.

I also eliminated the unnecessary synchronization, but judged the
time savings too insignificant to be worthy of inclusion. If anyone
wants the code, let me know.

-- Mohan
http://www.thisiscool.com/
http://www.animalsong.org/

current CVS version
-------------------
running gcj version
100000

real    0m34.864s
user    0m33.148s
sys     0m1.369s
running jdk version
100000

real    0m17.047s
user    0m15.639s
sys     0m1.020s

direct read into buffer
-------------------
running gcj version
100000

real    0m18.608s
user    0m16.908s
sys     0m1.326s
running jdk version
100000

real    0m17.430s
user    0m15.600s
sys     0m1.051s

direct read into buffer
+ StringBuffer member variable
-------------------
running gcj version
100000

real    0m18.009s
user    0m16.227s
sys     0m1.361s
running jdk version
100000

real    0m16.970s
user    0m15.633s
sys     0m1.010s

direct read into buffer
+ StringBuffer member variable
+ String.valueOf()
-------------------
running gcj version
100000

real    0m17.868s
user    0m16.033s
sys     0m1.410s
running jdk version
100000

real    0m17.314s
user    0m15.613s
sys     0m1.164s

direct read into buffer
+ StringBuffer member variable
+ String.valueOf()
+ lineEnd() native
-------------------
running gcj version
100000

real    0m17.185s
user    0m15.412s
sys     0m1.330s
running jdk version
100000

real    0m17.001s
user    0m15.615s
sys     0m1.027s

Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.347
diff -u -2 -r1.347 Makefile.am
--- Makefile.am	23 Dec 2003 11:55:29 -0000	1.347
+++ Makefile.am	26 Dec 2003 17:43:13 -0000
@@ -2739,4 +2739,5 @@
 gnu/java/nio/natSelectorImpl.cc \
 gnu/java/nio/natNIOServerSocket.cc \
+java/io/natBufferedReader.cc \
 java/io/natFile.cc \
 java/io/natFileDescriptor.cc \
Index: java/io/BufferedReader.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/BufferedReader.java,v
retrieving revision 1.14
diff -u -2 -r1.14 BufferedReader.java
--- java/io/BufferedReader.java	14 Jun 2003 05:44:38 -0000	1.14
+++ java/io/BufferedReader.java	26 Dec 2003 17:43:33 -0000
@@ -90,4 +90,9 @@
 
   /**
+   * The line buffer for <code>readLine</code>.
+   */
+  private StringBuffer sbuf = null;
+
+  /**
     * Create a new <code>BufferedReader</code> that will read from the 
     * specified subordinate stream with a default buffer size of 8192 chars.
@@ -389,15 +394,5 @@
    * if no line terminators were found.
    */
-  private int lineEnd(int limit)
-  {
-    int i = pos;
-    for (; i < limit; i++)
-      {
-	char ch = buffer[i];
-	if (ch == '\n' || ch == '\r')
-	  break;
-      }
-    return i;
-  }
+  private native int lineEnd(int limit);
 
   /**
@@ -430,5 +425,5 @@
     if (i < limit)
       {
-	String str = new String(buffer, pos, i - pos);
+	String str = String.valueOf(buffer, pos, i - pos);
 	pos = i + 1;
 	// If the last char in the buffer is a '\r', we must remember
@@ -441,5 +436,8 @@
 	return str;
       }
-    StringBuffer sbuf = new StringBuffer(200);
+    if (sbuf == null)
+      sbuf = new StringBuffer(200);
+    else
+      sbuf.setLength(0);
     sbuf.append(buffer, pos, i - pos);
     pos = i;
Index: java/io/InputStreamReader.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/InputStreamReader.java,v
retrieving revision 1.15
diff -u -2 -r1.15 InputStreamReader.java
--- java/io/InputStreamReader.java	9 May 2003 07:10:58 -0000	1.15
+++ java/io/InputStreamReader.java	26 Dec 2003 17:43:34 -0000
@@ -232,8 +232,6 @@
 	if (wavail <= 0)
 	  {
-	    // Nothing waiting, so refill our buffer.
-	    if (! refill ())
-	      return -1;
-	    wavail = wcount - wpos;
+	    // Nothing waiting, so refill their buffer.
+	    return refill(buf, offset, length);
 	  }
 
@@ -263,7 +261,12 @@
 	if (wavail <= 0)
 	  {
-	    // Nothing waiting, so refill our buffer.
-	    if (! refill ())
+	    // Nothing waiting, so refill our internal buffer.
+	    wpos = wcount = 0;
+	    if (work == null)
+	       work = new char[100];
+	    int count = refill(work, 0, work.length);
+	    if (count == -1)
 	      return -1;
+	    wcount += count;
 	  }
 
@@ -272,13 +275,8 @@
   }
 
-  // Read more bytes and convert them into the WORK buffer.
-  // Return false on EOF.
-  private boolean refill () throws IOException
+  // Read more bytes and convert them into the specified buffer.
+  // Returns the number of converted characters or -1 on EOF.
+  private int refill(char[] buf, int offset, int length) throws IOException
   {
-    wcount = wpos = 0;
-
-    if (work == null)
-      work = new char[100];
-
     for (;;)
       {
@@ -291,16 +289,12 @@
 	in.reset ();
 	if (! r)
-	  return false;
+	  return -1;
 	converter.setInput(in.buf, in.pos, in.count);
-	int count = converter.read (work, wpos, work.length - wpos);
+	int count = converter.read(buf, offset, length);
 	in.skip(converter.inpos - in.pos);
 	if (count > 0)
-	  {
-	    wcount += count;
-	    return true;
-	  }
+	  return count;
       }
   }
-
 } // class InputStreamReader
 
Index: java/io/natBufferedReader.cc
===================================================================
--- java/io/natBufferedReader.cc	2003-12-26 12:02:29.000000000 -0600
+++ java/io/natBufferedReader.cc	2003-12-26 10:26:14.000000000 -0600
@@ -0,0 +1,29 @@
+// natBufferedReader.cc - Native part of BufferedReader class.
+
+/* Copyright (C) 1998, 1999, 2000, 2001  Free Software Foundation
+
+   This ObjectInputStream is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the ObjectInputStream "LIBGCJ_LICENSE" for
+details.  */
+
+#include <config.h>
+
+#include <gcj/cni.h>
+#include <jvm.h>
+
+#include <java/io/BufferedReader.h>
+
+jint java::io::BufferedReader::lineEnd (jint limit)
+{
+  jchar *pbuf = elements (buffer) + pos;
+  int i = pos;
+  for (; i < limit; i++)
+  {
+    jchar ch = *pbuf++;
+    if (ch == '\n' || ch == '\r')
+      break;
+  }
+  return i;
+}





More information about the Java mailing list