1 /*
2  * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   - Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *
11  *   - Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *   - Neither the name of Oracle nor the names of its
16  *     contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * This source code is provided to illustrate the usage of a given feature
34  * or technique and has been deliberately simplified. Additional steps
35  * required for a production-quality application, such as security checks,
36  * input validation and proper error handling, might not be present in
37  * this sample code.
38  */
39 
40 
41 package j2dbench;
42 
43 public abstract class Test extends Option.Enable {
44     private DependentLink dependencies;
45 
Test(Group parent, String nodeName, String description)46     public Test(Group parent, String nodeName, String description) {
47         super(parent, nodeName, description, false);
48     }
49 
addDependency(Modifier mod)50     public void addDependency(Modifier mod) {
51         addDependency(mod, null);
52     }
53 
addDependency(Modifier mod, Modifier.Filter filter)54     public void addDependency(Modifier mod, Modifier.Filter filter) {
55         dependencies = DependentLink.add(dependencies, mod, filter);
56     }
57 
addDependencies(Group g, boolean recursive)58     public void addDependencies(Group g, boolean recursive) {
59         addDependencies(g, recursive, null);
60     }
61 
addDependencies(Group g, boolean recursive, Modifier.Filter filter)62     public void addDependencies(Group g, boolean recursive,
63                                 Modifier.Filter filter)
64     {
65         if (g instanceof Modifier) {
66             addDependency((Modifier) g, filter);
67         }
68         for (Node n = g.getFirstChild(); n != null; n = n.getNext()) {
69             if (n instanceof Modifier) {
70                 addDependency((Modifier) n, filter);
71             } else if (recursive && n instanceof Group) {
72                 addDependencies((Group) n, recursive, filter);
73             }
74         }
75     }
76 
runTest(TestEnvironment env)77     public void runTest(TestEnvironment env) {
78         if (!env.isStopped() && isEnabled()) {
79             dependencies.recurseAndRun(env, this);
80         }
81     }
82 
runOneTest(TestEnvironment env)83     public void runOneTest(TestEnvironment env) {
84         if (!env.isStopped()) {
85             Result result = new Result(this);
86             env.erase();
87             Object ctx = initTest(env, result);
88             result.setModifiers(env.getModifiers());
89             try {
90                 runTestLoop(env, result, ctx);
91             } catch (Throwable t) {
92                 result.setError(t);
93             }
94             cleanupTest(env, ctx);
95             // Skip recording results if we were interrupted before
96             // anything interesting happened...
97             if (result.getError() != null || result.getNumRuns() != 0) {
98                 if (J2DBench.printresults.isEnabled()) {
99                     result.summarize();
100                 }
101                 env.record(result);
102             }
103             ctx = null;
104             result = null;
105             env.idle();  // Also done after this method returns...
106         }
107     }
108 
initTest(TestEnvironment env, Result result)109     public abstract Object initTest(TestEnvironment env, Result result);
runTest(Object context, int numReps)110     public abstract void runTest(Object context, int numReps);
cleanupTest(TestEnvironment env, Object context)111     public abstract void cleanupTest(TestEnvironment env, Object context);
112 
runTestLoop(TestEnvironment env, Result result, Object ctx)113     public void runTestLoop(TestEnvironment env, Result result, Object ctx) {
114         // Prime the pump
115         runTest(ctx, 1);
116 
117         // Determine the number of reps
118         int numReps = env.getRepCount();
119         if (numReps == 0) {
120             numReps = calibrate(env, ctx);
121         }
122         result.setReps(numReps);
123 
124         int numRuns = env.getRunCount();
125         for (int i = 0; i < numRuns; i++) {
126             if (env.idle()) {
127                 break;
128             }
129 
130             env.sync();
131             env.startTiming();
132             runTest(ctx, numReps);
133             env.sync();
134             env.stopTiming();
135             result.addTime(env.getTimeMillis());
136 
137             env.flushToScreen();
138         }
139     }
140 
calibrate(TestEnvironment env, Object ctx)141     public int calibrate(TestEnvironment env, Object ctx) {
142         long testTime = env.getTestTime();
143         int numReps = 0;
144         int totalReps = 0;
145 
146         // First do one at a time until we get to 1 second elapsed
147         // But, if we get to 1000 reps we'll start ramping up our
148         // reps per cycle and throwing sync() calls in to make sure
149         // we aren't spinning our gears queueing up graphics calls
150         env.idle();
151         long now = System.currentTimeMillis();
152         long startTime = now;
153         while (numReps < 1000 && now < startTime + 1000) {
154             runTest(ctx, 1);
155             numReps++;
156             now = System.currentTimeMillis();
157         }
158 
159         // Time to shift gears into an exponential number of tests
160         // sync() each time in case batching at a lower level is
161         // causing us to spin our gears
162         env.sync();
163         now = System.currentTimeMillis();
164         int reps = 250;
165         while (now < startTime + 1000) {
166             runTest(ctx, reps);
167             env.sync();
168             numReps += reps;
169             reps *= 2;
170             now = System.currentTimeMillis();
171         }
172 
173         // Now keep estimating how many reps it takes to hit our target
174         // time exactly, trying it out, and guessing again.
175         while (now < startTime + testTime) {
176             int estimate = (int) (numReps * testTime / (now - startTime));
177             if (estimate <= numReps) {
178                 estimate = numReps+1;
179             }
180             runTest(ctx, estimate - numReps);
181             numReps = estimate;
182             env.sync();
183             now = System.currentTimeMillis();
184         }
185 
186         // Now make one last estimate of how many reps it takes to
187         // hit the target exactly in case we overshot.
188         int estimate = (int) (numReps * testTime / (now - startTime));
189         if (estimate < 1) {
190             estimate = 1;
191         }
192         return estimate;
193     }
194 
195     /*
196      * Finds a new width (w2) such that
197      *     (w-2) <= w2 <= w
198      *     and w2 is not a multiple of 3 (the X step size)
199      *     and GCD(w2, h) is as small as possible
200      */
201     static int prevw;
adjustWidth(int w, int h)202     public static int adjustWidth(int w, int h) {
203         int bestv = w;
204         int bestw = w;
205         boolean verbose = (prevw != w && J2DBench.verbose.isEnabled());
206         for (int i = 0; i < 3; i++) {
207             int w2 = w-i;
208             int u = w2;
209             int v = h;
210             while (u > 0) {
211                 if (u < v) { int t = u; u = v; v = t; }
212                 u -= v;
213             }
214             if (verbose) {
215                 System.out.println("w = "+w2+", h = "+h+
216                                    ", w % 3 == "+(w2 % 3)+
217                                    ", gcd(w, h) = "+v);
218             }
219             if (v < bestv && (w2 % 3) != 0) {
220                 bestv = v;
221                 bestw = w2;
222             }
223         }
224         if (verbose) {
225             System.out.println("using "+bestw+" (gcd = "+bestv+")");
226             prevw = w;
227         }
228         return bestw;
229     }
230 
toString()231     public String toString() {
232         return "Test("+getTreeName()+")";
233     }
234 
235     public static class DependentLink {
add(DependentLink d, Modifier mod, Modifier.Filter filter)236         public static DependentLink add(DependentLink d, Modifier mod,
237                                         Modifier.Filter filter)
238         {
239             DependentLink dl = new DependentLink(mod, filter);
240             if (d == null) {
241                 d = dl;
242             } else {
243                 DependentLink last = d;
244                 while (last.next != null) {
245                     last = last.next;
246                 }
247                 last.next = dl;
248             }
249             return d;
250         }
251 
252         private DependentLink next;
253         private Modifier mod;
254         private Modifier.Filter filter;
255 
DependentLink(Modifier mod, Modifier.Filter filter)256         private DependentLink(Modifier mod, Modifier.Filter filter) {
257             this.mod = mod;
258             this.filter = filter;
259         }
260 
getModifier()261         public Modifier getModifier() {
262             return mod;
263         }
264 
getFilter()265         public Modifier.Filter getFilter() {
266             return filter;
267         }
268 
getNext()269         public DependentLink getNext() {
270             return next;
271         }
272 
recurseAndRun(TestEnvironment env, Test test)273         public void recurseAndRun(TestEnvironment env, Test test) {
274             Modifier.Iterator iter = mod.getIterator(env);
275             while (iter.hasNext()) {
276                 Object val = iter.next();
277                 if (filter == null || filter.isCompatible(val)) {
278                     mod.modifyTest(env, val);
279                     if (next == null) {
280                         test.runOneTest(env);
281                         env.idle();  // One more time outside of runOneTest()
282                     } else {
283                         next.recurseAndRun(env, test);
284                     }
285                     mod.restoreTest(env, val);
286                 }
287             }
288         }
289     }
290 }
291