phoenix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mujt...@apache.org
Subject phoenix git commit: PHOENIX-2182 - Pherf - Add ability to compare of runs
Date Mon, 21 Sep 2015 20:02:55 GMT
Repository: phoenix
Updated Branches:
  refs/heads/4.x-HBase-1.0 3381de474 -> bf80d8e69


PHOENIX-2182 - Pherf - Add ability to compare of runs


Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/bf80d8e6
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/bf80d8e6
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/bf80d8e6

Branch: refs/heads/4.x-HBase-1.0
Commit: bf80d8e69ea8a11626daa1a1e293d6f68b138e75
Parents: 3381de4
Author: Mujtaba <mujtaba@apache.org>
Authored: Mon Sep 21 13:02:37 2015 -0700
Committer: Mujtaba <mujtaba@apache.org>
Committed: Mon Sep 21 13:02:37 2015 -0700

----------------------------------------------------------------------
 phoenix-pherf/config/pherf.properties           |   8 +-
 .../java/org/apache/phoenix/pherf/Pherf.java    |  23 +-
 .../phoenix/pherf/result/QueryResult.java       |  32 +-
 .../phoenix/pherf/result/ResultManager.java     |  19 +-
 .../apache/phoenix/pherf/result/ResultUtil.java |  12 +-
 .../phoenix/pherf/result/file/Header.java       |   2 +-
 .../pherf/util/GoogleChartGenerator.java        | 361 +++++++++++++++++++
 .../apache/phoenix/pherf/util/PhoenixUtil.java  |  30 ++
 .../pherf/workload/MultiThreadedRunner.java     |   4 +-
 .../pherf/workload/MultithreadedDiffer.java     |   4 +-
 .../phoenix/pherf/workload/QueryExecutor.java   |  12 +-
 .../phoenix/pherf/workload/QueryVerifier.java   |  30 --
 12 files changed, 494 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/bf80d8e6/phoenix-pherf/config/pherf.properties
----------------------------------------------------------------------
diff --git a/phoenix-pherf/config/pherf.properties b/phoenix-pherf/config/pherf.properties
index 152e09c..de5c167 100644
--- a/phoenix-pherf/config/pherf.properties
+++ b/phoenix-pherf/config/pherf.properties
@@ -30,4 +30,10 @@ pherf.default.dataloader.threadpool=0
 pherf.default.dataloader.batchsize=1000
 
 # Directory where results from a scenario run will be written
-pherf.default.results.dir=RESULTS
\ No newline at end of file
+pherf.default.results.dir=RESULTS
+
+# Google chart summary html file
+pherf.default.summary.file=RESULTS/summary.html
+
+# Threshold for comparator to fail. ex. 0.5 equates to 50%
+pherf.default.comparison.threshold=0.45
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bf80d8e6/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/Pherf.java
----------------------------------------------------------------------
diff --git a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/Pherf.java b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/Pherf.java
index 70fdb11..f6ed19d 100644
--- a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/Pherf.java
+++ b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/Pherf.java
@@ -22,7 +22,9 @@ import org.apache.commons.cli.*;
 import org.apache.phoenix.pherf.PherfConstants.GeneratePhoenixStats;
 import org.apache.phoenix.pherf.configuration.XMLConfigParser;
 import org.apache.phoenix.pherf.jmx.MonitorManager;
+import org.apache.phoenix.pherf.result.ResultUtil;
 import org.apache.phoenix.pherf.schema.SchemaReader;
+import org.apache.phoenix.pherf.util.GoogleChartGenerator;
 import org.apache.phoenix.pherf.util.PhoenixUtil;
 import org.apache.phoenix.pherf.util.ResourceList;
 import org.apache.phoenix.pherf.workload.QueryExecutor;
