JVM Tutorials - Herong's Tutorial Examples - Version 4.23, by Dr. Herong Yang
Revised BenchmarkRunner.java
This section provides the revised version of BenchmarkRunner.java. The report() method is revised to use Math.round() to report more accurate values.
After finished experimenting with the micro benchmark runner and different HotSpot JVM options, I am ready to do some real micro benchmark testing on my laptop now.
Before creating and running specific test methods, I have revised my benchmark runner program, BenchmarkRunner.java:
/** * BenchmarkRunner.java * Revised the report() method to use Math.round() * Copyright (c) 2010, HerongYang.com, All Rights Reserved. */ class BenchmarkRunner { static java.io.PrintStream out = System.out; static java.io.InputStream in = System.in; long startTime = 0; long endTime = 0; long[] timeRecords = null; public static void main(String[] a) { if (a.length<5) { out.println("Missing arguments. Usage: "); out.println( "BenchmarkRunner class method warmups runs steps"); return; } try { String className = a[0]; String methodName = a[1]; int numberOfWarmups = Integer.parseInt(a[2]); int numberOfRuns = Integer.parseInt(a[3]); int numberOfSteps = Integer.parseInt(a[4]); // Warming up the JVM out.println("Are you ready?"); in.read(new byte[1]); // Loading the benchmark class and method Class testClass = Class.forName(className); java.lang.reflect.Method testMethod = testClass.getMethod(methodName, int.class, BenchmarkRunner.class); BenchmarkRunner testRunner = new BenchmarkRunner(numberOfRuns); Object testObject = testClass.newInstance(); // JIT warmup out.println(); out.println("Waking up the JIT compiler..."); for (int i=1; i<=numberOfWarmups; i++) { Object testResult = testMethod.invoke(testObject, numberOfSteps, testRunner); out.println("Run: "+i+", Time: "+testRunner.returnTime() +", Test returns: "+testResult); } // Benchmark runs out.println(); out.println("Starting benchmark test runs..."); for (int i=1; i<=numberOfRuns; i++) { Object testResult = testMethod.invoke(testObject, numberOfSteps, testRunner); testRunner.recordTime(i); out.println("Run: "+i+", Time: "+testRunner.returnTime() +", Test returns: "+testResult); } // Benchmark report out.println(); out.println("Benchmark test time report..."); testRunner.report(numberOfRuns, numberOfSteps); } catch (Exception e) { e.printStackTrace(); } } // Constructor public BenchmarkRunner(int runs) { timeRecords = new long[runs]; } // Starting the timer - to be called by test method public void startTimer() { startTime = System.nanoTime(); } // Stopping the timer - to be called by test method public void stopTimer() { endTime = System.nanoTime(); } // Returning time from the timer public long returnTime() { return endTime - startTime; } // Recording time from the timer public void recordTime(int i) { timeRecords[i-1] = endTime - startTime; } // Reportting benchmark result public void report(int runs, int steps) { long total = 0; long minimum = Long.MAX_VALUE; long maximum = 0; for (int i=0; i<runs; i++) { long t = timeRecords[i]; total += t; if (t>maximum) maximum = t; if (t<minimum) minimum = t; } long average = Math.round(total/(double) runs); out.println("Runs: "+runs +", Ave: "+Math.round(average/(double) steps) +", Min: "+Math.round(minimum/(double) steps) +", Max: "+Math.round(maximum/(double) steps) +" - Per step in nanoseconds"); out.println("Runs: "+runs+", Ave: "+average +", Min: "+minimum+", Max: "+maximum +" - All steps in nanoseconds"); out.println("Runs: "+runs +", Ave: "+Math.round(average/1000000.0) +", Min: "+Math.round(minimum/1000000.0) +", Max: "+Math.round(maximum/1000000.0) +" - All steps in milliseconds"); out.println("Runs: "+runs +", Ave: "+Math.round(average/1000000000.0) +", Min: "+Math.round(minimum/1000000000.0) +", Max: "+Math.round(maximum/1000000000.0) +" - All steps in seconds"); } // Constructor needed as a sample benchmark test class public BenchmarkRunner() { } // A sample benchmark test method public static long sampleTest(int steps, BenchmarkRunner runner) { long total = 0; runner.startTimer(); for (int i=0; i<steps; i++) { total += i; } runner.stopTimer(); return total; } }
As you can see from the source code, the report() method has been revised to use Math.round() to make reported values more accurate.
Last update: 2010.
Table of Contents
Downloading and Installing JDK 1.8.0 on Windows
Downloading and Installing JDK 1.7.0 on Windows
java.lang.Runtime Class - The JVM Instance
java.lang.System Class - The Operating System
ClassLoader Class - Class Loaders
Class Class - Class Reflections
JRockit JVM 28.2.7 by Oracle Corporation
Memory Management and Garbage Collectors
JVM Stack, Frame and Stack Overflow
Thread Testing Program and Result
CPU Impact of Multi-Thread Applications
I/O Impact of Multi-Thread Applications
Micro Benchmark Runner and JVM Options
►Micro Benchmark Tests on "int" Operations
Hardware, OS and JVM Configurations
"int" Empty Loop: 16 Nanoseconds per Step
"int" Assignment Only: 14 Nanoseconds per Step
"int" Shift and Assignment: 17 Nanoseconds per Step
"int" Add and Assignment: 17 Nanoseconds per Step
"int" Multiply and Assignment: 17 Nanoseconds per Step
"int" Division and Assignment: 19 Nanoseconds per Step
Micro Benchmark Tests on "long" Operations
Micro Benchmark Tests in JIT Compilation Mode