| /* |
| * 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'> </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'> </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'> </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+" </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'> </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 + " </div></div>"); |
| } |
| w.println("</td></tr>"); |
| } |
| } |
| |
| w.println("<tr><td colspan='2'> </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(); |
| } |
| } |
| } |