@@ -45,6 +47,8 @@ public class Pherf {
 
     static {
         options.addOption("disableSchemaApply", false, "Set to disable schema from being
applied.");
+		options.addOption("disableRuntimeResult", false,
+				"Set to disable writing detailed CSV file during query execution. Those will eventually
get written at the end of query execution.");
         options.addOption("z", "zookeeper", true,
                 "HBase Zookeeper address for connection. Default: localhost");
         options.addOption("q", "query", false, "Executes multi-threaded query sets");
@@ -76,6 +80,8 @@ public class Pherf {
         options.addOption("d", "debug", false, "Put tool in debug mode");
         options.addOption("stats", false,
                 "Update Phoenix Statistics after data is loaded with -l argument");
+		options.addOption("label", true, "Label a run. Result file name will be suffixed with specified
label");
+		options.addOption("compare", true, "Specify labeled runs to compare against current run");
     }
 
     private final String zookeeper;
@@ -92,7 +98,10 @@ public class Pherf {
     private final int rowCountOverride;
     private final boolean listFiles;
     private final boolean applySchema;
+    private final boolean writeRuntimeResults;
     private final GeneratePhoenixStats generateStatistics;
+    private final String label;
+    private final String compareResults;
 
     public Pherf(String[] args) throws Exception {
         CommandLineParser parser = new PosixParser();
@@ -126,6 +135,7 @@ public class Pherf {
         isFunctional = command.hasOption("diff");
         listFiles = command.hasOption("listFiles");
         applySchema = !command.hasOption("disableSchemaApply");
+        writeRuntimeResults = !command.hasOption("disableRuntimeResult");
         scenarioFile =
                 command.hasOption("scenarioFile") ? command.getOptionValue("scenarioFile")
: null;
         schemaFile = command.hasOption("schemaFile") ? command.getOptionValue("schemaFile")
: null;
@@ -136,6 +146,8 @@ public class Pherf {
                 command.getOptionValue("writerThreadSize",
                         properties.getProperty("pherf.default.dataloader.threadpool"));
         properties.setProperty("pherf. default.dataloader.threadpool", writerThreadPoolSize);
+        label = command.getOptionValue("label", null);
+        compareResults = command.getOptionValue("compare", null);
 
         if ((command.hasOption("h") || (args == null || args.length == 0)) && !command
                 .hasOption("listFiles")) {
@@ -144,6 +156,7 @@ public class Pherf {
         }
         PhoenixUtil.setZookeeper(zookeeper);
         PhoenixUtil.setRowCountOverride(rowCountOverride);
+        ResultUtil.setFileSuffix(label);
     }
 
     public static void main(String[] args) {
@@ -179,6 +192,14 @@ public class Pherf {
                 }
                 return;
             }
+            
+            // Compare results and exit  
+			if (null != compareResults) {
+				logger.info("\nStarting to compare results and exiting for " + compareResults);
+				new GoogleChartGenerator(compareResults).readAndRender();
+				return;
+            }
+            
             XMLConfigParser parser = new XMLConfigParser(scenarioFile);
 
             // Drop tables with PHERF schema and regex comparison
@@ -225,7 +246,7 @@ public class Pherf {
 
                 workloadExecutor
                         .add(new QueryExecutor(parser, phoenixUtil, workloadExecutor, parser.getDataModels(),
queryHint,
-                                isFunctional));
+                                isFunctional, writeRuntimeResults));
 
             } else {
                 logger.info(

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bf80d8e6/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/QueryResult.java
----------------------------------------------------------------------
diff --git a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/QueryResult.java
b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/QueryResult.java
index c0b4bf7..669a472 100644
--- a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/QueryResult.java
+++ b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/QueryResult.java
@@ -20,15 +20,18 @@ package org.apache.phoenix.pherf.result;
 
 import org.apache.phoenix.pherf.configuration.Query;
 import org.apache.phoenix.pherf.result.file.ResultFileDetails;
+import org.apache.phoenix.pherf.util.PhoenixUtil;
 import org.apache.phoenix.util.DateUtil;
 
+import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
 public class QueryResult extends Query {
     private List<ThreadTime> threadTimes = new ArrayList<>();
-
+    private static PhoenixUtil pUtil = PhoenixUtil.create();
+    
     public QueryResult() {
         super();
     }
@@ -106,8 +109,35 @@ public class QueryResult extends Query {
         rowValues.add(new ResultValue(util.convertNull(String.valueOf(getAvgRunTimeInMs()))));
         rowValues.add(new ResultValue(util.convertNull(String.valueOf(getAvgMinRunTimeInMs()))));
         rowValues.add(new ResultValue(util.convertNull(String.valueOf(getRunCount()))));
+        rowValues.add(new ResultValue(util.convertNull(String.valueOf(getExplainPlan()))));
+        rowValues.add(new ResultValue(util.convertNull(String.valueOf(getResultRowCount()))));
         return rowValues;
     }
+    
+    private String getExplainPlan() {
+    	try {
+			return pUtil.getExplainPlan(this);
+		} catch (SQLException e) {
+			e.printStackTrace();
+		}
+    	return null;
+    }
+    
+    private long getResultRowCount() {
+        long resultRowCount = -1;
+        for (ThreadTime tt : getThreadTimes()) {
+        	for (int i = 0; i < tt.getRunTimesInMs().size(); i++) {
+        		if (resultRowCount == -1) {
+        			resultRowCount = tt.getRunTimesInMs().get(i).getResultRowCount();
+        		} else {
+        			if (resultRowCount != tt.getRunTimesInMs().get(i).getResultRowCount()) {
+        				return -1;
+        			}
+        		}
+        	}
+        }
+        return resultRowCount;
+    }
 
     public List<List<ResultValue>> getCsvDetailedRepresentation(ResultUtil util,
ResultFileDetails details) {
         List<List<ResultValue>> rows = new ArrayList<>();

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bf80d8e6/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/ResultManager.java
----------------------------------------------------------------------
diff --git a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/ResultManager.java
b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/ResultManager.java
index 6a79486..f994621 100644
--- a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/ResultManager.java
+++ b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/ResultManager.java
@@ -32,7 +32,8 @@ public class ResultManager {
     private final List<ResultHandler> resultHandlers;
     private final ResultUtil util;
     private static final List<ResultHandler> defaultHandlers;
-
+    private static final List<ResultHandler> minimalHandlers;
+    
     static {
         defaultHandlers = new ArrayList<>();
         XMLResultHandler xmlResultHandler = new XMLResultHandler();
@@ -51,9 +52,23 @@ public class ResultManager {
         handlerDet.setResultFileDetails(ResultFileDetails.CSV_DETAILED_PERFORMANCE);
         defaultHandlers.add(handlerDet);
     }
+    
+    static {
+    	minimalHandlers = new ArrayList<>();
+        ImageResultHandler imageResultHandler = new ImageResultHandler();
+        imageResultHandler.setResultFileDetails(ResultFileDetails.IMAGE);
+        minimalHandlers.add(imageResultHandler);
+    }
 
     public ResultManager(String fileNameSeed) {
-        this(fileNameSeed, InstanceResolver.get(ResultHandler.class, defaultHandlers));
+        this(fileNameSeed, true);
+    }
+    
+    @SuppressWarnings("unchecked")
+	public ResultManager(String fileNameSeed, boolean writeRuntimeResults) {
+        this(fileNameSeed, writeRuntimeResults ?
+        		InstanceResolver.get(ResultHandler.class, defaultHandlers) :
+        		InstanceResolver.get(ResultHandler.class, minimalHandlers));
     }
 
     public ResultManager(String fileNameSeed, List<ResultHandler> resultHandlers) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bf80d8e6/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/ResultUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/ResultUtil.java b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/ResultUtil.java
index 9a589f5..04e6197 100644
--- a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/ResultUtil.java
+++ b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/ResultUtil.java
@@ -153,9 +153,9 @@ public class ResultUtil {
         if (null == FILE_SUFFIX) {
             Date date = new Date();
             Format formatter = new SimpleDateFormat("YYYY-MM-dd_hh-mm-ss");
-            FILE_SUFFIX = "_" + formatter.format(date);
+            FILE_SUFFIX = formatter.format(date);
         }
-        return FILE_SUFFIX;
+        return "_" + FILE_SUFFIX;
     }
 
     public String convertNull(String str) {
@@ -236,4 +236,12 @@ public class ResultUtil {
         }
         return sb.toString();
     }
+    
+    /**
+     * Set the file suffix
+     * @param suffix
+     */
+    public static void setFileSuffix(String suffix) {
+    	FILE_SUFFIX = suffix;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bf80d8e6/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/file/Header.java
----------------------------------------------------------------------
diff --git a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/file/Header.java
b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/file/Header.java
index 15e2b9a..066fa7a 100644
--- a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/file/Header.java
+++ b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/file/Header.java
@@ -21,7 +21,7 @@ package org.apache.phoenix.pherf.result.file;
 public enum Header {
     EMPTY(""),
     AGGREGATE_PERFORMANCE(
-            "START_TIME,QUERY_GROUP,QUERY,TENANT_ID,AVG_MAX_TIME_MS,AVG_TIME_MS,AVG_MIN_TIME_MS,RUN_COUNT"),
+            "START_TIME,QUERY_GROUP,QUERY,TENANT_ID,AVG_MAX_TIME_MS,AVG_TIME_MS,AVG_MIN_TIME_MS,RUN_COUNT,EXPLAIN_PLAN,RESULT_ROW_COUNT"),
     DETAILED_BASE(
             "BASE_TABLE_NAME,SCENARIO_NAME,ZOOKEEPER,ROW_COUNT,EXECUTION_COUNT,EXECUTION_TYPE,PHOENIX_PROPERTIES"
                     + ",START_TIME,QUERY_GROUP,QUERY,TENANT_ID,THREAD_NUMBER,CONCURRENCY_LEVEL"),

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bf80d8e6/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/util/GoogleChartGenerator.java
----------------------------------------------------------------------
diff --git a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/util/GoogleChartGenerator.java
b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/util/GoogleChartGenerator.java
new file mode 100644
index 0000000..37f29e7
--- /dev/null
+++ b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/util/GoogleChartGenerator.java
@@ -0,0 +1,361 @@
+package org.apache.phoenix.pherf.util;
+
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVRecord;
+import org.apache.phoenix.pherf.PherfConstants;
+import org.apache.phoenix.pherf.result.file.ResultFileDetails;
+
+/**
+ * Compare results based on set threshold and render results as Google Charts
+ */
+public class GoogleChartGenerator {
+
+	private String[] labels;
+	private final Map<String, DataNode> datanodes = new TreeMap<String, DataNode>();
+	private final PherfConstants constants = PherfConstants.create();
+	private final String resultDir = constants.getProperty("pherf.default.results.dir");
+	private final double threshold = Double.parseDouble(constants.getProperty("pherf.default.comparison.threshold"));
+
+	public GoogleChartGenerator(String labels) {
+		this.setLabels(labels);
+	}
+	
+	String[] getLabels() {
+		return labels;
+	}
+
+	void setLabels(String[] labels) {
+		this.labels = labels;
+	}
+
+	void setLabels(String labels) {
+		this.labels = labels.split(",");
+	}
+	
+	public void readAndRender() {
+		try {
+			for (String label : labels) {
+				read(label);
+			}
+			renderAsGoogleChartsHTML();
+
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * Reads aggregate file and convert it to DataNode 
+	 * @param label
+	 * @throws Exception
+	 */
+    private void read(String label) throws Exception {
+		String resultFileName = resultDir 
+				+ PherfConstants.PATH_SEPARATOR
+				+ PherfConstants.RESULT_PREFIX 
+				+ label
+				+ ResultFileDetails.CSV_AGGREGATE_PERFORMANCE.getExtension();
+
+    	FileReader in = new FileReader(resultFileName);
+    	final CSVParser parser = new CSVParser(in, CSVFormat.DEFAULT.withHeader());
+
+        for (CSVRecord record : parser) {
+            String group = record.get("QUERY_GROUP");
+            String query = record.get("QUERY");
+            String explain = record.get("EXPLAIN_PLAN");
+            String tenantId = record.get("TENANT_ID");
+            long avgTime = Long.parseLong(record.get("AVG_TIME_MS"));
+            long minTime = Long.parseLong(record.get("AVG_MIN_TIME_MS"));
+            long numRuns = Long.parseLong(record.get("RUN_COUNT"));
+            long rowCount = Long.parseLong(record.get("RESULT_ROW_COUNT"));
+            Node node = new Node(minTime, avgTime, numRuns, explain, query, tenantId, label,
rowCount);
+            
+            if (datanodes.containsKey(group)) {
+            	datanodes.get(group).getDataSet().put(label, node);
+            } else {
+            	datanodes.put(group, new DataNode(label, node));
+            }
+        }
+        parser.close();
+    }
+
+    /**
+     * Verifies if the first result is within the set 
+     * threshold of pherf.default.comparison.threshold
+     * set in pherf.properties files
+     * @param threshold
+     * @return
+     */
+    private boolean verifyWithinThreshold(double threshold) {
+    	long resetTimeToCompare = -1;
+    	long timeToCompare = resetTimeToCompare;
+    	for (Map.Entry<String, DataNode> dn : datanodes.entrySet()) {    	   	
+        	for (Map.Entry<String, Node> node : dn.getValue().getDataSet().entrySet())
{
+        		if (timeToCompare == -1) {
+        			timeToCompare = node.getValue().getMinTime();
+        			if (timeToCompare < 10) { // extremely small query time in ms therefore don't
compare
+        				return true;
+        			}
+        		}
+				if ((((double) (timeToCompare - node.getValue().getMinTime())) / (double) node
+						.getValue().getMinTime()) > threshold) {
+					return false;
+				}
+        	}
+        	timeToCompare = resetTimeToCompare;
+    	}
+    	return true;
+    }
+    
+    /**
+     * Render results as Google charts
+     * @throws FileNotFoundException
+     * @throws UnsupportedEncodingException
+     */
+    private void renderAsGoogleChartsHTML() throws FileNotFoundException, UnsupportedEncodingException
{
+    	String lastKeyPrefix = "";
+    	StringBuffer sb = new StringBuffer();
+    	for (String label : labels) {
+    		sb.append("dataTable.addColumn('number', '" + label + "');\n");
+    		sb.append("dataTable.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});\n");
+    	}
+    	sb.append("dataTable.addRows([\n");
+    	for (Map.Entry<String, DataNode> dn : datanodes.entrySet()) {
+    		String currentKeyPrefix = dn.getKey().substring(0, dn.getKey().indexOf('|'));
+    		if (!lastKeyPrefix.equalsIgnoreCase(currentKeyPrefix) && lastKeyPrefix != "")
{
+    			sb.append(getBlankRow());
+    		}
+    		lastKeyPrefix = currentKeyPrefix;
+        	sb.append("['" + dn.getKey() + "'");
+        	for (Map.Entry<String, Node> nodeSet : dn.getValue().getDataSet().entrySet())
{
+        		sb.append (", " + nodeSet.getValue().getMinTime());
+        		sb.append (",'" + getToolTipAsHTML(dn.getValue().getDataSet()) + "'");
+        	}
+        	sb.append("],\n");
+        }
+    	String summaryFile = PherfConstants.create().getProperty("pherf.default.summary.file");
+    	String title = labels[0];
+    	PrintWriter writer = new PrintWriter(summaryFile, "UTF-8");
+    	
+    	writer.println(StaticGoogleChartsRenderingData.HEADER.replace("[title]", title));
+    	writer.println(sb.substring(0, sb.length() - 2) + "\n]);");
+		String thresholdString = Math.round((threshold*100)) + "%"; 
+		String footer = StaticGoogleChartsRenderingData.FOOTER
+				.replace("[summary]",
+						((verifyWithinThreshold(threshold) == true ? "<font color=green>PASSED | Results
are within ": 
+							"<font color=red>FAILED | Results are outside "))
+								+ "set threshold of " + thresholdString + "</font><br>"
+								+ new SimpleDateFormat("yyyy/MM/dd ha z").format(new Date()));
+		footer = footer.replace("[title]", title);
+    	writer.println(footer);
+    	writer.close();
+    }
+    
+    /**
+     * Render a blank Google charts row
+     * @return
+     */
+    private String getBlankRow() {
+    	String ret = "['" + new String(new char[60]).replace("\0", ".") + "'";
+    	for (int i=0; i<labels.length; i++)
+    		ret += ",0,''";
+    	ret += "],";
+    	return ret;
+	}
+
+    /**
+     * Render tooltip as HTML table
+     * @param nodeDataSet
+     * @return
+     */
+	private String getToolTipAsHTML(Map<String, Node> nodeDataSet) {
+       	String ret = "<table width=1000 cellpadding=1 cellspacing=0 border=0 bgcolor=#F4F4F4><tr>";
+    	for (Map.Entry<String, Node> nodeSet : nodeDataSet.entrySet())	
+    		ret += "<td>" + getToolText(nodeSet.getValue()) + "</td>";
+    	return ret + "</tr></table>";
+    }
+    
+	/**
+	 * Get tooltip for node
+	 * @param node
+	 * @return
+	 */
+    private String getToolText(Node node) {
+        return node.getLabelAsHTML() 
+        		+ node.getAvgTimeAsHTML()
+        		+ node.getMinTimeAsHTML()
+        		+ node.getNumRunsAsHTML()
+        		+ node.getRowCountAsHTML()
+        		+ node.getExplainPlanAsHTML()
+        		+ node.getQueryAsHTML();
+    }
+    
+    /**
+     * DataNode to store results to render and compare 
+     */
+    class DataNode {
+    	private Map<String, Node> dataSet = new LinkedHashMap<String, Node>();
+		
+    	public DataNode(String label, Node node) {
+    		this.getDataSet().put(label, node);
+    	}
+    	
+		public Map<String, Node> getDataSet() {
+			return dataSet;
+		}
+		public void setDataSet(Map<String, Node> dataSet) {
+			this.dataSet = dataSet;
+		}
+    }
+    
+    class Node {
+    	private String explainPlan;
+    	private String query;
+    	private String tenantId;
+    	private long minTime;
+    	private long avgTime;
+    	private long numRuns;
+    	private long rowCount;
+    	private String label;
+    	private DecimalFormat df = new DecimalFormat("#.#");
+    	
+    	public Node(long minTime, long avgTime, long numRuns, String explainPlan, String query,
String tenantId, String label, long rowCount) {
+    		this.setMinTime(minTime);
+    		this.setAvgTime(avgTime);
+    		this.setNumRuns(numRuns);
+    		this.setExplainPlan(explainPlan);
+    		this.setQuery(query);
+    		this.setTenantId(tenantId);
+    		this.setLabel(label);
+    		this.setRowCount(rowCount);
+    	}
+    	
+		String getExplainPlan() {
+			return explainPlan;
+		}
+		String getExplainPlanAsHTML() {
+			return "</br><font face=arial size=1><b>EXPLAIN PLAN </b>"
+					+ explainPlan.replace("'", "") + "</font><br>";
+		}
+		
+		void setExplainPlan(String explainPlan) {
+			this.explainPlan = explainPlan;
+		}
+		long getMinTime() {
+			if (minTime <= 2) 
+				return 2;
+			else
+				return minTime;
+		}
+		public String getMinTimeAsHTML() {
+			return "<font face=arial size=1><b>MIN TIME </b></font><font
face=arial size=3>"
+					+ minTime
+					+ " ms ("
+					+ df.format((double) minTime / 1000)
+					+ " sec)</font><br>";
+		}
+		void setMinTime(long minTime) {
+			this.minTime = minTime;
+		}
+		long getAvgTime() {
+			return avgTime;
+		}
+		public String getAvgTimeAsHTML() {
+			return "<font face=arial size=1><b>AVERAGE TIME </b></font><font
face=arial size=3>"
+					+ avgTime
+					+ " ms ("
+					+ df.format((double) avgTime / 1000)
+					+ " sec)</font><br>";
+		}
+		void setAvgTime(long avgTime) {
+			this.avgTime = avgTime;
+		}
+
+		public long getNumRuns() {
+			return numRuns;
+		}
+		public String getNumRunsAsHTML() {
+			return "<font face=arial size=1><b>NUMBER OF RUNS </b></font><font
face=arial size=3>"
+					+ numRuns + "</font><br>";
+		}
+
+		public void setNumRuns(long numRuns) {
+			this.numRuns = numRuns;
+		}
+
+		public String getQuery() {
+			return query;
+		}
+
+		public String getQueryAsHTML() {
+			return "<br><font face=arial size=1><b>QUERY </b>"
+					+ query.replace("'", "") + " (TENANT ID: " + getTenantId()
+					+ ")</font><br>";
+		}
+		
+		public void setQuery(String query) {
+			this.query = query;
+		}
+
+		public String getTenantId() {
+			return tenantId;
+		}
+		
+		public void setTenantId(String tenantId) {
+			this.tenantId = tenantId;
+		}
+
+		public String getLabel() {
+			return label;
+		}
+		
+		public String getLabelAsHTML() {
+			return "<font face=arial size=4 color=#666699>" + label
+					+ "</font><br>";
+		}
+
+		public void setLabel(String label) {
+			this.label = label;
+		}
+
+		public long getRowCount() {
+			return rowCount;
+		}
+		public String getRowCountAsHTML() {
+			return "<font face=arial size=1><b>RESULT ROW COUNT </b></font><font
face=arial size=3>"
+					+ rowCount + "</font><br>";
+		}
+
+		public void setRowCount(long rowCount) {
+			this.rowCount = rowCount;
+		}
+    }
+    
+    static class StaticGoogleChartsRenderingData {
+		public static String HEADER = "<html><head><title>[title]</title>"
+				+ "<script type='text/javascript' src='https://www.google.com/jsapi'></script>"
+				+ "<script type='text/javascript'>google.load('visualization', '1', {packages:
['corechart', 'bar']});google.setOnLoadCallback(drawMaterial);"
+				+ "function drawMaterial() {var dataTable = new google.visualization.DataTable();dataTable.addColumn('string',
'Query');";
+		public static String FOOTER = "var options = {title: '',titleTextStyle: {color: 'gray',
fontName: 'Raleway', fontSize: '24'},hAxis: {title: 'Minimum query time for all runs in milli-seconds
(ms) | Scaled logrithmic | Hover to see details',titleTextStyle: {italic: false,fontName:
'arial', fontSize: '12'},"
+				+ "logScale: true,minValue: 0,textStyle: { fontName: 'arial', fontSize: '14'},},vAxis:
{textStyle: {fontName: 'arial', fontSize: '12', fontWidth: 'normal', paddingRight: '100',marginRight:
'100'}},"
+				+ "chartArea: {left:300, width: 500, right: 400, top: 50, height: 700},"
+				+ "legend:{textStyle:{fontSize:'13', fontName:'arial'}},"
+				+ "tooltip: {isHtml: true},width: 1200,height: 800,"
+				+ "bars:'horizontal',bar: { groupWidth: '75%' },colors: ['#E1A5A9', '#A9A5BC', '#A9A5E1']};"
+				+ "var material = new google.visualization.BarChart(document.getElementById('chart_div'));"
+				+ "material.draw(dataTable, options);}"
+				+ "</script></head><body><b><font face=raleway size=5>PHERFED
[title]</font><br><font face=raleway size=4>[summary]</font></b><div
id='chart_div' style='margin:0px;padding:0px;'></div></body></html>";
+    }
+}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bf80d8e6/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/util/PhoenixUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/util/PhoenixUtil.java b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/util/PhoenixUtil.java
index 57858a3..1f610f6 100644
--- a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/util/PhoenixUtil.java
+++ b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/util/PhoenixUtil.java
@@ -300,4 +300,34 @@ public class PhoenixUtil {
 
         return manager;
     }
+    
+    /**
+     * Get explain plan for a query
+     *
+     * @param query
+     * @return
+     * @throws SQLException
+     */
+    public String getExplainPlan(Query query) throws SQLException {
+        Connection conn = null;
+        ResultSet rs = null;
+        PreparedStatement statement = null;
+        StringBuilder buf = new StringBuilder();
+        try {
+            conn = getConnection(query.getTenantId());
+            statement = conn.prepareStatement("EXPLAIN " + query.getStatement());
+            rs = statement.executeQuery();
+            while (rs.next()) {
+                buf.append(rs.getString(1).trim().replace(",", "-"));
+            }
+            statement.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (rs != null) rs.close();
+            if (statement != null) statement.close();
+            if (conn != null) conn.close();
+        }
+        return buf.toString();
+    }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bf80d8e6/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/MultiThreadedRunner.java
----------------------------------------------------------------------
diff --git a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/MultiThreadedRunner.java
b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/MultiThreadedRunner.java
index 524724c..de6cdaf 100644
--- a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/MultiThreadedRunner.java
+++ b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/MultiThreadedRunner.java
@@ -57,14 +57,14 @@ class MultiThreadedRunner implements Runnable {
      * @param executionDurationInMs
      */
     MultiThreadedRunner(String threadName, Query query, DataModelResult dataModelResult,
-            ThreadTime threadTime, long numberOfExecutions, long executionDurationInMs) {
+            ThreadTime threadTime, long numberOfExecutions, long executionDurationInMs, boolean
writeRuntimeResults) {
         this.query = query;
         this.threadName = threadName;
         this.threadTime = threadTime;
         this.dataModelResult = dataModelResult;
         this.numberOfExecutions = numberOfExecutions;
         this.executionDurationInMs = executionDurationInMs;
-        this.resultManager = new ResultManager(dataModelResult.getName());
+       	this.resultManager = new ResultManager(dataModelResult.getName(), writeRuntimeResults);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bf80d8e6/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/MultithreadedDiffer.java
----------------------------------------------------------------------
diff --git a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/MultithreadedDiffer.java
b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/MultithreadedDiffer.java
index 91189e2..decff51 100644
--- a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/MultithreadedDiffer.java
+++ b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/MultithreadedDiffer.java
@@ -25,6 +25,7 @@ import org.apache.phoenix.pherf.PherfConstants;
 import org.apache.phoenix.pherf.configuration.Query;
 import org.apache.phoenix.pherf.result.RunTime;
 import org.apache.phoenix.pherf.result.ThreadTime;
+import org.apache.phoenix.pherf.util.PhoenixUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,6 +37,7 @@ class MultithreadedDiffer implements Runnable {
     private long numberOfExecutions;
     private long executionDurationInMs;
     private QueryVerifier queryVerifier = new QueryVerifier(true);
+    private static PhoenixUtil pUtil = PhoenixUtil.create();
 
     private synchronized ThreadTime getThreadTime() {
         return threadTime;
@@ -51,7 +53,7 @@ class MultithreadedDiffer implements Runnable {
         Date startDate = Calendar.getInstance().getTime();
         String newCSV = queryVerifier.exportCSV(query);
         boolean verifyResult = queryVerifier.doDiff(query, newCSV);
-        String explainPlan = queryVerifier.getExplainPlan(query);
+        String explainPlan = pUtil.getExplainPlan(query);
         getThreadTime().getRunTimesInMs().add(new RunTime(
                         verifyResult == true ? PherfConstants.DIFF_PASS : PherfConstants.DIFF_FAIL,
                         explainPlan, startDate, -1L, (int) (System.currentTimeMillis() -
start)));

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bf80d8e6/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/QueryExecutor.java
----------------------------------------------------------------------
diff --git a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/QueryExecutor.java
b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/QueryExecutor.java
index 50d7190..347e203 100644
--- a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/QueryExecutor.java
+++ b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/QueryExecutor.java
@@ -41,21 +41,29 @@ public class QueryExecutor implements Workload {
     private final XMLConfigParser parser;
     private final PhoenixUtil util;
     private final WorkloadExecutor workloadExecutor;
+    private final boolean writeRuntimeResults;
 
     public QueryExecutor(XMLConfigParser parser, PhoenixUtil util,
             WorkloadExecutor workloadExecutor) {
-        this(parser, util, workloadExecutor, parser.getDataModels(), null, false);
+        this(parser, util, workloadExecutor, parser.getDataModels(), null, false, true);
     }
 
     public QueryExecutor(XMLConfigParser parser, PhoenixUtil util,
             WorkloadExecutor workloadExecutor, List<DataModel> dataModels, String queryHint,
             boolean exportCSV) {
+    	this(parser, util, workloadExecutor, dataModels, queryHint, exportCSV, true);
+    }
+
+    public QueryExecutor(XMLConfigParser parser, PhoenixUtil util,
+            WorkloadExecutor workloadExecutor, List<DataModel> dataModels, String queryHint,
+            boolean exportCSV, boolean writeRuntimeResults) {
         this.parser = parser;
         this.queryHint = queryHint;
         this.exportCSV = exportCSV;
         this.dataModels = dataModels;
         this.util = util;
         this.workloadExecutor = workloadExecutor;
+        this.writeRuntimeResults = writeRuntimeResults;
     }
 
     @Override
@@ -262,7 +270,7 @@ public class QueryExecutor implements Workload {
             thread =
                     new MultiThreadedRunner(threadTime.getThreadName(), queryResult,
                             dataModelResult, threadTime, querySet.getNumberOfExecutions(),
-                            querySet.getExecutionDurationInMs());
+                            querySet.getExecutionDurationInMs(), writeRuntimeResults);
         } else {
             thread =
                     new MultithreadedDiffer(threadTime.getThreadName(), queryResult, threadTime,

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bf80d8e6/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/QueryVerifier.java
----------------------------------------------------------------------
diff --git a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/QueryVerifier.java
b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/QueryVerifier.java
index c9333a0..7b2bb12 100644
--- a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/QueryVerifier.java
+++ b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/workload/QueryVerifier.java
@@ -141,36 +141,6 @@ public class QueryVerifier {
     }
 
     /**
-     * Get explain plan for a query
-     *
-     * @param query
-     * @return
-     * @throws SQLException
-     */
-    public String getExplainPlan(Query query) throws SQLException {
-        Connection conn = null;
-        ResultSet rs = null;
-        PreparedStatement statement = null;
-        StringBuilder buf = new StringBuilder();
-        try {
-            conn = pUtil.getConnection(query.getTenantId());
-            statement = conn.prepareStatement("EXPLAIN " + query.getStatement());
-            rs = statement.executeQuery();
-            while (rs.next()) {
-                buf.append(rs.getString(1).trim().replace(",", "-"));
-            }
-            statement.close();
-        } catch (Exception e) {
-            e.printStackTrace();
-        } finally {
-            if (rs != null) rs.close();
-            if (statement != null) statement.close();
-            if (conn != null) conn.close();
-        }
-        return buf.toString();
-    }
-
-    /**
      * Helper method to generate CSV file name
      *
      * @param query


Mime
View raw message