blob: 7ac7ee01447fb35c72598e75a8306495645eb97a [file] [log] [blame]
/*
* Copyright (c) 2005, 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.
*/
/**
* HTMLSeriesReporter.java
*
* Show series data in graphical form.
*/
package j2dbench.report;
import java.io.*;
import java.util.*;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import j2dbench.report.J2DAnalyzer.ResultHolder;
import j2dbench.report.J2DAnalyzer.ResultSetHolder;
import j2dbench.report.J2DAnalyzer.SingleResultSetHolder;
public class HTMLSeriesReporter {
/**
* Flag to indicate - Generate new report or append to existing report
*/
private static final int HTMLGEN_FILE_NEW = 1;
private static final int HTMLGEN_FILE_UPDATE = 2;
/**
* Path to results directory where all results are stored
*/
public static String resultsDir = ".";
/**
* Holds the groups and corresponding group-display-names
*/
public static List groups = new ArrayList();
public static Map groupNames = new HashMap();
/**
* Level at which tests are grouped to be displayed in summary
*/
public static int LEVEL = 2;
private static final DecimalFormat decimalFormat =
new DecimalFormat("0.##");
private static final SimpleDateFormat dateFormat =
new SimpleDateFormat("EEE, MMM d, yyyy G 'at' HH:mm:ss z");
static final Comparator numericComparator = new Comparator() {
public int compare(Object lhs, Object rhs) {
double lval = -1;
try {
lval = Double.parseDouble((String)lhs);
}
catch (NumberFormatException pe) {
}
double rval = -1;
try {
rval = Double.parseDouble((String)rhs);
}
catch (NumberFormatException pe) {
}
double delta = lval - rval;
return delta == 0 ? 0 : delta < 0 ? -1 : 1;
}
};
/**
* Opens a File and returns a PrintWriter instance based on new/update
* option specified in argument.
*/
private static PrintWriter openFile(String name, int nSwitch) {
FileOutputStream file = null;
OutputStreamWriter writer = null;
try {
switch (nSwitch) {
case 1: // HTMLGEN_FILE_NEW
file = new FileOutputStream(name, false);
break;
case 2: // HTMLGEN_FILE_UPDATE
file = new FileOutputStream(name, true);
break;
}
writer = new OutputStreamWriter(file);
} catch (IOException ee) {
System.out.println("Error opening file: " + ee);
System.exit(1);
}
return new PrintWriter(new BufferedWriter(writer));
}
private static void generateSeriesReport(String resultsDir, ArrayList xmlFileNames) {
for (int i = 0; i < xmlFileNames.size(); ++i) {
String xml = (String)xmlFileNames.get(i);
try {
J2DAnalyzer.readResults(xml);
}
catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
// first, display the values of system properties that distinguish the
// sets, and the values of the system properties that are common to all sets
File reportFile = new File(resultsDir, "series.html");
PrintWriter w =
openFile(reportFile.getAbsolutePath(), HTMLGEN_FILE_NEW);
w.println("<html><body bgcolor='#ffffff'>");
w.println("<hr size='1'/><center><h2>J2DBench Series</h2></center><hr size='1'/>");
// collect system properties common to all result sets
// and those unique to only some sets
// first collect all the property keys. these should be the same, but we'll play
// it safe.
// final since referenced from inner class comparator below
final SingleResultSetHolder[] results = new SingleResultSetHolder[J2DAnalyzer.results.size()];
Set propKeys = new HashSet();
for (int i = 0; i < results.length; ++i) {
SingleResultSetHolder srsh = (SingleResultSetHolder)J2DAnalyzer.results.get(i);
Map props = srsh.getProperties();
Set keys = props.keySet();
propKeys.addAll(keys);
results[i] = srsh;
}
Map[] uniqueProps = new Map[results.length];
Map commonProps = new HashMap();
for (int i = 0; i < results.length; ++i) {
Map m = new HashMap();
m.putAll(results[i].getProperties());
uniqueProps[i] = m;
}
{
Iterator iter = propKeys.iterator();
loop: while (iter.hasNext()) {
Object k = iter.next();
Object v = null;
for (int i = 0; i < uniqueProps.length; ++i) {
Map props = uniqueProps[i];
if (i == 0) {
v = props.get(k);
} else {
Object mv = props.get(k);
if (!(v == null ? v == mv : v.equals(mv))) {
// not common, keep this key
continue loop;
}
}
}
// common, so put value in commonProps and remove this key
commonProps.put(k, v);
for (int i = 0; i < uniqueProps.length; ++i) {
uniqueProps[i].remove(k);
}
}
}
String[] hexColor = {
"#fc9505", "#fcd805", "#fc5c05", "#b5fc05", "1cfc05", "#05fc7a",
"#44ff88", "#77ff77", "#aaff66", "#ddff55", "#ffff44", "#ffdd33",
};
Comparator comparator = new Comparator() {
public int compare(Object lhs, Object rhs) {
return ((String)((Map.Entry)lhs).getKey()).compareTo((String)((Map.Entry)rhs).getKey());
}
};
// write table of unique and common properties
w.println("<br/>");
w.println("<table align='center' cols='2' cellspacing='0' cellpadding='0' border='0' width='80%'>");
w.println("<tr><th colspan='2' bgcolor='#aaaaaa'>Result Set Properties</th></tr>");
for (int i = 0; i < results.length; ++i) {
String titl = results[i].getTitle();
String desc = results[i].getDescription();
w.println("<tr bgcolor='" + hexColor[i%hexColor.length] + "'><th>"+titl+"</th><td>"+desc+"</td></tr>");
TreeSet ts = new TreeSet(comparator);
ts.addAll(uniqueProps[i].entrySet());
Iterator iter = ts.iterator();
while (iter.hasNext()) {
Map.Entry e = (Map.Entry)iter.next();
w.println("<tr><td width='30%'><b>"+e.getKey()+"</b></td><td>"+e.getValue()+"</td></tr>");
}
}
w.println("<tr><th colspan='2'>&nbsp;</th></tr>");
w.println("<tr><th colspan='2' bgcolor='#aaaaaa'>Common Properties</th></tr>");
{
TreeSet ts = new TreeSet(comparator);
ts.addAll(commonProps.entrySet());
Iterator iter = ts.iterator();
while (iter.hasNext()) {
Map.Entry e = (Map.Entry)iter.next();
w.println("<tr><td width='30%'><b>"+e.getKey()+"</b></td><td>"+e.getValue()+"</td></tr>");
}
}
w.println("<tr><th colspan='2'>&nbsp;</th></tr>");
w.println("<tr><th colspan='2' bgcolor='#aaaaaa'>Common Test Options</th></tr>");
{
TreeSet ts = new TreeSet(String.CASE_INSENSITIVE_ORDER);
ts.addAll(ResultHolder.commonkeys.keySet());
Iterator iter = ts.iterator();
while (iter.hasNext()) {
Object key = iter.next();
Object val = ResultHolder.commonkeymap.get(key);
w.println("<tr><td width='30%'><b>"+key+"</b></td><td>"+val+"</td></tr>");
}
}
w.println("</table>");
// for each test that appears in one or more result sets
// for each option that has multiple values
// for each value
// for each result set
// display count and bar
Map testRuns = new HashMap(); // from test name to resultholders
Set testNames = new TreeSet(String.CASE_INSENSITIVE_ORDER);
for (int i = 0; i < results.length; ++i) {
Enumeration en = results[i].getResultEnumeration();
while (en.hasMoreElements()) {
ResultHolder rh = (ResultHolder)en.nextElement();
String name = rh.getName();
testNames.add(name);
ArrayList list = (ArrayList)testRuns.get(name);
if (list == null) {
list = new ArrayList();
testRuns.put(name, list);
}
list.add(rh);
}
}
w.println("<hr size='1' width='60%'/>");
w.println("<br/>");
w.println("<table align='center' cols='2' cellspacing='0' cellpadding='0' border='0' width='80%'>");
Iterator iter = testNames.iterator();
while (iter.hasNext()) {
String name = (String)iter.next();
w.println("<tr bgcolor='#aaaaaa'><th colspan='2'>"+name+"</th></tr>");
double bestScore = 0;
// get sorted list of variable options for this test
// optionMap maps each option to a value map. the value map contains all the values,
// sorted depending on the value type (numeric or string). it maps
// from each (string) value to a list of all the resultholders for that value
// value.
Map optionMap = new TreeMap(String.CASE_INSENSITIVE_ORDER);
ArrayList list = (ArrayList)testRuns.get(name);
Iterator riter = list.iterator();
while (riter.hasNext()) {
ResultHolder rh = (ResultHolder)riter.next();
Hashtable options = rh.getOptions();
Set entries = options.entrySet();
Iterator eiter = entries.iterator();
while (eiter.hasNext()) {
Map.Entry e = (Map.Entry)eiter.next();
Object key = e.getKey();
if (ResultHolder.commonkeys.contains(key)) {
continue;
}
Object val = e.getValue();
Map vmap = (Map)optionMap.get(key);
if (vmap == null) {
// determine how to sort
boolean numeric = false;
try {
Integer.parseInt((String)val);
numeric = true;
}
catch (NumberFormatException pe) {
}
Comparator c = numeric ? numericComparator : String.CASE_INSENSITIVE_ORDER;
vmap = new TreeMap(c);
optionMap.put(key, vmap);
}
ArrayList vlist = (ArrayList)vmap.get(val);
if (vlist == null) {
vlist = new ArrayList();
vmap.put(val, vlist);
}
vlist.add(rh);
double score = rh.getScore();
if (score > bestScore) {
bestScore = score;
}
}
}
Iterator oi = optionMap.keySet().iterator();
while (oi.hasNext()) {
String optionName = (String)oi.next();
Map optionValues = (Map)optionMap.get(optionName);
if (optionValues.size() == 1) continue; // don't group by this if only one value
StringBuffer grouping = new StringBuffer();
grouping.append("Grouped by " + optionName + ", Result set");
Iterator oi2 = optionMap.keySet().iterator();
while (oi2.hasNext()) {
String oname2 = (String)oi2.next();
if (oname2.equals(optionName)) continue;
Map ov2 = (Map)optionMap.get(oname2);
if (ov2.size() == 1) continue;
grouping.append(", " + oname2);
Iterator ov2i = ov2.entrySet().iterator();
grouping.append(" (");
boolean comma = false;
while (ov2i.hasNext()) {
if (comma) grouping.append(", ");
grouping.append(((Map.Entry)ov2i.next()).getKey());
comma = true;
}
grouping.append(")");
}
w.println("<tr><td colspan='2'>&nbsp;</td></tr>");
w.println("<tr><td colspan='2'><b>" + grouping.toString() + "</b></td></tr>");
Iterator vi = optionValues.keySet().iterator();
while (vi.hasNext()) {
String valueName = (String)vi.next();
w.print("<tr><td align='right' valign='center' width='10%'>"+valueName+"&nbsp;</td><td>");
ArrayList resultList = (ArrayList)optionValues.get(valueName);
// sort the result list in order of the sets the results come from
// we count on this being a stable sort, otherwise we'd have to also sort
// within each result set on all other variables
Comparator c = new Comparator() {
public int compare(Object lhs, Object rhs) {
ResultSetHolder lh = ((ResultHolder)lhs).rsh;
ResultSetHolder rh = ((ResultHolder)rhs).rsh;
int li = -1;
for (int k = 0; k < results.length; ++k) {
if (results[k] == lh) {
li = k;
break;
}
}
int ri = -1;
for (int k = 0; k < results.length; ++k) {
if (results[k] == rh) {
ri = k;
break;
}
}
return li - ri;
}
};
w.println(" <div style='height: 5'>&nbsp;</div>");
ResultHolder[] sorted = new ResultHolder[resultList.size()];
sorted = (ResultHolder[])resultList.toArray(sorted);
Arrays.sort(sorted, c);
for (int k = 0; k < sorted.length; ++k) {
ResultHolder holder = sorted[k];
String color = null;
for (int n = 0; n < results.length; ++n) {
if (results[n] == holder.rsh) {
color = hexColor[n];
}
}
double score = holder.getScore();
int pix = 0;
if (bestScore > 1) {
double scale = logScale
? Math.log(score)/Math.log(bestScore)
: (score)/(bestScore);
pix = (int)(scale*80.0);
}
w.println(" <div style='width: " + pix +
"%; height: 15; font-size: smaller; valign: center; background-color: " + color+"'>" +
"<div align='right' style='height: 15'>" + (int)score + "&nbsp;</div></div>");
}
w.println("</td></tr>");
}
}
w.println("<tr><td colspan='2'>&nbsp;</td></tr>");
}
w.println("</table>");
w.println("<br/>");
w.println("</body></html>");
w.flush();
w.close();
}
private static void printUsage() {
String usage =
"\njava HTMLSeriesReporter [options] resultfile... " +
" \n\n" +
"where options include: " +
" \n" +
" -r | -results <result directory> " +
"directory to which reports are stored \n" +
" -ls " +
"display using logarithmic scale \n" +
" -resultxml | -xml <xml file path> " +
"path to result XML \n" +
" -group | -g <level> " +
"group-level for tests \n" +
" " +
" [ 1 , 2 , 3 or 4 ] \n" +
" -analyzermode | -am " +
"mode to be used for finding score \n" +
" " +
" [ BEST , WORST , AVERAGE , MIDAVG ] ";
System.out.println(usage);
System.exit(0);
}
static boolean logScale = false;
/**
* main
*/
public static void main(String args[]) {
String resDir = ".";
ArrayList results = new ArrayList();
int group = 2;
/* ---- Analysis Mode ----
BEST = 1;
WORST = 2;
AVERAGE = 3;
MIDAVG = 4;
------------------------ */
int analyzerMode = 4;
try {
for (int i = 0; i < args.length; i++) {
if (args[i].startsWith("-ls")) {
logScale = true;
} else if (args[i].startsWith("-results") ||
args[i].startsWith("-r"))
{
i++;
resDir = args[i];
} else if (args[i].startsWith("-group") ||
args[i].startsWith("-g"))
{
i++;
group = Integer.parseInt(args[i]);
System.out.println("Grouping Level for tests: " + group);
} else if (args[i].startsWith("-analyzermode") ||
args[i].startsWith("-am"))
{
i++;
String strAnalyzerMode = args[i];
if(strAnalyzerMode.equalsIgnoreCase("BEST")) {
analyzerMode = 0;
} else if (strAnalyzerMode.equalsIgnoreCase("WORST")) {
analyzerMode = 1;
} else if (strAnalyzerMode.equalsIgnoreCase("AVERAGE")) {
analyzerMode = 2;
} else if (strAnalyzerMode.equalsIgnoreCase("MIDAVG")) {
analyzerMode = 3;
} else {
printUsage();
}
System.out.println("Analyzer-Mode: " + analyzerMode);
} else {
results.add(args[i]);
}
}
}
catch(Exception e) {
printUsage();
}
if (resDir != null) {
J2DAnalyzer.setMode(analyzerMode);
HTMLSeriesReporter.generateSeriesReport(resDir, results);
} else {
printUsage();
}
}
}