1 /*
   2  * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * This is not a regression test, but a micro-benchmark.
  26  *
  27  * I have run this as follows:
  28  *
  29  * repeat 5 for f in -client -server; do mergeBench dolphin . jr -dsa -da $f TypeCheckMicroBenchmark.java; done
  30  *
  31  *
  32  * @author Martin Buchholz
  33  */
  34 
  35 import java.util.*;
  36 
  37 public class TypeCheckMicroBenchmark {
  38     abstract static class Job {
  39         private final String name;
  40         Job(String name) { this.name = name; }
  41         String name() { return name; }
  42         abstract void work() throws Throwable;
  43     }
  44 
  45     private static void collectAllGarbage() {
  46         final java.util.concurrent.CountDownLatch drained
  47             = new java.util.concurrent.CountDownLatch(1);
  48         try {
  49             System.gc();        // enqueue finalizable objects
  50             new Object() { protected void finalize() {
  51                 drained.countDown(); }};
  52             System.gc();        // enqueue detector
  53             drained.await();    // wait for finalizer queue to drain
  54             System.gc();        // cleanup finalized objects
  55         } catch (InterruptedException e) { throw new Error(e); }
  56     }
  57 
  58     /**
  59      * Runs each job for long enough that all the runtime compilers
  60      * have had plenty of time to warm up, i.e. get around to
  61      * compiling everything worth compiling.
  62      * Returns array of average times per job per run.
  63      */
  64     private static long[] time0(Job ... jobs) throws Throwable {
  65         final long warmupNanos = 10L * 1000L * 1000L * 1000L;
  66         long[] nanoss = new long[jobs.length];
  67         for (int i = 0; i < jobs.length; i++) {
  68             collectAllGarbage();
  69             long t0 = System.nanoTime();
  70             long t;
  71             int j = 0;
  72             do { jobs[i].work(); j++; }
  73             while ((t = System.nanoTime() - t0) < warmupNanos);
  74             nanoss[i] = t/j;
  75         }
  76         return nanoss;
  77     }
  78 
  79     private static void time(Job ... jobs) throws Throwable {
  80 
  81         long[] warmup = time0(jobs); // Warm up run
  82         long[] nanoss = time0(jobs); // Real timing run
  83         long[] milliss = new long[jobs.length];
  84         double[] ratios = new double[jobs.length];
  85 
  86         final String nameHeader   = "Method";
  87         final String millisHeader = "Millis";
  88         final String ratioHeader  = "Ratio";
  89 
  90         int nameWidth   = nameHeader.length();
  91         int millisWidth = millisHeader.length();
  92         int ratioWidth  = ratioHeader.length();
  93 
  94         for (int i = 0; i < jobs.length; i++) {
  95             nameWidth = Math.max(nameWidth, jobs[i].name().length());
  96 
  97             milliss[i] = nanoss[i]/(1000L * 1000L);
  98             millisWidth = Math.max(millisWidth,
  99                                    String.format("%d", milliss[i]).length());
 100 
 101             ratios[i] = (double) nanoss[i] / (double) nanoss[0];
 102             ratioWidth = Math.max(ratioWidth,
 103                                   String.format("%.3f", ratios[i]).length());
 104         }
 105 
 106         String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
 107                                       nameWidth, millisWidth, ratioWidth);
 108         String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
 109                                             nameWidth, millisWidth, ratioWidth);
 110         System.out.printf(headerFormat, "Method", "Millis", "Ratio");
 111 
 112         // Print out absolute and relative times, calibrated against first job
 113         for (int i = 0; i < jobs.length; i++)
 114             System.out.printf(format, jobs[i].name(), milliss[i], ratios[i]);
 115     }
 116 
 117     private static String keywordValue(String[] args, String keyword) {
 118         for (String arg : args)
 119             if (arg.startsWith(keyword))
 120                 return arg.substring(keyword.length() + 1);
 121         return null;
 122     }
 123 
 124     private static int intArg(String[] args, String keyword, int defaultValue) {
 125         String val = keywordValue(args, keyword);
 126         return val == null ? defaultValue : Integer.parseInt(val);
 127     }
 128 
 129     private static java.util.regex.Pattern patternArg(String[] args,
 130                                                       String keyword) {
 131         String val = keywordValue(args, keyword);
 132         return val == null ? null : java.util.regex.Pattern.compile(val);
 133     }
 134 
 135     private static Job[] filter(java.util.regex.Pattern filter,
 136                                 Job[] jobs) {
 137         if (filter == null) return jobs;
 138         Job[] newJobs = new Job[jobs.length];
 139         int n = 0;
 140         for (Job job : jobs)
 141             if (filter.matcher(job.name()).find())
 142                 newJobs[n++] = job;
 143         // Arrays.copyOf not available in JDK 5
 144         Job[] ret = new Job[n];
 145         System.arraycopy(newJobs, 0, ret, 0, n);
 146         return ret;
 147     }
 148 
 149     /**
 150      * Usage: [iterations=N] [size=N] [filter=REGEXP]
 151      */
 152     public static void main(String[] args) throws Throwable {
 153         final int iterations = intArg(args, "iterations", 30000);
 154         final int size       = intArg(args, "size", 1000);
 155         final java.util.regex.Pattern filter
 156             = patternArg(args, "filter");
 157 
 158         final List<Integer> list = new ArrayList<Integer>();
 159         final Random rnd = new Random();
 160         for (int i = 0; i < size; i++)
 161             list.add(rnd.nextInt());
 162         final Class klazz = Integer.class;
 163 
 164         final Job[] jobs = {
 165             new Job("toArray(T[])") { void work() {
 166                 Object[] a = new Integer[0];
 167                 for (int i = 0; i < iterations; i++) {
 168                     try { list.toArray(a); }
 169                     catch (ArrayStoreException ase) {
 170                         throw new ClassCastException(); }}}},
 171             new Job("isInstance") { void work() {
 172                 for (int i = 0; i < iterations; i++) {
 173                     for (Object x : list.toArray())
 174                         if (! (x != null && klazz.isInstance(x)))
 175                             throw new ClassCastException(); }}},
 176             new Job("Class.cast") { void work() {
 177                 for (int i = 0; i < iterations; i++) {
 178                     for (Object x : list.toArray())
 179                         klazz.cast(x); }}},
 180             new Job("write into array") { void work() {
 181                 Object[] a = new Integer[1];
 182                 for (int i = 0; i < iterations; i++) {
 183                     for (Object x : list.toArray()) {
 184                         try { a[0] = x; }
 185                         catch (ArrayStoreException ignore) {
 186                             throw new ClassCastException(); }}}}},
 187             new Job("write into dynamic array") { void work() {
 188                 for (int i = 0; i < iterations; i++) {
 189                     for (Object x : list.toArray()) {
 190                         Object[] a = (Object[])
 191                             java.lang.reflect.Array.newInstance(klazz, 1);
 192                         try { a[0] = x; }
 193                         catch (ArrayStoreException ignore) {
 194                             throw new ClassCastException(); }}}}}
 195         };
 196 
 197         time(filter(filter, jobs));
 198     }
 199 }