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
41package j2dbench;
42
43import java.util.Vector;
44import java.util.Hashtable;
45import java.util.Enumeration;
46import java.io.PrintWriter;
47import java.util.HashMap;
48
49public class Result {
50    public static final int RATE_UNKNOWN    = 0;
51
52    public static final int WORK_OPS        = 1;
53    public static final int WORK_UNITS      = 2;
54    public static final int WORK_THOUSANDS  = 4;
55    public static final int WORK_MILLIONS   = 6;
56    public static final int WORK_AUTO       = 8;
57
58    public static final int TIME_SECONDS    = 10;
59    public static final int TIME_MILLIS     = 11;
60    public static final int TIME_MICROS     = 12;
61    public static final int TIME_NANOS      = 13;
62    public static final int TIME_AUTO       = 14;
63
64    static Group resultoptroot;
65    static Option.ObjectChoice timeOpt;
66    static Option.ObjectChoice workOpt;
67    static Option.ObjectChoice rateOpt;
68
69    public static void init() {
70        resultoptroot = new Group(TestEnvironment.globaloptroot,
71                                  "results", "Result Options");
72
73        String workStrings[] = {
74            "units",
75            "kilounits",
76            "megaunits",
77            "autounits",
78            "ops",
79            "kiloops",
80            "megaops",
81            "autoops",
82        };
83        String workDescriptions[] = {
84            "Test Units",
85            "Thousands of Test Units",
86            "Millions of Test Units",
87            "Auto-scaled Test Units",
88            "Operations",
89            "Thousands of Operations",
90            "Millions of Operations",
91            "Auto-scaled Operations",
92        };
93        Integer workObjects[] = {
94            new Integer(WORK_UNITS),
95            new Integer(WORK_THOUSANDS),
96            new Integer(WORK_MILLIONS),
97            new Integer(WORK_AUTO),
98            new Integer(WORK_OPS | WORK_UNITS),
99            new Integer(WORK_OPS | WORK_THOUSANDS),
100            new Integer(WORK_OPS | WORK_MILLIONS),
101            new Integer(WORK_OPS | WORK_AUTO),
102        };
103        workOpt = new Option.ObjectChoice(resultoptroot,
104                                          "workunits", "Work Units",
105                                          workStrings, workObjects,
106                                          workStrings, workDescriptions,
107                                          0);
108        String timeStrings[] = {
109            "sec",
110            "msec",
111            "usec",
112            "nsec",
113            "autosec",
114        };
115        String timeDescriptions[] = {
116            "Seconds",
117            "Milliseconds",
118            "Microseconds",
119            "Nanoseconds",
120            "Auto-scaled seconds",
121        };
122        Integer timeObjects[] = {
123            new Integer(TIME_SECONDS),
124            new Integer(TIME_MILLIS),
125            new Integer(TIME_MICROS),
126            new Integer(TIME_NANOS),
127            new Integer(TIME_AUTO),
128        };
129        timeOpt = new Option.ObjectChoice(resultoptroot,
130                                          "timeunits", "Time Units",
131                                          timeStrings, timeObjects,
132                                          timeStrings, timeDescriptions,
133                                          0);
134        String rateStrings[] = {
135            "unitspersec",
136            "secsperunit",
137        };
138        String rateDescriptions[] = {
139            "Work units per Time",
140            "Time units per Work",
141        };
142        Boolean rateObjects[] = {
143            Boolean.FALSE,
144            Boolean.TRUE,
145        };
146        rateOpt = new Option.ObjectChoice(resultoptroot,
147                                          "ratio", "Rate Ratio",
148                                          rateStrings, rateObjects,
149                                          rateStrings, rateDescriptions,
150                                          0);
151    }
152
153    public static boolean isTimeUnit(int unit) {
154        return (unit >= TIME_SECONDS && unit <= TIME_AUTO);
155    }
156
157    public static boolean isWorkUnit(int unit) {
158        return (unit >= WORK_OPS && unit <= (WORK_AUTO | WORK_OPS));
159    }
160
161    public static String parseRateOpt(String opt) {
162        int timeScale = timeOpt.getIntValue();
163        int workScale = workOpt.getIntValue();
164        boolean invertRate = rateOpt.getBooleanValue();
165        int divindex = opt.indexOf('/');
166        if (divindex < 0) {
167            int unit = parseUnit(opt);
168            if (isTimeUnit(unit)) {
169                timeScale = unit;
170            } else if (isWorkUnit(unit)) {
171                workScale = unit;
172            } else {
173                return "Bad unit: "+opt;
174            }
175        } else {
176            int unit1 = parseUnit(opt.substring(0,divindex));
177            int unit2 = parseUnit(opt.substring(divindex+1));
178            if (isTimeUnit(unit1)) {
179                if (isWorkUnit(unit2)) {
180                    timeScale = unit1;
181                    workScale = unit2;
182                    invertRate = true;
183                } else if (isTimeUnit(unit2)) {
184                    return "Both time units: "+opt;
185                } else {
186                    return "Bad denominator: "+opt;
187                }
188            } else if (isWorkUnit(unit1)) {
189                if (isWorkUnit(unit2)) {
190                    return "Both work units: "+opt;
191                } else if (isTimeUnit(unit2)) {
192                    timeScale = unit2;
193                    workScale = unit1;
194                    invertRate = false;
195                } else {
196                    return "Bad denominator: "+opt;
197                }
198            } else {
199                return "Bad numerator: "+opt;
200            }
201        }
202        timeOpt.setValue(timeScale);
203        workOpt.setValue(workScale);
204        rateOpt.setValue(invertRate);
205        return null;
206    }
207
208    private static HashMap unitMap;
209
210    static {
211        unitMap = new HashMap();
212        unitMap.put("U",  new Integer(WORK_UNITS));
213        unitMap.put("M",  new Integer(WORK_MILLIONS));
214        unitMap.put("K",  new Integer(WORK_THOUSANDS));
215        unitMap.put("A",  new Integer(WORK_AUTO));
216        unitMap.put("MU", new Integer(WORK_MILLIONS));
217        unitMap.put("KU", new Integer(WORK_THOUSANDS));
218        unitMap.put("AU", new Integer(WORK_AUTO));
219
220        unitMap.put("O",  new Integer(WORK_UNITS | WORK_OPS));
221        unitMap.put("NO", new Integer(WORK_UNITS | WORK_OPS));
222        unitMap.put("MO", new Integer(WORK_MILLIONS | WORK_OPS));
223        unitMap.put("KO", new Integer(WORK_THOUSANDS | WORK_OPS));
224        unitMap.put("AO", new Integer(WORK_AUTO | WORK_OPS));
225
226        unitMap.put("s",  new Integer(TIME_SECONDS));
227        unitMap.put("m",  new Integer(TIME_MILLIS));
228        unitMap.put("u",  new Integer(TIME_MICROS));
229        unitMap.put("n",  new Integer(TIME_NANOS));
230        unitMap.put("a",  new Integer(TIME_AUTO));
231    }
232
233    public static int parseUnit(String c) {
234        Integer u = (Integer) unitMap.get(c);
235        if (u != null) {
236            return u.intValue();
237        }
238        return RATE_UNKNOWN;
239    }
240
241    String unitname = "unit";
242    Test test;
243    int repsPerRun;
244    int unitsPerRep;
245    Vector times;
246    Hashtable modifiers;
247    Throwable error;
248
249    public Result(Test test) {
250        this.test = test;
251        this.repsPerRun = 1;
252        this.unitsPerRep = 1;
253        times = new Vector();
254    }
255
256    public void setReps(int reps) {
257        this.repsPerRun = reps;
258    }
259
260    public void setUnits(int units) {
261        this.unitsPerRep = units;
262    }
263
264    public void setUnitName(String name) {
265        this.unitname = name;
266    }
267
268    public void addTime(long time) {
269        if (J2DBench.printresults.isEnabled()) {
270            System.out.println(test+" took "+time+"ms for "+
271                               getRepsPerRun()+" reps");
272        }
273        times.addElement(new Long(time));
274    }
275
276    public void setError(Throwable t) {
277        this.error = t;
278    }
279
280    public void setModifiers(Hashtable modifiers) {
281        this.modifiers = modifiers;
282    }
283
284    public Throwable getError() {
285        return error;
286    }
287
288    public int getRepsPerRun() {
289        return repsPerRun;
290    }
291
292    public int getUnitsPerRep() {
293        return unitsPerRep;
294    }
295
296    public long getUnitsPerRun() {
297        return ((long) getRepsPerRun()) * ((long) getUnitsPerRep());
298    }
299
300    public Hashtable getModifiers() {
301        return modifiers;
302    }
303
304    public long getNumRuns() {
305        return times.size();
306    }
307
308    public long getTime(int index) {
309        return ((Long) times.elementAt(index)).longValue();
310    }
311
312    public double getRepsPerSecond(int index) {
313        return (getRepsPerRun() * 1000.0) / getTime(index);
314    }
315
316    public double getUnitsPerSecond(int index) {
317        return (getUnitsPerRun() * 1000.0) / getTime(index);
318    }
319
320    public long getTotalReps() {
321        return getRepsPerRun() * getNumRuns();
322    }
323
324    public long getTotalUnits() {
325        return getUnitsPerRun() * getNumRuns();
326    }
327
328    public long getTotalTime() {
329        long totalTime = 0;
330        for (int i = 0; i < times.size(); i++) {
331            totalTime += getTime(i);
332        }
333        return totalTime;
334    }
335
336    public double getAverageRepsPerSecond() {
337        return (getTotalReps() * 1000.0) / getTotalTime();
338    }
339
340    public double getAverageUnitsPerSecond() {
341        return (getTotalUnits() * 1000.0) / getTotalTime();
342    }
343
344    public String getAverageString() {
345        int timeScale = timeOpt.getIntValue();
346        int workScale = workOpt.getIntValue();
347        boolean invertRate = rateOpt.getBooleanValue();
348        double time = getTotalTime();
349        String timeprefix = "";
350        switch (timeScale) {
351        case TIME_AUTO:
352        case TIME_SECONDS:
353            time /= 1000;
354            break;
355        case TIME_MILLIS:
356            timeprefix = "m";
357            break;
358        case TIME_MICROS:
359            time *= 1000.0;
360            timeprefix = "u";
361            break;
362        case TIME_NANOS:
363            time *= 1000000.0;
364            timeprefix = "n";
365            break;
366        }
367
368        String workprefix = "";
369        boolean isOps = (workScale & WORK_OPS) != 0;
370        String workname = isOps ? "op" : unitname;
371        double work = isOps ? getTotalReps() : getTotalUnits();
372        switch (workScale & (~WORK_OPS)) {
373        case WORK_AUTO:
374        case WORK_UNITS:
375            break;
376        case WORK_THOUSANDS:
377            work /= 1000.0;
378            workprefix = "K";
379            break;
380        case WORK_MILLIONS:
381            work /= 1000000.0;
382            workprefix = "M";
383            break;
384        }
385        if (invertRate) {
386            double rate = time / work;
387            if (timeScale == TIME_AUTO) {
388                if (rate < 1.0) {
389                    rate *= 1000.0;
390                    timeprefix = "m";
391                    if (rate < 1.0) {
392                        rate *= 1000.0;
393                        timeprefix = "u";
394                        if (rate < 1.0) {
395                            rate *= 1000.0;
396                            timeprefix = "n";
397                        }
398                    }
399                }
400            }
401            return rate+" "+timeprefix+"secs/"+workprefix+workname;
402        } else {
403            double rate = work / time;
404            if (workScale == WORK_AUTO) {
405                if (rate > 1000.0) {
406                    rate /= 1000.0;
407                    workprefix = "K";
408                    if (rate > 1000.0) {
409                        rate /= 1000.0;
410                        workprefix = "M";
411                    }
412                }
413            }
414            return rate+" "+workprefix+workname+"s/"+timeprefix+"sec";
415        }
416    }
417
418    public void summarize() {
419        if (error != null) {
420            System.out.println(test+" skipped due to "+error);
421            error.printStackTrace(System.out);
422        } else {
423            System.out.println(test+" averaged "+getAverageString());
424        }
425        if (true) {
426            Enumeration enum_ = modifiers.keys();
427            System.out.print("    with");
428            String sep = " ";
429            while (enum_.hasMoreElements()) {
430                Modifier mod = (Modifier) enum_.nextElement();
431                Object v = modifiers.get(mod);
432                System.out.print(sep);
433                System.out.print(mod.getAbbreviatedModifierDescription(v));
434                sep = ", ";
435            }
436            System.out.println();
437        }
438    }
439
440    public void write(PrintWriter pw) {
441        pw.println("  <result "+
442                   "num-reps=\""+getRepsPerRun()+"\" "+
443                   "num-units=\""+getUnitsPerRep()+"\" "+
444                   "name=\""+test.getTreeName()+"\">");
445        Enumeration enum_ = modifiers.keys();
446        while (enum_.hasMoreElements()) {
447            Modifier mod = (Modifier) enum_.nextElement();
448            Object v = modifiers.get(mod);
449            String val = mod.getModifierValueName(v);
450            pw.println("    <option "+
451                       "key=\""+mod.getTreeName()+"\" "+
452                       "value=\""+val+"\"/>");
453        }
454        for (int i = 0; i < getNumRuns(); i++) {
455            pw.println("    <time value=\""+getTime(i)+"\"/>");
456        }
457        pw.println("  </result>");
458    }
459}
460