9

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?

Cogsy
  • 5,584
  • 4
  • 35
  • 47

6 Answers6

5

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.

JWrapper support AOT https://www.jwrapper.com/features

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • I am not able to get it will compile the code further. please elaborate on this, and why only after 10000 times run, one can get the appropriate results for micro-benchmarking(average out) – lowLatency Mar 15 '13 at 19:31
  • The default "compiler threshold" is 10000. see `-XX:CompileThreshold=10000` This can mean the code is not fully optimised until it is run 10,000 and you may want to ignore these runs to get the best results. In any case I suggest running the test for at least 2-10 seconds. – Peter Lawrey Mar 16 '13 at 21:22
  • in that case if I give -XX:CompileThreshold=10, then we are good to test it for a loop of 10000(yup, I know it will run only for some millisecs only) – lowLatency Mar 16 '13 at 23:16
  • 1
    @PeterLawrey which JVMs support eager class loading? – caduceus Nov 23 '20 at 12:39
  • @caduceus I believe https://www.jwrapper.com/features support AOT and it is being added to the Gradle VM if it hasn't already. – Peter Lawrey Nov 23 '20 at 14:01
5

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
  • 60,850
  • 18
  • 118
  • 163
  • if one wants to load the classes, as and when Main class loads,he can import, what is the need of Class.forName – lowLatency Mar 15 '13 at 19:35
  • @Naroji importing is a compiler only thing, it does nothing at run time. – TofuBeer Mar 15 '13 at 20:11
  • Please validate... class can be loaded into jvm method area by a ClassLoader,Class.forName, or new Operator,DI,Factory(internally they all are using classLoader only) ... new,DI,Factory also creates object – lowLatency Mar 15 '13 at 20:39
  • All of those should do it. There is no need to create an instance of a class to get the class loaded though. System.out.println(X.staticVariable); for instance will cause the class to load. If you just want to get the class to load then doing Class.forName is all you need. – TofuBeer Mar 15 '13 at 22:23
4

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

This thread contains some solid advice: How do I write a correct micro-benchmark in Java?

Community
  • 1
  • 1
gustafc
  • 28,465
  • 7
  • 73
  • 99
3

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

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

akuhn
  • 27,477
  • 2
  • 76
  • 91
1

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
  • 145,806
  • 30
  • 211
  • 305
0

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
  • 48,893
  • 5
  • 92
  • 171