blob: 37cab7587d45253784ddc6b6fc715d1fdbfa86be [file] [log] [blame]
/*
* Copyright (c) 2002, 2007, 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.
*/
package j2dbench.report;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
public class J2DAnalyzer {
static Vector results = new Vector();
static GroupResultSetHolder groupHolder;
static final int BEST = 1; /* The best score */
static final int WORST = 2; /* The worst score */
static final int AVERAGE = 3; /* Average of all scores */
static final int MIDAVG = 4; /* Average of all but the best and worst */
static int mode = MIDAVG;
public static void usage(PrintStream out) {
out.println("usage:");
out.println(" java -jar J2DAnalyzer.jar [Option]*");
out.println();
out.println("where options are any of the following in any order:");
out.println(" -Help|-Usage "+
"print out this usage statement");
out.println(" -Group:<groupname> "+
"the following result sets are combined into a group");
out.println(" -NoGroup "+
"the following result sets stand on their own");
out.println(" -Graph "+
"graph the results visually (using lines of *'s)");
out.println(" -Best "+
"use best time within a resultset");
out.println(" -Worst "+
"use worst time within a resultset");
out.println(" -Average|-Avg "+
"use average of all times within a resultset");
out.println(" -MidAverage|-MidAvg "+
"like -Average but ignore best and worst times");
out.println(" <resultfilename> "+
"load in results from named file");
out.println();
out.println("results within a result set "+
"use Best/Worst/Average mode");
out.println("results within a group "+
"are best of all result sets in that group");
}
public static void main(String argv[]) {
boolean gavehelp = false;
boolean graph = false;
if (argv.length > 0 && argv[0].equalsIgnoreCase("-html")) {
String newargs[] = new String[argv.length-1];
System.arraycopy(argv, 1, newargs, 0, newargs.length);
HTMLSeriesReporter.main(newargs);
return;
}
for (int i = 0; i < argv.length; i++) {
String arg = argv[i];
if (arg.regionMatches(true, 0, "-Group:", 0, 7)) {
groupHolder = new GroupResultSetHolder();
groupHolder.setTitle(arg.substring(7));
results.add(groupHolder);
} else if (arg.equalsIgnoreCase("-NoGroup")) {
groupHolder = null;
} else if (arg.equalsIgnoreCase("-Graph")) {
graph = true;
} else if (arg.equalsIgnoreCase("-Best")) {
mode = BEST;
} else if (arg.equalsIgnoreCase("-Worst")) {
mode = WORST;
} else if (arg.equalsIgnoreCase("-Average") ||
arg.equalsIgnoreCase("-Avg"))
{
mode = AVERAGE;
} else if (arg.equalsIgnoreCase("-MidAverage") ||
arg.equalsIgnoreCase("-MidAvg"))
{
mode = MIDAVG;
} else if (arg.equalsIgnoreCase("-Help") ||
arg.equalsIgnoreCase("-Usage"))
{
usage(System.out);
gavehelp = true;
} else {
readResults(argv[i]);
}
}
if (results.size() == 0) {
if (!gavehelp) {
System.err.println("No results loaded");
usage(System.err);
}
return;
}
int numsets = results.size();
double totalscore[] = new double[numsets];
int numwins[] = new int[numsets];
int numties[] = new int[numsets];
int numloss[] = new int[numsets];
int numtests[] = new int[numsets];
double bestscore[] = new double[numsets];
double worstscore[] = new double[numsets];
double bestspread[] = new double[numsets];
double worstspread[] = new double[numsets];
for (int i = 0; i < numsets; i++) {
bestscore[i] = Double.NEGATIVE_INFINITY;
worstscore[i] = Double.POSITIVE_INFINITY;
bestspread[i] = Double.POSITIVE_INFINITY;
worstspread[i] = Double.NEGATIVE_INFINITY;
}
ResultSetHolder base = (ResultSetHolder) results.elementAt(0);
Enumeration enum_ = base.getKeyEnumeration();
Vector keyvector = new Vector();
while (enum_.hasMoreElements()) {
keyvector.add(enum_.nextElement());
}
String keys[] = new String[keyvector.size()];
keyvector.copyInto(keys);
sort(keys);
enum_ = ResultHolder.commonkeys.keys();
System.out.println("Options common across all tests:");
if (ResultHolder.commonname != null &&
ResultHolder.commonname.length() != 0)
{
System.out.println(" testname="+ResultHolder.commonname);
}
while (enum_.hasMoreElements()) {
Object key = enum_.nextElement();
System.out.println(" "+key+"="+ResultHolder.commonkeymap.get(key));
}
System.out.println();
for (int k = 0; k < keys.length; k++) {
String key = keys[k];
ResultHolder rh = base.getResultByKey(key);
double score = rh.getScore();
System.out.println(rh.getShortKey()+":");
double maxscore = score;
if (graph) {
for (int i = 0; i < numsets; i++) {
ResultSetHolder rsh =
(ResultSetHolder) results.elementAt(i);
ResultHolder rh2 = rsh.getResultByKey(key);
if (rh2 != null) {
maxscore = Math.max(maxscore, rh2.getBestScore());
}
}
}
for (int i = 0; i < numsets; i++) {
ResultSetHolder rsh = (ResultSetHolder) results.elementAt(i);
System.out.print(rsh.getTitle()+": ");
ResultHolder rh2 = rsh.getResultByKey(key);
if (rh2 == null) {
System.out.println("not run");
} else {
double score2 = rh2.getScore();
double percent = calcPercent(score, score2);
numtests[i]++;
if (percent < 97.5) {
numloss[i]++;
} else if (percent > 102.5) {
numwins[i]++;
} else {
numties[i]++;
}
totalscore[i] += score2;
if (bestscore[i] < percent) {
bestscore[i] = percent;
}
if (worstscore[i] > percent) {
worstscore[i] = percent;
}
double spread = rh2.getSpread();
if (bestspread[i] > spread) {
bestspread[i] = spread;
}
if (worstspread[i] < spread) {
worstspread[i] = spread;
}
System.out.print(format(score2));
System.out.print(" (var="+spread+"%)");
System.out.print(" ("+percent+"%)");
System.out.println();
if (graph) {
int maxlen = 60;
int avgpos =
(int) Math.round(maxlen * score / maxscore);
Vector scores = rh2.getAllScores();
for (int j = 0; j < scores.size(); j++) {
double s = ((Double) scores.get(j)).doubleValue();
int len = (int) Math.round(maxlen * s / maxscore);
int pos = 0;
while (pos < len) {
System.out.print(pos == avgpos ? '|' : '*');
pos++;
}
while (pos <= avgpos) {
System.out.print(pos == avgpos ? '|' : ' ');
pos++;
}
System.out.println();
}
}
}
}
}
System.out.println();
System.out.println("Summary:");
for (int i = 0; i < numsets; i++) {
ResultSetHolder rsh = (ResultSetHolder) results.elementAt(i);
System.out.println(" "+rsh.getTitle()+": ");
if (numtests[i] == 0) {
System.out.println(" No tests matched reference results");
} else {
double overallscore = totalscore[i]/numtests[i];
System.out.println(" Number of tests: "+numtests[i]);
System.out.println(" Overall average: "+overallscore);
System.out.println(" Best spread: "+bestspread[i]+
"% variance");
System.out.println(" Worst spread: "+worstspread[i]+
"% variance");
if (i == 0) {
System.out.println(" (Basis for results comparison)");
} else {
System.out.println(" Comparison to basis:");
System.out.println(" Best result: "+bestscore[i]+
"% of basis");
System.out.println(" Worst result: "+worstscore[i]+
"% of basis");
System.out.println(" Number of wins: "+numwins[i]);
System.out.println(" Number of ties: "+numties[i]);
System.out.println(" Number of losses: "+numloss[i]);
}
}
System.out.println();
}
}
public static void readResults(String filename) {
BufferedReader in;
try {
in = new BufferedReader(new FileReader(filename));
readResults(in);
} catch (IOException e) {
System.out.println(e);
return;
}
}
public static void addResultSet(ResultSetHolder rs) {
if (groupHolder == null) {
results.add(rs);
} else {
groupHolder.addResultSet(rs);
}
}
public static void readResults(BufferedReader in)
throws IOException
{
String xmlver = in.readLine();
if (xmlver == null || !xmlver.startsWith("<?xml version=\"1.0\"")) {
return;
}
while (true) {
String rsline = in.readLine();
if (rsline == null) {
break;
}
rsline = rsline.trim();
if (rsline.startsWith("<result-set version=")) {
String title = getStringAttribute(rsline, "name");
if (title == null) {
title = "No title";
}
SingleResultSetHolder srs = new SingleResultSetHolder();
srs.setTitle(title);
readResultSet(in, srs);
addResultSet(srs);
}
}
}
public static void readResultSet(BufferedReader in,
SingleResultSetHolder srs)
throws IOException
{
String line;
while ((line = in.readLine()) != null) {
line = line.trim();
if (line.startsWith("<test-desc>")) {
int index = line.indexOf("<", 11);
if (index < 0) {
index = line.length();
}
line = line.substring(11, index);
srs.setDescription(line);
} else if (line.startsWith("<sys-prop")) {
String key = getStringAttribute(line, "key");
String val = getStringAttribute(line, "value");
if (key != null && val != null) {
srs.setProperty(key, val);
}
} else if (line.startsWith("<test-date")) {
srs.setStartTime(getLongAttribute(line, "start"));
srs.setEndTime(getLongAttribute(line, "end"));
} else if (line.startsWith("<result")) {
int numreps = getIntAttribute(line, "num-reps");
int numunits = getIntAttribute(line, "num-units");
String name = getStringAttribute(line, "name");
if (numreps > 0 && numunits >= 0 && name != null) {
ResultHolder rh = new ResultHolder(srs);
rh.setName(name);
rh.setReps(numreps);
rh.setUnits(numunits);
readResult(in, rh);
srs.addResult(rh);
}
} else if (line.equals("</result-set>")) {
break;
} else {
System.err.println("Unrecognized line in Result-Set: "+line);
}
}
}
public static void readResult(BufferedReader in, ResultHolder rh)
throws IOException
{
String line;
while ((line = in.readLine()) != null) {
line = line.trim();
if (line.startsWith("<option")) {
String key = getStringAttribute(line, "key");
String val = getStringAttribute(line, "value");
if (key != null && val != null) {
rh.addOption(key, val);
}
} else if (line.startsWith("<time")) {
long ms = getLongAttribute(line, "value");
if (ms >= 0) {
rh.addTime(ms);
}
} else if (line.equals("</result>")) {
break;
} else {
System.err.println("Unrecognized line in Result: "+line);
}
}
}
public static String getStringAttribute(String line, String attrname) {
int index = line.indexOf(attrname+"=");
if (index < 0) {
return null;
}
index += attrname.length()+1;
int endindex;
if (line.charAt(index) == '\"') {
index++;
endindex = line.indexOf('\"', index);
} else {
endindex = -1;
}
if (endindex < 0) {
endindex = line.indexOf(' ', index);
}
if (endindex < 0) {
endindex = line.indexOf('>', index);
}
if (endindex < 0) {
endindex = line.length();
}
return line.substring(index, endindex);
}
public static long getLongAttribute(String line, String attrname) {
String val = getStringAttribute(line, attrname);
if (val == null) {
return -1;
}
try {
return Long.parseLong(val);
} catch (NumberFormatException e) {
return -1;
}
}
public static int getIntAttribute(String line, String attrname) {
String val = getStringAttribute(line, attrname);
if (val == null) {
return -1;
}
try {
return Integer.parseInt(val);
} catch (NumberFormatException e) {
return -1;
}
}
public abstract static class ResultSetHolder {
private String title;
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public abstract Enumeration getKeyEnumeration();
public abstract Enumeration getResultEnumeration();
public abstract ResultHolder getResultByKey(String key);
}
public static class GroupResultSetHolder extends ResultSetHolder {
private Vector members = new Vector();
private Hashtable allresultkeys = new Hashtable();
public void addResultSet(ResultSetHolder rsh) {
members.add(rsh);
Enumeration enum_ = rsh.getResultEnumeration();
while (enum_.hasMoreElements()) {
ResultHolder rh = (ResultHolder) enum_.nextElement();
String key = rh.getKey();
allresultkeys.put(key, key);
}
}
private ResultSetHolder getResultSet(int index) {
return (ResultSetHolder) members.elementAt(index);
}
public Enumeration getKeyEnumeration() {
return allresultkeys.keys();
}
public Enumeration getResultEnumeration() {
return new Enumerator();
}
public ResultHolder getResultByKey(String key) {
ResultHolder best = null;
double bestscore = 0.0;
for (int i = 0; i < members.size(); i++) {
ResultHolder cur = getResultSet(i).getResultByKey(key);
if (cur != null) {
double curscore = cur.getScore();
if (best == null || curscore > bestscore) {
best = cur;
bestscore = curscore;
}
}
}
return best;
}
public class Enumerator implements Enumeration {
Enumeration raw = getKeyEnumeration();
public boolean hasMoreElements() {
return raw.hasMoreElements();
}
public Object nextElement() {
return getResultByKey((String) raw.nextElement());
}
}
}
public static class SingleResultSetHolder extends ResultSetHolder {
private String desc;
private long start;
private long end;
private Hashtable props = new Hashtable();
private Vector results = new Vector();
private Hashtable resultsbykey = new Hashtable();
public void setDescription(String desc) {
this.desc = desc;
}
public String getDescription() {
return desc;
}
public void setStartTime(long ms) {
start = ms;
}
public long getStartTime() {
return start;
}
public void setEndTime(long ms) {
end = ms;
}
public long getEndTime() {
return end;
}
public void setProperty(String key, String value) {
props.put(key, value);
}
public Hashtable getProperties() {
return this.props;
}
public void addResult(ResultHolder rh) {
results.add(rh);
resultsbykey.put(rh.getKey(), rh);
}
public Enumeration getKeyEnumeration() {
return new Enumerator();
}
public Enumeration getResultEnumeration() {
return results.elements();
}
public ResultHolder getResultByKey(String key) {
return (ResultHolder) resultsbykey.get(key);
}
public class Enumerator implements Enumeration {
Enumeration raw = getResultEnumeration();
public boolean hasMoreElements() {
return raw.hasMoreElements();
}
public Object nextElement() {
return ((ResultHolder) raw.nextElement()).getKey();
}
}
}
public static class ResultHolder {
public static Hashtable commonkeymap = new Hashtable();
public static Hashtable commonkeys = new Hashtable();
public static String commonname;
ResultSetHolder rsh;
private String name;
private String key;
private String shortkey;
private int numreps;
private int numunits;
private int numruns;
private long total;
private long longest;
private long shortest;
private Hashtable options = new Hashtable();
private Vector times = new Vector();
public ResultHolder(ResultSetHolder rsh) {
this.rsh = rsh;
}
public void setName(String name) {
this.name = name;
if (commonname == null) {
commonname = name;
} else if (!commonname.equals(name)) {
commonname = "";
}
}
public String getName() {
return name;
}
public String getKey() {
if (key == null) {
key = makeKey(false);
}
return key;
}
public String getShortKey() {
if (shortkey == null) {
shortkey = makeKey(true);
}
return shortkey;
}
private String makeKey(boolean prunecommon) {
String keys[] = new String[options.size()];
Enumeration enum_ = options.keys();
int i = 0;
while (enum_.hasMoreElements()) {
keys[i++] = (String) enum_.nextElement();
}
sort(keys);
String key = (prunecommon && commonname.equals(name)) ? "" : name;
for (i = 0; i < keys.length; i++) {
if (!prunecommon || !commonkeys.containsKey(keys[i])) {
key = key+","+keys[i]+"="+options.get(keys[i]);
}
}
if (key.length() == 0) {
key = name;
} else if (key.startsWith(",")) {
key = key.substring(1);
}
return key;
}
public void setReps(int numreps) {
this.numreps = numreps;
}
public int getReps() {
return numreps;
}
public void setUnits(int numunits) {
this.numunits = numunits;
}
public int getUnits() {
return numunits;
}
public void addOption(String key, String value) {
if (this.key != null) {
throw new InternalError("option added after key was made!");
}
options.put(key, value);
Object commonval = commonkeymap.get(key);
if (commonval == null) {
commonkeymap.put(key, value);
commonkeys.put(key, key);
} else if (!commonval.equals(value)) {
commonkeys.remove(key);
}
}
public Hashtable getOptions() {
return options;
}
public void addTime(long ms) {
times.add(new Long(ms));
if (numruns == 0) {
longest = shortest = ms;
} else {
if (longest < ms) longest = ms;
if (shortest > ms) shortest = ms;
}
total += ms;
numruns++;
}
public double getSpread() {
return calcPercent(shortest, longest - shortest);
}
public double getScore() {
double score = numreps;
if (numunits > 0) {
score *= numunits;
}
long divisor;
if (mode == BEST) {
divisor = shortest;
} else if (mode == WORST) {
divisor = longest;
} else if (mode == AVERAGE || numruns < 3) {
score *= numruns;
divisor = total;
} else {
score *= (numruns-2);
divisor = (total - longest - shortest);
}
score /= divisor;
return score;
}
public double getBestScore() {
double score = numreps;
if (numunits > 0) {
score *= numunits;
}
return score / shortest;
}
public Vector getAllScores() {
Vector scores = new Vector();
double score = numreps;
if (numunits > 0) {
score *= numunits;
}
if (mode == BEST) {
scores.add(new Double(score / shortest));
} else if (mode == WORST) {
scores.add(new Double(score / longest));
} else {
long elimshort, elimlong;
if (mode == AVERAGE || numruns < 3) {
elimshort = elimlong = -1;
} else {
elimshort = shortest;
elimlong = longest;
}
for (int i = 0; i < times.size(); i++) {
long time = ((Long) times.get(i)).longValue();
if (time == elimshort) {
elimshort = -1;
continue;
}
if (time == elimlong) {
elimlong = -1;
continue;
}
scores.add(new Double(score / time));
}
}
return scores;
}
}
public static double calcPercent(double base, double val) {
val /= base;
val *= 10000;
val = Math.rint(val);
return val / 100;
}
public static String format(double val) {
long lval = (long) val;
String ret = String.valueOf(lval);
int digits = ret.length();
if (digits > 17) {
ret = String.valueOf(val);
} else {
val -= lval;
String fraction = String.valueOf(val);
fraction = fraction.substring(fraction.indexOf('.'));
ret += fraction;
int len = digits+5;
if (len < 10) len = 10;
len++;
if (ret.length() > len) {
ret = ret.substring(0, len);
}
}
return ret;
}
public static void sort(String strs[]) {
for (int i = 1; i < strs.length; i++) {
for (int j = i; j > 0; j--) {
if (strs[j].compareTo(strs[j-1]) >= 0) {
break;
}
String tmp = strs[j-1];
strs[j-1] = strs[j];
strs[j] = tmp;
}
}
}
public static void setMode(int mode) {
if(mode >= BEST && mode <= MIDAVG) {
J2DAnalyzer.mode = mode;
}
else {
J2DAnalyzer.mode = MIDAVG;
}
}
}