| /* |
| * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * - Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * - Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * - Neither the name of Oracle nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
| * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /* |
| * This source code is provided to illustrate the usage of a given feature |
| * or technique and has been deliberately simplified. Additional steps |
| * required for a production-quality application, such as security checks, |
| * input validation and proper error handling, might not be present in |
| * this sample code. |
| */ |
| |
| |
| package j2dbench; |
| |
| public abstract class Test extends Option.Enable { |
| private DependentLink dependencies; |
| |
| public Test(Group parent, String nodeName, String description) { |
| super(parent, nodeName, description, false); |
| } |
| |
| public void addDependency(Modifier mod) { |
| addDependency(mod, null); |
| } |
| |
| public void addDependency(Modifier mod, Modifier.Filter filter) { |
| dependencies = DependentLink.add(dependencies, mod, filter); |
| } |
| |
| public void addDependencies(Group g, boolean recursive) { |
| addDependencies(g, recursive, null); |
| } |
| |
| public void addDependencies(Group g, boolean recursive, |
| Modifier.Filter filter) |
| { |
| if (g instanceof Modifier) { |
| addDependency((Modifier) g, filter); |
| } |
| for (Node n = g.getFirstChild(); n != null; n = n.getNext()) { |
| if (n instanceof Modifier) { |
| addDependency((Modifier) n, filter); |
| } else if (recursive && n instanceof Group) { |
| addDependencies((Group) n, recursive, filter); |
| } |
| } |
| } |
| |
| public void runTest(TestEnvironment env) { |
| if (!env.isStopped() && isEnabled()) { |
| dependencies.recurseAndRun(env, this); |
| } |
| } |
| |
| public void runOneTest(TestEnvironment env) { |
| if (!env.isStopped()) { |
| Result result = new Result(this); |
| env.erase(); |
| Object ctx = initTest(env, result); |
| result.setModifiers(env.getModifiers()); |
| try { |
| runTestLoop(env, result, ctx); |
| } catch (Throwable t) { |
| result.setError(t); |
| } |
| cleanupTest(env, ctx); |
| // Skip recording results if we were interrupted before |
| // anything interesting happened... |
| if (result.getError() != null || result.getNumRuns() != 0) { |
| if (J2DBench.printresults.isEnabled()) { |
| result.summarize(); |
| } |
| env.record(result); |
| } |
| ctx = null; |
| result = null; |
| env.idle(); // Also done after this method returns... |
| } |
| } |
| |
| public abstract Object initTest(TestEnvironment env, Result result); |
| public abstract void runTest(Object context, int numReps); |
| public abstract void cleanupTest(TestEnvironment env, Object context); |
| |
| public void runTestLoop(TestEnvironment env, Result result, Object ctx) { |
| // Prime the pump |
| runTest(ctx, 1); |
| |
| // Determine the number of reps |
| int numReps = env.getRepCount(); |
| if (numReps == 0) { |
| numReps = calibrate(env, ctx); |
| } |
| result.setReps(numReps); |
| |
| int numRuns = env.getRunCount(); |
| for (int i = 0; i < numRuns; i++) { |
| if (env.idle()) { |
| break; |
| } |
| |
| env.sync(); |
| env.startTiming(); |
| runTest(ctx, numReps); |
| env.sync(); |
| env.stopTiming(); |
| result.addTime(env.getTimeMillis()); |
| |
| env.flushToScreen(); |
| } |
| } |
| |
| public int calibrate(TestEnvironment env, Object ctx) { |
| long testTime = env.getTestTime(); |
| int numReps = 0; |
| int totalReps = 0; |
| |
| // First do one at a time until we get to 1 second elapsed |
| // But, if we get to 1000 reps we'll start ramping up our |
| // reps per cycle and throwing sync() calls in to make sure |
| // we aren't spinning our gears queueing up graphics calls |
| env.idle(); |
| long now = System.currentTimeMillis(); |
| long startTime = now; |
| while (numReps < 1000 && now < startTime + 1000) { |
| runTest(ctx, 1); |
| numReps++; |
| now = System.currentTimeMillis(); |
| } |
| |
| // Time to shift gears into an exponential number of tests |
| // sync() each time in case batching at a lower level is |
| // causing us to spin our gears |
| env.sync(); |
| now = System.currentTimeMillis(); |
| int reps = 250; |
| while (now < startTime + 1000) { |
| runTest(ctx, reps); |
| env.sync(); |
| numReps += reps; |
| reps *= 2; |
| now = System.currentTimeMillis(); |
| } |
| |
| // Now keep estimating how many reps it takes to hit our target |
| // time exactly, trying it out, and guessing again. |
| while (now < startTime + testTime) { |
| int estimate = (int) (numReps * testTime / (now - startTime)); |
| if (estimate <= numReps) { |
| estimate = numReps+1; |
| } |
| runTest(ctx, estimate - numReps); |
| numReps = estimate; |
| env.sync(); |
| now = System.currentTimeMillis(); |
| } |
| |
| // Now make one last estimate of how many reps it takes to |
| // hit the target exactly in case we overshot. |
| int estimate = (int) (numReps * testTime / (now - startTime)); |
| if (estimate < 1) { |
| estimate = 1; |
| } |
| return estimate; |
| } |
| |
| /* |
| * Finds a new width (w2) such that |
| * (w-2) <= w2 <= w |
| * and w2 is not a multiple of 3 (the X step size) |
| * and GCD(w2, h) is as small as possible |
| */ |
| static int prevw; |
| public static int adjustWidth(int w, int h) { |
| int bestv = w; |
| int bestw = w; |
| boolean verbose = (prevw != w && J2DBench.verbose.isEnabled()); |
| for (int i = 0; i < 3; i++) { |
| int w2 = w-i; |
| int u = w2; |
| int v = h; |
| while (u > 0) { |
| if (u < v) { int t = u; u = v; v = t; } |
| u -= v; |
| } |
| if (verbose) { |
| System.out.println("w = "+w2+", h = "+h+ |
| ", w % 3 == "+(w2 % 3)+ |
| ", gcd(w, h) = "+v); |
| } |
| if (v < bestv && (w2 % 3) != 0) { |
| bestv = v; |
| bestw = w2; |
| } |
| } |
| if (verbose) { |
| System.out.println("using "+bestw+" (gcd = "+bestv+")"); |
| prevw = w; |
| } |
| return bestw; |
| } |
| |
| public String toString() { |
| return "Test("+getTreeName()+")"; |
| } |
| |
| public static class DependentLink { |
| public static DependentLink add(DependentLink d, Modifier mod, |
| Modifier.Filter filter) |
| { |
| DependentLink dl = new DependentLink(mod, filter); |
| if (d == null) { |
| d = dl; |
| } else { |
| DependentLink last = d; |
| while (last.next != null) { |
| last = last.next; |
| } |
| last.next = dl; |
| } |
| return d; |
| } |
| |
| private DependentLink next; |
| private Modifier mod; |
| private Modifier.Filter filter; |
| |
| private DependentLink(Modifier mod, Modifier.Filter filter) { |
| this.mod = mod; |
| this.filter = filter; |
| } |
| |
| public Modifier getModifier() { |
| return mod; |
| } |
| |
| public Modifier.Filter getFilter() { |
| return filter; |
| } |
| |
| public DependentLink getNext() { |
| return next; |
| } |
| |
| public void recurseAndRun(TestEnvironment env, Test test) { |
| Modifier.Iterator iter = mod.getIterator(env); |
| while (iter.hasNext()) { |
| Object val = iter.next(); |
| if (filter == null || filter.isCompatible(val)) { |
| mod.modifyTest(env, val); |
| if (next == null) { |
| test.runOneTest(env); |
| env.idle(); // One more time outside of runOneTest() |
| } else { |
| next.recurseAndRun(env, test); |
| } |
| mod.restoreTest(env, val); |
| } |
| } |
| } |
| } |
| } |