Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4137835

java.io.RandomAccessFile.writeInt(),readInt() methods results in four kernel cal

    XMLWordPrintable

    Details

    • Type: Enhancement
    • Status: Closed
    • Priority: P3
    • Resolution: Won't Fix
    • Affects Version/s: 1.1.5, 1.1.6, 1.2.0, 5.0
    • Fix Version/s: None
    • Component/s: core-libs
    • Subcomponent:
    • CPU:
      generic, sparc
    • OS:
      generic, solaris_2.5.1, solaris_2.6

      Description

      Problem
      -------
      Synopsis: java.io.*.writeInt() methods results in four Solaris write() calls.

      Summary:

             The Java.io.*.writeInt() methods results in four Solaris write() system
             call invocations for a single 32 bit value. The equivalent optimzed
             version of the code using the Java write(byte[], int, int) method can
             show significant improvements in the amount of time required to run and
             a related reduction in the number of write(2) Solaris system calls made.

      Code Example
      ------------

      The following Java code reveals the underlying performance of the Solaris
      implementation of java.io.*.writeInt():

      import java.io.RandomAccessFile;
      import java.io.IOException;

      class IntWrite
      {
          public static void main(String args[])
              throws IOException
          {
              RandomAccessFile raf = new RandomAccessFile("testfile.dat", "rw");

              int lim = Integer.parseInt(args[0]);

              for (int i=0; i<lim; i++) {
                  raf.writeInt(i);
              }
              raf.close();
          }
      }

      -------

      Contrasting this with:

      import java.io.RandomAccessFile;
      import java.io.IOException;
      import java.lang.Integer;

      class ByteArrayWrite
      {
          public static void main(String args[])
              throws IOException
          {
              RandomAccessFile raf = new RandomAccessFile("testfile.dat", "rw");

              byte [] a;

              int lim = Integer.parseInt(args[0]);

              for (int i = 0; i < lim; i++) {
                      a = IntToByteArray.getByteA(i);
                      raf.write(a,0,4);
              }

              raf.close();
          }
      }

      ----- Code follows for: IntToByteArray.getByteA():

      //
      // Take an Int, convert it to a byte[].

      public class IntToByteArray {

              public static void main ( String args[] ) {
                      byte[] b;
                      b = IntToByteArray.getByteA(10);
                      b = IntToByteArray.getByteA(-1);
              }

              public static byte[] getByteA(int startInt) {

                      //int startInt = i;
                      //int endInt = 0;
                      byte[] a = new byte[4];

                      // Make a byte array
                      a[3] = (byte) startInt;
                      a[2] = (byte) ( startInt >>> 8 );
                      a[1] = (byte) ( startInt >>> 16 );
                      a[0] = (byte) ( startInt >>> 24 );

                      //System.out.println ( " Bytes " + a[0] + " " + a[1] + " " + a
       [2] + " " + a[3] );

                      //endInt = ((a[0]&0xff) << 24 | (a[1]&0xff) << 16 | (a[2]&0xff)
       << 8 | a[3]);

                      //System.out.println ( "Ending: " + endInt );
                      return a;
              }

      }

      To Reproduce
      ------------

      In my testing I took:

           Solaris 2.6 3/98 + patches (see attachment "showrev-p")
           Ultra 30 UltraSPARC-II 296 MHz
           128Mb memory

           Disk Vendor: SEAGATE
               Product: ST34371W SUN4.2G
              Revision: 7462

      With the Solaris Java JDK 1.1.5 installed, specifically:

           java full version "Solaris_JDK_1.1.5_02"

      although other versions of Java can be seen to exhibit the behaviour
      detailed in this bug report.

      The relative performance of each can be summarized by the timed statistics
      generated by the following test harnesses, firstly for the test "IntWrite":

         #!/bin/ksh -x
         #rm -f testfile.dat
         #truss -o output.tr -t,write java IntWrite $1
         #grep write output.tr| wc -l > writes
         rm -f testfile.dat
         /bin/time -p java IntWrite $1 >time.out.$1 2>&1

      and via, the ByteArrayWrite harness:

         #!/bin/ksh -x
         #rm -f testfile.dat
         #truss -o output.tr -t,write java ByteArrayWrite $1
         #grep write output.tr| wc -l > writes
         rm -f testfile.dat
         /bin/time -p java ByteArrayWrite $1 >time.out.$1 2>&1

      When driven over a range of values, governing the number of integers
      to be written, the timings can be summarized as follows:

      Times for JDK 1.1.5

         kuta% grep real byteW/time.out.*
         byteW/time.out.10:real 0.19
         byteW/time.out.100:real 0.20
         byteW/time.out.1000:real 0.22
         byteW/time.out.10000:real 0.43
         byteW/time.out.100000:real 2.82
         byteW/time.out.1000000:real 27.48

         kuta% grep real intW/time.out.*
         intW/time.out.10:real 0.20
         intW/time.out.100:real 0.21
         intW/time.out.1000:real 0.28
         intW/time.out.10000:real 0.96
         intW/time.out.100000:real 8.78
         intW/time.out.1000000:real 89.26

      Times for JDK 1.1.6

         kuta% grep real byteW/time.out.*
         byteW/time.out.10:real 0.37
         byteW/time.out.100:real 0.33
         byteW/time.out.1000:real 0.36
         byteW/time.out.10000:real 0.54
         byteW/time.out.100000:real 2.24
         byteW/time.out.1000000:real 18.65

         kuta% grep real intW/time.out.*
         intW/time.out.10:real 0.37
         intW/time.out.100:real 0.34
         intW/time.out.1000:real 0.39
         intW/time.out.10000:real 0.88
         intW/time.out.100000:real 5.45
         intW/time.out.1000000:real 52.07


      From the above we can highlight the performance of JDK 1.1.6:

         intW/time.out.1000000:real 52.07

      as the issue at the core of this bug, contrast this with the time taken to
      write the equivalent interation recorded when the ByteArrayWrite class is
      used:

         byteW/time.out.1000000:real 18.65

      Looking more deeply at what the:

         IntWrite.RandomAccessFile.raf.writeInt(i);

      becomes in terms of a system call to Solaris we can see via truss
      that exactly four write(2) system calls are made for each
      RandomAccessFile.writeInt() method invocation. Looking at a typical
      truss record we see:

         kuta% cat output.tr
         write(8, "\0", 1) = 1
         write(8, "\0", 1) = 1
         write(8, "\0", 1) = 1
         write(8, "\0", 1) = 1

      For a call to:

        truss -o output.tr -t,write java IntWrite 1

      When optimized via the ByteArrayWrite class and:

        ByteArrayWrite.RandomAccessFile.raf.write(a,0,4);

      we can imediately cut the number of calls to the Solaris system call,
      giving an improvment in run time, illustrated in the timings shown
      above.

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              bgomessunw Benedict Gomes (Inactive)
              Reporter:
              duke J. Duke (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: