// $Id: performance.java,v 1.8 1998/09/23 06:30:18 oliva Exp $ /* Copyright 1998 Alexandre Oliva * * This file is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ import java.util.Hashtable; import java.util.Vector; /** * This program times several Java operations. * * @author Alexandre Oliva * @version $Revision: 1.8 $ */ public class performance { static finaltest object = statictest.createFinal(); static int[] array = statictest.createArray(); static class statictest { static int i; static void test() {} static finaltest createFinal() { return new finaltest(); } static Object createObject() { return new Object(); } static int[] createArray() { return new int[1]; } static long createObject(int count) { Object o = new Object(); long start = System.currentTimeMillis(); while(count-- > 0) { o = new Object(); } return System.currentTimeMillis() - start; } static long createArray(int count) { Object o = new int[1]; long start = System.currentTimeMillis(); while(count-- > 0) { o = new int[1]; } return System.currentTimeMillis() - start; } static long createMultiArray(int count) { Object o = new int[1][1]; long start = System.currentTimeMillis(); while(count-- > 0) { o = new int[1][1]; } return System.currentTimeMillis() - start; } } static interface interfacetest { void test(); } static class virtualtest implements interfacetest { int i; public void test() {} } static class finaltest extends virtualtest { private void ftest() {} static long finalMethodRun(int count) { finaltest o = object; o.ftest(); long start = System.currentTimeMillis(); while(count-- > 0) o.ftest(); return System.currentTimeMillis() - start; } } static interface test { long run(int count); } static final test[] tests = new test[] { new test() { public String toString() { return "getTime"; } public long run(int count) { System.currentTimeMillis(); long start = System.currentTimeMillis(); while(--count > 0) { /* --count, not count--, because we run it once more in the return statement! */ System.currentTimeMillis(); } return System.currentTimeMillis() - start; } }, new test() { public String toString() { return "emptyloop"; } public long run(int count) { System.currentTimeMillis(); long start = System.currentTimeMillis(); while(count-- > 0) { ; } return System.currentTimeMillis() - start; } }, new test() { public String toString() { return "monitorenter/exit"; } public long run(int count) { Class c = statictest.class; synchronized(c) {} long start = System.currentTimeMillis(); while(count-- > 0) { synchronized(c) {} } return System.currentTimeMillis() - start; } }, new test() { public String toString() { return "invokestatic"; } public long run(int count) { statictest.test(); long start = System.currentTimeMillis(); while(count-- > 0) { statictest.test(); } return System.currentTimeMillis() - start; } }, new test() { public String toString() { return "invokespecial"; } public long run(int count) { return finaltest.finalMethodRun(count); } }, new test() { public String toString() { return "invokevirtual"; } public long run(int count) { virtualtest o = object; o.test(); long start = System.currentTimeMillis(); while(count-- > 0) { o.test(); } return System.currentTimeMillis() - start; } }, new test() { public String toString() { return "invokeinterface"; } public long run(int count) { interfacetest o = object; o.test(); long start = System.currentTimeMillis(); while(count-- > 0) { o.test(); } return System.currentTimeMillis() - start; } }, new test() { public String toString() { return "getstatic"; } public long run(int count) { int j = statictest.i; long start = System.currentTimeMillis(); while(count-- > 0) { j = statictest.i; } return System.currentTimeMillis() - start; } }, new test() { public String toString() { return "putstatic"; } public long run(int count) { int j = 0; statictest.i = j; long start = System.currentTimeMillis(); while(count-- > 0) { statictest.i = j; } return System.currentTimeMillis() - start; } }, new test() { public String toString() { return "getfield"; } public long run(int count) { virtualtest o = object; int j = o.i; long start = System.currentTimeMillis(); while(count-- > 0) { j = o.i; } return System.currentTimeMillis() - start; } }, new test() { public String toString() { return "putfield"; } public long run(int count) { virtualtest o = object; int j = 0; o.i = j; long start = System.currentTimeMillis(); while(count-- > 0) { o.i = j; } return System.currentTimeMillis() - start; } }, new test() { public String toString() { return "arraylength"; } public long run(int count) { int[] a = array; int j = a.length; long start = System.currentTimeMillis(); while(count-- > 0) { j = a.length; } return System.currentTimeMillis() - start; } }, new test() { public String toString() { return "iaload"; } public long run(int count) { int[] a = array; int j = a[0]; long start = System.currentTimeMillis(); while(count-- > 0) { j = a[0]; } return System.currentTimeMillis() - start; } }, new test() { public String toString() { return "iastore"; } public long run(int count) { int[] a = array; int j = 0; a[0] = j; long start = System.currentTimeMillis(); while(count-- > 0) { a[0] = j; } return System.currentTimeMillis() - start; } }, new test() { public String toString() { return "new/invokespecial"; } public long run(int count) { return statictest.createObject(count); } }, new test() { public String toString() { return "newarray"; } public long run(int count) { return statictest.createArray(count); } }, new test() { public String toString() { return "multianewarray"; } public long run(int count) { return statictest.createMultiArray(count); } }, new test() { public String toString() { return "println"; } public long run(int count) { System.out.println("Hello world!"); long start = System.currentTimeMillis(); while(count-- > 0) { System.out.println("Hello world!"); } return System.currentTimeMillis() - start; } } }; static final Hashtable table = new Hashtable(); static { for(int i = 0, e = tests.length; i < e; ++i) table.put(tests[i].toString(), tests[i]); } public static void main(String [ ] argv) throws NumberFormatException { if (argv.length == 0) for(int i = 0, e = tests.length; i < e; ++i) runtestAndPrint(tests[i]); else if (argv.length == 1 && "--list".equals(argv[0])) for(int i = 0, e = tests.length; i < e; ++i) System.out.println(tests[i]); else for(int i = 0, e = argv.length; i < e; ++i) { if ("--total".equals(argv[i])) total = Double.valueOf(argv[++i]).doubleValue(); else if ("--cycle".equals(argv[i])) cycle = Double.valueOf(argv[++i]).doubleValue(); else if ("--time".equals(argv[i])) esttime = 1e3*Double.valueOf(argv[++i]).doubleValue(); else if ("--tolerance".equals(argv[i])) tolerance = 1e3*Double.valueOf(argv[++i]).doubleValue(); else if ("--all".equals(argv[i])) main(new String[0]); else if ("--nostat".equals(argv[i])) stat = false; else try { runtestAndPrint((test)table.get(argv[i])); } catch (NullPointerException p) { System.err.println("Ignoring invalid argument: " + argv[i]); } } } /** The total overhead per full loop, in seconds. */ static double total = 0; /** The overhead per loop iteration, in seconds. */ static double cycle = 0; /** The total loop time to aim at, in milliseconds. */ static double esttime = 1100; /** The minimum loop time to accept, in milliseconds. */ static double tolerance = 1000; /** Controls whether we're going to actually measure the tests and print their results. The --nostat command-line argument disables this variable, so that no output will be produced, and every test will be executed only once. This is used by a separate script that produces the assembly code generated for each test. */ static boolean stat = true; static void runtestAndPrint(test t) { if (stat) System.err.print(t + ": "); double avgtime = runtest(t, null); if (stat) System.err.println(avgtime); } static double runtest(test t, Vector sizelist) { int count = 1; long time = 0; do { if (sizelist != null) sizelist.addElement(new Integer(count)); if ((time = t.run(count)) > tolerance) break; if (time == 0) count *= 10; else count = (int)(count * esttime / (time - total - count * cycle)); } while(stat); return (t.run(count)*1e-3 - total)/count - cycle; } }