Is Java Slower on Solaris than Windows?

Discussions

Performance and scalability: Is Java Slower on Solaris than Windows?

  1. Is Java Slower on Solaris than Windows? (4 messages)

    As part of my job, I have been writing some Java code to do some pretty complex data moving and processing, and was getting great performance results on my laptop. The next step was to test the performance on a "Production" system - usually thought of as Unix/Linux. The first test was on Solaris. To my disappointment, the numbers weren't that great.

    So I created a little benchmark class (others must have also done this before, but nothing was handy) to rule out any of the processing and test the performance of basic functions.

    This class does 5 things:

    1) A simple for loop with a billion iterations
    2) A loop doing simple FP processing (d = 34.0, for(..) d= (d* 23.7)/56.9
    3) Writing a 50MB filling it with ASCII '0123456789' repeated
    4) Reading that file using fis.read()
    5) Reading the file using a 1MB memory map block read

    The results I got kind of shocked me, so I was wondering if anyone could shed any light on them. Both of these results are using exactly the same code, JSDK1.4.2, and the same VM params (Client [HotSpot] mode).

    Windows XP on my Laptop: Dell Latitude 600, 1.6GHz, 1GB Ram

        Starting Benchmark
        Counting to 1,000,000,000...took 5060ms
        Doing 500,000,000 FP ops...took 6320ms
        Writing a 50MB file...took 7043ms
        Reading the 50MB file using FIS.read...took 1893ms
        Reading the 50MB file using ByteBuffer...took 531ms

    Sun-Fire-V440 Solaris 5.10, 2x1GHz, 4GB Ram

        Starting Benchmark
        Counting to 1,000,000,000...took 16753ms
        Doing 500,000,000 FP ops...took 14140ms
        Writing a 50MB file...took 2031ms
        Reading the 50MB file using FIS.read...took 7058ms
        Reading the 50MB file using ByteBuffer...took 1430ms

    So the basic iterations were 3 1/2 times slower, writing a file 3 1/2 times faster, but reading 3 1/2 times slower on Solaris than Windows.

    If anyone could repeat this test and past the results as comments here, I'd really appreciate it. I would like to know if this is expected behavior for Solaris, or if our machine needs its kernel tuned. I have also tried it on our AIX, Linux and HP-UX machines, using Xeon and Itanium processors and gotten equally disappointing results.

    This article is copied in my blog together with a link to download the Java File. I'm going to do some more research, but would love to find out how other peoples systems perform.

    Threaded Messages (4)

  2. it's not the O/S...[ Go to top ]

    i'm spearheading a transition of my company's commercial java products onto the Opteron platform. The Sparc cpu's are just slow. some of my benchmarks show that applications on a system with the 2.2Ghz Opteron is ~3 times faster than the 1.5Ghz Sparc IIIi, with same memory. Of course, when it comes to disks, you can always optimize with RAID (etc) to suit your purposes. Solaris rocks though (porting from Sparc to x64 was a breeze).
  3. I've updated the BenchMark to have usual basic operations and FP testing that are not optimized out by the -server flag. I also added a large array and CRC64 test.

    What I really want to do is improve the file reading performance and basic operations for Java on Solaris (Sparc). Any pointers would be greatly appreciated.
  4. scanning bytebuffers[ Go to top ]

    I modified your code to do some real work, in this case scanning the file for the ascii code for "5", which is 53.

       {

                _resetBuffer();

                System.out.print("Reading the 50MB file using ByteBuffer...");

                start = (new Date()).getTime();

                FileInputStream fis = null;

                int k = 0;

                try {

                    fis = new FileInputStream("/tmp/test.txt");

                    byte[] buffer = new byte[50];

                    while (_readUsingBuffer(fis, buffer) != -1) {

                        for (int i = 0; i < buffer.length; i++) {

                            if (buffer[i] == 53) {

                                k++;

                            }

                        }

                    }

                } catch (Exception e) {

                    System.err.println("Exception: " + e);

                    e.printStackTrace();

                } finally {

                    try {

                        fis.close();

                    } catch (Exception ee) {

                    }

                }

                end = (new Date()).getTime();

                System.out.println("took " + (end - start) + "ms, found " + k

                        + " fives.");

            }



            {

                _resetBuffer();

                System.out.print("Reading the 50MB file using ByteBuffer...");

                start = (new Date()).getTime();

                FileInputStream fis = null;

                int k = 0;

                try {

                    fis = new FileInputStream("/tmp/test.txt");

                    fChannel = fis.getChannel();

                    long pos = 0;

                    long bSize = 5 * 1024 * 1024;

                    long fcSize = fChannel.size();



                    while (pos < fChannel.size()) {

                        if (pos + bSize > fcSize) {

                            bSize = fcSize - pos;

                        }

                        MappedByteBuffer mBuf = fChannel.map(

                            FileChannel.MapMode.READ_ONLY, pos, bSize);

                        ByteBuffer bBuf = mBuf.asReadOnlyBuffer();

                        while (bBuf.hasRemaining()) {

                            if (bBuf.get() == 53) {

                                k++;

                            }

                        }

                        pos += bSize;

                    }

                } catch (Exception e) {

                    System.err.println("Exception: " + e);

                    e.printStackTrace();

                } finally {

                    try {

                        fis.close();

                    } catch (Exception ee) {

                    }

                }

                end = (new Date()).getTime();

                System.out.println("took " + (end - start) + "ms, found " + k

                        + " fives.");

            }


    Then I wrote another scan method using idioms straight out of the nio examples from java.sun.com, and the results were quite different:

    1062ms scanning with byte array copies of length 50.
    590ms scanning using a mapped byte buffer and one byte at a time.

    Almost half the time. This was done on Linux 2.6.8, 1.4.2 JVM, on a P4 3.0E (prescott). I think you might find that solaris would be happier if you scanned the bytes or did whatever work you needed to do against the byte buffer directly, as opposed to slowly copying it back into primitive bytes.
  5. scanning bytebuffers[ Go to top ]

    Thanks for the suggestion. I guess what is missing in my posts is the context of the problem. The benchmark was constructed to test certain aspect of the actual app I am writing. Reading a byte array of length n from a file is part of the app, reading individual bytes is not. So, although this may be faster, it doesn't really help in my case.

    I also tested your code on my laptop, and interestingly get exactly the opposite results, with the almost the same speed. My laptop is only a 1.6GHz and has a laptop hard-drive, which has to be slower than your linux machine (doesn't it):

    Finding fives scanning byte array copies of length 50...took 640ms, found 5242060 fives.
    Finding fives using mapped byte buffer a byte at a time...took 1051ms, found 5242061 fives.

    On the Solaris box:
    Finding fives scanning byte array copies of length 50...took 1415ms, found 5242060 fives.
    Finding fives using mapped byte buffer a byte at a time...took 1659ms, found 5242061 fives.

    Must be something about the Linux JVM or filesystem. With the fastest method here I'm still getting Solaris file reading less than half as fast as my laptop.