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 <mujt...@apache.org> Authored: Mon Sep 21 13:02:37 2015 -0700 Committer: Mujtaba <mujt...@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