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
35import java.util.*;
36
37public 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 unused) {
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 unused) {
194                            throw new ClassCastException(); }}}}}
195        };
196
197        time(filter(filter, jobs));
198    }
199}
200