1 /*
   2  * Copyright (c) 2002, 2018, 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.report;
  42 
  43 import java.util.Vector;
  44 import java.util.Hashtable;
  45 import java.util.Enumeration;
  46 import java.io.BufferedReader;
  47 import java.io.FileReader;
  48 import java.io.IOException;
  49 import java.io.PrintStream;
  50 
  51 public class J2DAnalyzer {
  52     static Vector results = new Vector();
  53     static GroupResultSetHolder groupHolder;
  54 
  55     static final int BEST = 1;    /* The best score */
  56     static final int WORST = 2;   /* The worst score */
  57     static final int AVERAGE = 3; /* Average of all scores */
  58     static final int MIDAVG = 4;  /* Average of all but the best and worst */
  59 
  60     static int mode = MIDAVG;
  61 
  62     public static void usage(PrintStream out) {
  63         out.println("usage:");
  64         out.println("    java -jar J2DAnalyzer.jar [Option]*");
  65         out.println();
  66         out.println("where options are any of the following in any order:");
  67         out.println("   -Help|-Usage          "+
  68                     "print out this usage statement");
  69         out.println("   -Group:<groupname>    "+
  70                     "the following result sets are combined into a group");
  71         out.println("   -NoGroup              "+
  72                     "the following result sets stand on their own");
  73         out.println("   -ShowUncontested      "+
  74                     "show results even when only result set has a result");
  75         out.println("   -Graph                "+
  76                     "graph the results visually (using lines of *'s)");
  77         out.println("   -Best                 "+
  78                     "use best time within a resultset");
  79         out.println("   -Worst                "+
  80                     "use worst time within a resultset");
  81         out.println("   -Average|-Avg         "+
  82                     "use average of all times within a resultset");
  83         out.println("   -MidAverage|-MidAvg   "+
  84                     "like -Average but ignore best and worst times");
  85         out.println("   <resultfilename>      "+
  86                     "load in results from named file");
  87         out.println();
  88         out.println("results within a result set "+
  89                     "use Best/Worst/Average mode");
  90         out.println("results within a group "+
  91                     "are best of all result sets in that group");
  92     }
  93 
  94     public static void main(String[] argv) {
  95         boolean gavehelp = false;
  96         boolean graph = false;
  97         boolean ignoreuncontested = true;
  98         if (argv.length > 0 && argv[0].equalsIgnoreCase("-html")) {
  99             String[] newargs = new String[argv.length-1];
 100             System.arraycopy(argv, 1, newargs, 0, newargs.length);
 101             HTMLSeriesReporter.main(newargs);
 102             return;
 103         }
 104         for (int i = 0; i < argv.length; i++) {
 105             String arg = argv[i];
 106             if (arg.regionMatches(true, 0, "-Group:", 0, 7)) {
 107                 groupHolder = new GroupResultSetHolder();
 108                 groupHolder.setTitle(arg.substring(7));
 109                 results.add(groupHolder);
 110             } else if (arg.equalsIgnoreCase("-NoGroup")) {
 111                 groupHolder = null;
 112             } else if (arg.equalsIgnoreCase("-ShowUncontested")) {
 113                 ignoreuncontested = false;
 114             } else if (arg.equalsIgnoreCase("-Graph")) {
 115                 graph = true;
 116             } else if (arg.equalsIgnoreCase("-Best")) {
 117                 mode = BEST;
 118             } else if (arg.equalsIgnoreCase("-Worst")) {
 119                 mode = WORST;
 120             } else if (arg.equalsIgnoreCase("-Average") ||
 121                        arg.equalsIgnoreCase("-Avg"))
 122             {
 123                 mode = AVERAGE;
 124             } else if (arg.equalsIgnoreCase("-MidAverage") ||
 125                        arg.equalsIgnoreCase("-MidAvg"))
 126             {
 127                 mode = MIDAVG;
 128             } else if (arg.equalsIgnoreCase("-Help") ||
 129                        arg.equalsIgnoreCase("-Usage"))
 130             {
 131                 usage(System.out);
 132                 gavehelp = true;
 133             } else {
 134                 readResults(argv[i]);
 135             }
 136         }
 137 
 138         if (results.size() == 0) {
 139             if (!gavehelp) {
 140                 System.err.println("No results loaded");
 141                 usage(System.err);
 142             }
 143             return;
 144         }
 145 
 146         int numsets = results.size();
 147         double[] totalscore = new double[numsets];
 148         int[] numwins = new int[numsets];
 149         int[] numties = new int[numsets];
 150         int[] numloss = new int[numsets];
 151         int[] numtests = new int[numsets];
 152         double[] bestscore = new double[numsets];
 153         double[] worstscore = new double[numsets];
 154         double[] bestspread = new double[numsets];
 155         double[] worstspread = new double[numsets];
 156         for (int i = 0; i < numsets; i++) {
 157             bestscore[i] = Double.NEGATIVE_INFINITY;
 158             worstscore[i] = Double.POSITIVE_INFINITY;
 159             bestspread[i] = Double.POSITIVE_INFINITY;
 160             worstspread[i] = Double.NEGATIVE_INFINITY;
 161         }
 162 
 163         ResultSetHolder base = (ResultSetHolder) results.elementAt(0);
 164         Enumeration enum_ = base.getKeyEnumeration();
 165         Vector keyvector = new Vector();
 166         while (enum_.hasMoreElements()) {
 167             keyvector.add(enum_.nextElement());
 168         }
 169         String[] keys = new String[keyvector.size()];
 170         keyvector.copyInto(keys);
 171         sort(keys);
 172         enum_ = ResultHolder.commonkeys.keys();
 173         System.out.println("Options common across all tests:");
 174         if (ResultHolder.commonname != null &&
 175             ResultHolder.commonname.length() != 0)
 176         {
 177             System.out.println("  testname="+ResultHolder.commonname);
 178         }
 179         while (enum_.hasMoreElements()) {
 180             Object key = enum_.nextElement();
 181             System.out.println("  "+key+"="+ResultHolder.commonkeymap.get(key));
 182         }
 183         System.out.println();
 184         for (int k = 0; k < keys.length; k++) {
 185             String key = keys[k];
 186             ResultHolder rh = base.getResultByKey(key);
 187             double score = rh.getScore();
 188             double maxscore = score;
 189             int numcontesting = 0;
 190             for (int i = 0; i < numsets; i++) {
 191                 ResultSetHolder rsh =
 192                     (ResultSetHolder) results.elementAt(i);
 193                 ResultHolder rh2 = rsh.getResultByKey(key);
 194                 if (rh2 != null) {
 195                     if (graph) {
 196                         maxscore = Math.max(maxscore, rh2.getBestScore());
 197                     }
 198                     numcontesting++;
 199                 }
 200             }
 201             if (ignoreuncontested && numcontesting < 2) {
 202                 continue;
 203             }
 204             System.out.println(rh.getShortKey()+":");
 205             for (int i = 0; i < numsets; i++) {
 206                 ResultSetHolder rsh = (ResultSetHolder) results.elementAt(i);
 207                 System.out.print(rsh.getTitle()+": ");
 208                 ResultHolder rh2 = rsh.getResultByKey(key);
 209                 if (rh2 == null) {
 210                     System.out.println("not run");
 211                 } else {
 212                     double score2 = rh2.getScore();
 213                     double percent = calcPercent(score, score2);
 214                     numtests[i]++;
 215                     if (percent < 97.5) {
 216                         numloss[i]++;
 217                     } else if (percent > 102.5) {
 218                         numwins[i]++;
 219                     } else {
 220                         numties[i]++;
 221                     }
 222                     totalscore[i] += score2;
 223                     if (bestscore[i] < percent) {
 224                         bestscore[i] = percent;
 225                     }
 226                     if (worstscore[i] > percent) {
 227                         worstscore[i] = percent;
 228                     }
 229                     double spread = rh2.getSpread();
 230                     if (bestspread[i] > spread) {
 231                         bestspread[i] = spread;
 232                     }
 233                     if (worstspread[i] < spread) {
 234                         worstspread[i] = spread;
 235                     }
 236                     System.out.print(format(score2));
 237                     System.out.print(" (var="+spread+"%)");
 238                     System.out.print(" ("+percent+"%)");
 239                     System.out.println();
 240                     if (graph) {
 241                         int maxlen = 60;
 242                         int avgpos =
 243                             (int) Math.round(maxlen * score / maxscore);
 244                         Vector scores = rh2.getAllScores();
 245                         for (int j = 0; j < scores.size(); j++) {
 246                             double s = ((Double) scores.get(j)).doubleValue();
 247                             int len = (int) Math.round(maxlen * s / maxscore);
 248                             int pos = 0;
 249                             while (pos < len) {
 250                                 System.out.print(pos == avgpos ? '|' : '*');
 251                                 pos++;
 252                             }
 253                             while (pos <= avgpos) {
 254                                 System.out.print(pos == avgpos ? '|' : ' ');
 255                                 pos++;
 256                             }
 257                             System.out.println();
 258                         }
 259                     }
 260                 }
 261             }
 262         }
 263         System.out.println();
 264         System.out.println("Summary:");
 265         for (int i = 0; i < numsets; i++) {
 266             ResultSetHolder rsh = (ResultSetHolder) results.elementAt(i);
 267             System.out.println("  "+rsh.getTitle()+": ");
 268             if (numtests[i] == 0) {
 269                 System.out.println("    No tests matched reference results");
 270             } else {
 271                 double overallscore = totalscore[i]/numtests[i];
 272                 System.out.println("    Number of tests:  "+numtests[i]);
 273                 System.out.println("    Overall average:  "+overallscore);
 274                 System.out.println("    Best spread:      "+bestspread[i]+
 275                                    "% variance");
 276                 System.out.println("    Worst spread:     "+worstspread[i]+
 277                                    "% variance");
 278                 if (i == 0) {
 279                     System.out.println("    (Basis for results comparison)");
 280                 } else {
 281                     System.out.println("    Comparison to basis:");
 282                     System.out.println("      Best result:      "+bestscore[i]+
 283                                        "% of basis");
 284                     System.out.println("      Worst result:     "+worstscore[i]+
 285                                        "% of basis");
 286                     System.out.println("      Number of wins:   "+numwins[i]);
 287                     System.out.println("      Number of ties:   "+numties[i]);
 288                     System.out.println("      Number of losses: "+numloss[i]);
 289                 }
 290             }
 291             System.out.println();
 292         }
 293     }
 294 
 295     public static void readResults(String filename) {
 296         BufferedReader in;
 297         try {
 298             in = new BufferedReader(new FileReader(filename));
 299             readResults(in);
 300         } catch (IOException e) {
 301             System.out.println(e);
 302             return;
 303         }
 304     }
 305 
 306     public static void addResultSet(ResultSetHolder rs) {
 307         if (groupHolder == null) {
 308             results.add(rs);
 309         } else {
 310             groupHolder.addResultSet(rs);
 311         }
 312     }
 313 
 314     public static void readResults(BufferedReader in)
 315         throws IOException
 316     {
 317         String xmlver = in.readLine();
 318         if (xmlver == null || !xmlver.startsWith("<?xml version=\"1.0\"")) {
 319             return;
 320         }
 321         while (true) {
 322             String rsline = in.readLine();
 323             if (rsline == null) {
 324                 break;
 325             }
 326             rsline = rsline.trim();
 327             if (rsline.startsWith("<result-set version=")) {
 328                 String title = getStringAttribute(rsline, "name");
 329                 if (title == null) {
 330                     title = "No title";
 331                 }
 332                 SingleResultSetHolder srs = new SingleResultSetHolder();
 333                 srs.setTitle(title);
 334                 readResultSet(in, srs);
 335                 addResultSet(srs);
 336             }
 337         }
 338     }
 339 
 340     public static void readResultSet(BufferedReader in,
 341                                      SingleResultSetHolder srs)
 342         throws IOException
 343     {
 344         String line;
 345         while ((line = in.readLine()) != null) {
 346             line = line.trim();
 347             if (line.startsWith("<test-desc>")) {
 348                 int index = line.indexOf("<", 11);
 349                 if (index < 0) {
 350                     index = line.length();
 351                 }
 352                 line = line.substring(11, index);
 353                 srs.setDescription(line);
 354             } else if (line.startsWith("<sys-prop")) {
 355                 String key = getStringAttribute(line, "key");
 356                 String val = getStringAttribute(line, "value");
 357                 if (key != null && val != null) {
 358                     srs.setProperty(key, val);
 359                 }
 360             } else if (line.startsWith("<test-date")) {
 361                 srs.setStartTime(getLongAttribute(line, "start"));
 362                 srs.setEndTime(getLongAttribute(line, "end"));
 363             } else if (line.startsWith("<result")) {
 364                 int numreps = getIntAttribute(line, "num-reps");
 365                 int numunits = getIntAttribute(line, "num-units");
 366                 String name = getStringAttribute(line, "name");
 367                 if (numreps > 0 && numunits >= 0 && name != null) {
 368                     ResultHolder rh = new ResultHolder(srs);
 369                     rh.setName(name);
 370                     rh.setReps(numreps);
 371                     rh.setUnits(numunits);
 372                     readResult(in, rh);
 373                     srs.addResult(rh);
 374                 }
 375             } else if (line.equals("</result-set>")) {
 376                 break;
 377             } else {
 378                 System.err.println("Unrecognized line in Result-Set: "+line);
 379             }
 380         }
 381     }
 382 
 383     public static void readResult(BufferedReader in, ResultHolder rh)
 384         throws IOException
 385     {
 386         String line;
 387         while ((line = in.readLine()) != null) {
 388             line = line.trim();
 389             if (line.startsWith("<option")) {
 390                 String key = getStringAttribute(line, "key");
 391                 String val = getStringAttribute(line, "value");
 392                 if (key != null && val != null) {
 393                     rh.addOption(key, val);
 394                 }
 395             } else if (line.startsWith("<time")) {
 396                 long ms = getLongAttribute(line, "value");
 397                 if (ms >= 0) {
 398                     rh.addTime(ms);
 399                 }
 400             } else if (line.equals("</result>")) {
 401                 break;
 402             } else {
 403                 System.err.println("Unrecognized line in Result: "+line);
 404             }
 405         }
 406     }
 407 
 408     public static String getStringAttribute(String line, String attrname) {
 409         int index = line.indexOf(attrname+"=");
 410         if (index < 0) {
 411             return null;
 412         }
 413         index += attrname.length()+1;
 414         int endindex;
 415         if (line.charAt(index) == '\"') {
 416             index++;
 417             endindex = line.indexOf('\"', index);
 418         } else {
 419             endindex = -1;
 420         }
 421         if (endindex < 0) {
 422             endindex = line.indexOf(' ', index);
 423         }
 424         if (endindex < 0) {
 425             endindex = line.indexOf('>', index);
 426         }
 427         if (endindex < 0) {
 428             endindex = line.length();
 429         }
 430         return line.substring(index, endindex);
 431     }
 432 
 433     public static long getLongAttribute(String line, String attrname) {
 434         String val = getStringAttribute(line, attrname);
 435         if (val == null) {
 436             return -1;
 437         }
 438         try {
 439             return Long.parseLong(val);
 440         } catch (NumberFormatException e) {
 441             return -1;
 442         }
 443     }
 444 
 445     public static int getIntAttribute(String line, String attrname) {
 446         String val = getStringAttribute(line, attrname);
 447         if (val == null) {
 448             return -1;
 449         }
 450         try {
 451             return Integer.parseInt(val);
 452         } catch (NumberFormatException e) {
 453             return -1;
 454         }
 455     }
 456 
 457     public abstract static class ResultSetHolder {
 458         private String title;
 459 
 460         public void setTitle(String title) {
 461             this.title = title;
 462         }
 463 
 464         public String getTitle() {
 465             return title;
 466         }
 467 
 468         public abstract Enumeration getKeyEnumeration();
 469 
 470         public abstract Enumeration getResultEnumeration();
 471 
 472         public abstract ResultHolder getResultByKey(String key);
 473     }
 474 
 475     public static class GroupResultSetHolder extends ResultSetHolder {
 476         private Vector members = new Vector();
 477         private Hashtable allresultkeys = new Hashtable();
 478 
 479         public void addResultSet(ResultSetHolder rsh) {
 480             members.add(rsh);
 481             Enumeration enum_ = rsh.getResultEnumeration();
 482             while (enum_.hasMoreElements()) {
 483                 ResultHolder rh = (ResultHolder) enum_.nextElement();
 484                 String key = rh.getKey();
 485                 allresultkeys.put(key, key);
 486             }
 487         }
 488 
 489         private ResultSetHolder getResultSet(int index) {
 490             return (ResultSetHolder) members.elementAt(index);
 491         }
 492 
 493         public Enumeration getKeyEnumeration() {
 494             return allresultkeys.keys();
 495         }
 496 
 497         public Enumeration getResultEnumeration() {
 498             return new Enumerator();
 499         }
 500 
 501         public ResultHolder getResultByKey(String key) {
 502             ResultHolder best = null;
 503             double bestscore = 0.0;
 504             for (int i = 0; i < members.size(); i++) {
 505                 ResultHolder cur = getResultSet(i).getResultByKey(key);
 506                 if (cur != null) {
 507                     double curscore = cur.getScore();
 508                     if (best == null || curscore > bestscore) {
 509                         best = cur;
 510                         bestscore = curscore;
 511                     }
 512                 }
 513             }
 514             return best;
 515         }
 516 
 517         public class Enumerator implements Enumeration {
 518             Enumeration raw = getKeyEnumeration();
 519 
 520             public boolean hasMoreElements() {
 521                 return raw.hasMoreElements();
 522             }
 523 
 524             public Object nextElement() {
 525                 return getResultByKey((String) raw.nextElement());
 526             }
 527         }
 528     }
 529 
 530     public static class SingleResultSetHolder extends ResultSetHolder {
 531         private String desc;
 532         private long start;
 533         private long end;
 534         private Hashtable props = new Hashtable();
 535         private Vector results = new Vector();
 536         private Hashtable resultsbykey = new Hashtable();
 537 
 538         public void setDescription(String desc) {
 539             this.desc = desc;
 540         }
 541 
 542         public String getDescription() {
 543             return desc;
 544         }
 545 
 546         public void setStartTime(long ms) {
 547             start = ms;
 548         }
 549 
 550         public long getStartTime() {
 551             return start;
 552         }
 553 
 554         public void setEndTime(long ms) {
 555             end = ms;
 556         }
 557 
 558         public long getEndTime() {
 559             return end;
 560         }
 561 
 562         public void setProperty(String key, String value) {
 563             props.put(key, value);
 564         }
 565 
 566         public Hashtable getProperties() {
 567             return this.props;
 568         }
 569 
 570         public void addResult(ResultHolder rh) {
 571             results.add(rh);
 572             resultsbykey.put(rh.getKey(), rh);
 573         }
 574 
 575         public Enumeration getKeyEnumeration() {
 576             return new Enumerator();
 577         }
 578 
 579         public Enumeration getResultEnumeration() {
 580             return results.elements();
 581         }
 582 
 583         public ResultHolder getResultByKey(String key) {
 584             return (ResultHolder) resultsbykey.get(key);
 585         }
 586 
 587         public class Enumerator implements Enumeration {
 588             Enumeration raw = getResultEnumeration();
 589 
 590             public boolean hasMoreElements() {
 591                 return raw.hasMoreElements();
 592             }
 593 
 594             public Object nextElement() {
 595                 return ((ResultHolder) raw.nextElement()).getKey();
 596             }
 597         }
 598     }
 599 
 600     public static class ResultHolder {
 601         public static Hashtable commonkeymap = new Hashtable();
 602         public static Hashtable commonkeys = new Hashtable();
 603         public static String commonname;
 604 
 605         ResultSetHolder rsh;
 606         private String name;
 607         private String key;
 608         private String shortkey;
 609         private int numreps;
 610         private int numunits;
 611         private int numruns;
 612         private long total;
 613         private long longest;
 614         private long shortest;
 615         private Hashtable options = new Hashtable();
 616         private Vector times = new Vector();
 617 
 618         public ResultHolder(ResultSetHolder rsh) {
 619             this.rsh = rsh;
 620         }
 621 
 622         public void setName(String name) {
 623             this.name = name;
 624             if (commonname == null) {
 625                 commonname = name;
 626             } else if (!commonname.equals(name)) {
 627                 commonname = "";
 628             }
 629         }
 630 
 631         public String getName() {
 632             return name;
 633         }
 634 
 635         public String getKey() {
 636             if (key == null) {
 637                 key = makeKey(false);
 638             }
 639             return key;
 640         }
 641 
 642         public String getShortKey() {
 643             if (shortkey == null) {
 644                 shortkey = makeKey(true);
 645             }
 646             return shortkey;
 647         }
 648 
 649         private String makeKey(boolean prunecommon) {
 650             String[] keys = new String[options.size()];
 651             Enumeration enum_ = options.keys();
 652             int i = 0;
 653             while (enum_.hasMoreElements()) {
 654                 keys[i++] = (String) enum_.nextElement();
 655             }
 656             sort(keys);
 657             String key = (prunecommon && commonname.equals(name)) ? "" : name;
 658             for (i = 0; i < keys.length; i++) {
 659                 if (!prunecommon || !commonkeys.containsKey(keys[i])) {
 660                     key = key+","+keys[i]+"="+options.get(keys[i]);
 661                 }
 662             }
 663             if (key.length() == 0) {
 664                 key = name;
 665             } else if (key.startsWith(",")) {
 666                 key = key.substring(1);
 667             }
 668             return key;
 669         }
 670 
 671         public void setReps(int numreps) {
 672             this.numreps = numreps;
 673         }
 674 
 675         public int getReps() {
 676             return numreps;
 677         }
 678 
 679         public void setUnits(int numunits) {
 680             this.numunits = numunits;
 681         }
 682 
 683         public int getUnits() {
 684             return numunits;
 685         }
 686 
 687         public void addOption(String key, String value) {
 688             if (this.key != null) {
 689                 throw new InternalError("option added after key was made!");
 690             }
 691             options.put(key, value);
 692             Object commonval = commonkeymap.get(key);
 693             if (commonval == null) {
 694                 commonkeymap.put(key, value);
 695                 commonkeys.put(key, key);
 696             } else if (!commonval.equals(value)) {
 697                 commonkeys.remove(key);
 698             }
 699         }
 700 
 701         public Hashtable getOptions() {
 702             return options;
 703         }
 704 
 705         public void addTime(long ms) {
 706             times.add(new Long(ms));
 707             if (numruns == 0) {
 708                 longest = shortest = ms;
 709             } else {
 710                 if (longest < ms) longest = ms;
 711                 if (shortest > ms) shortest = ms;
 712             }
 713             total += ms;
 714             numruns++;
 715         }
 716 
 717         public double getSpread() {
 718             return calcPercent(shortest, longest - shortest);
 719         }
 720 
 721         public double getScore() {
 722             double score = numreps;
 723             if (numunits > 0) {
 724                 score *= numunits;
 725             }
 726             long divisor;
 727             if (mode == BEST) {
 728                 divisor = shortest;
 729             } else if (mode == WORST) {
 730                 divisor = longest;
 731             } else if (mode == AVERAGE || numruns < 3) {
 732                 score *= numruns;
 733                 divisor = total;
 734             } else {
 735                 score *= (numruns-2);
 736                 divisor = (total - longest - shortest);
 737             }
 738             score /= divisor;
 739             return score;
 740         }
 741 
 742         public double getBestScore() {
 743             double score = numreps;
 744             if (numunits > 0) {
 745                 score *= numunits;
 746             }
 747             return score / shortest;
 748         }
 749 
 750         public Vector getAllScores() {
 751             Vector scores = new Vector();
 752 
 753             double score = numreps;
 754             if (numunits > 0) {
 755                 score *= numunits;
 756             }
 757             if (mode == BEST) {
 758                 scores.add(new Double(score / shortest));
 759             } else if (mode == WORST) {
 760                 scores.add(new Double(score / longest));
 761             } else {
 762                 long elimshort, elimlong;
 763                 if (mode == AVERAGE || numruns < 3) {
 764                     elimshort = elimlong = -1;
 765                 } else {
 766                     elimshort = shortest;
 767                     elimlong = longest;
 768                 }
 769                 for (int i = 0; i < times.size(); i++) {
 770                     long time = ((Long) times.get(i)).longValue();
 771                     if (time == elimshort) {
 772                         elimshort = -1;
 773                         continue;
 774                     }
 775                     if (time == elimlong) {
 776                         elimlong = -1;
 777                         continue;
 778                     }
 779                     scores.add(new Double(score / time));
 780                 }
 781             }
 782             return scores;
 783         }
 784     }
 785 
 786     public static double calcPercent(double base, double val) {
 787         val /= base;
 788         val *= 10000;
 789         val = Math.rint(val);
 790         return val / 100;
 791     }
 792 
 793     public static String format(double val) {
 794         long lval = (long) val;
 795         String ret = String.valueOf(lval);
 796         int digits = ret.length();
 797         if (digits > 17) {
 798             ret = String.valueOf(val);
 799         } else {
 800             val -= lval;
 801             String fraction = String.valueOf(val);
 802             fraction = fraction.substring(fraction.indexOf('.'));
 803             ret += fraction;
 804             int len = digits+5;
 805             if (len < 10) len = 10;
 806             len++;
 807             if (ret.length() > len) {
 808                 ret = ret.substring(0, len);
 809             }
 810         }
 811         return ret;
 812     }
 813 
 814     public static void sort(String[] strs) {
 815         for (int i = 1; i < strs.length; i++) {
 816             for (int j = i; j > 0; j--) {
 817                 if (strs[j].compareTo(strs[j-1]) >= 0) {
 818                     break;
 819                 }
 820                 String tmp = strs[j-1];
 821                 strs[j-1] = strs[j];
 822                 strs[j] = tmp;
 823             }
 824         }
 825     }
 826 
 827     public static void setMode(int mode) {
 828         if(mode >= BEST && mode <= MIDAVG) {
 829             J2DAnalyzer.mode = mode;
 830         }
 831         else {
 832             J2DAnalyzer.mode = MIDAVG;
 833         }
 834     }
 835 }