tags:

views:

444

answers:

6

I'm trying to do some benchmarking of JVMs running on various hardware and OS platforms. I've created an algorithm to exercise the parts of the JVM I'm interested in and intend to run this algorithm many times to find a decent average.

When I run the benchmark, I find that the first run is significantly longer than subsequent runs:

132ms
86ms
77ms
89ms
72ms

My suspicion is that classes are loaded lazily, putting a large overhead on the first run. While this is indeed a feature that I assume is unique to each JVM, it's not one I'm interested in at this point.

Is there a standard command line option or property to eagerly load classes? or does anyone have any other theories?

+4  A: 

The simplest thing to do is ignore the first run. (If that is a valid thing to do) Note: if you run the same code 10,000 times, it will compile the code further and you get better results, so you might want to ignore the first 10K results for some micro-benchmarks.

Some JVMs support eager loading but I don't think Sun's JVM does.

Peter Lawrey
A: 

Use java -XX:+TraceClassLoading to trace the loading of classes.

Use java -XX:+PrintCompilation to trace when methods are JITed.

Adrian
A: 

There isn't a standard command line option, since that's not part of the JVM spec. Lazy class loading is (explicitly allowed as) part of the JVM spec. It would be possible to use Class.forName() before the run to load the classes you know about, but it's not automatically transitive.

HotSpot compilation will also effect the first few runs - a method is interpreted a few times before being compiled, and the compilation process takes some time.

Pete Kirkham
+2  A: 

Rule #1 for Java benchmarking: The first 15000 times (or so) a method runs aren't interesting.

This thread contains some solid advice: http://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java

gustafc
+1  A: 

If you want to force the classes to be loaded do something like this:

public class Main
{
    static
    {
        loadClasses();
    }

    public static void main(final String[] argv)
    {
        // whatever
    }

    private static void loadClasses()
    {
        final String[] classesToLoad;

        // even better, read them from a file and pass the filename to this method
        classesToLoad = new String[]
        {
            "foo.bar.X",
            "foo.bar.Y",
        }

        for(final String className : classesToLoad)
        {
            try
            {
                // load the class
                Class.forName(className);
            }
            catch(final ClassNotFoundException ex)
            {
                // do something that makes sense here
                ex.printStackTrace();
            }
        }
    }
}
TofuBeer
A: 

Once you have the classes loaded, to avoid running the interpreter use -Xcomp (on Sun implementations) to run compiled code only. It can be very slow running normal applications this way as all of the code has to be compiled rather than just a few pieces.

Tom Hawtin - tackline