[
https://issues.apache.org/jira/browse/PHOENIX-2182?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14726273#comment-14726273
]
ASF GitHub Bot commented on PHOENIX-2182:
-----------------------------------------
Github user codymarcel commented on a diff in the pull request:
https://github.com/apache/phoenix/pull/115#discussion_r38477085
--- Diff:
phoenix-pherf/src/main/java/org/apache/phoenix/pherf/util/ResultsComparator.java
---
@@ -0,0 +1,353 @@
+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 ResultsComparator {
+
+ 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 ResultsComparator(String labels) {
+ this.setLabelsAsString(labels);
+ }
+
+ String[] getLabels() {
+ return labels;
+ }
+
+ void setLabels(String[] labels) {
+ this.labels = labels;
+ }
+
+ void setLabelsAsString(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 ((((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 summaryDir =
PherfConstants.create().getProperty("pherf.default.summary.dir");
+ PrintWriter writer = new PrintWriter(summaryDir + "/" +
PherfConstants.SUMMARY_HTML_FILE_NAME, "UTF-8");
+ writer.println(StaticGoogleChartsRenderingData.HEADER);
+ 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]", labels[0]);
+ 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>"
--- End diff --
Perhaps we should use an html generation library instead of hard coding all
this in strings?
Never tried this one, bit looks like it has god template support.
http://freemarker.org/docs/dgui_quickstart_basics.html
> Pherf - Add ability to compare of run(s) and generate warning if performance
> degrades beyond set threshold
> ----------------------------------------------------------------------------------------------------------
>
> Key: PHOENIX-2182
> URL: https://issues.apache.org/jira/browse/PHOENIX-2182
> Project: Phoenix
> Issue Type: Improvement
> Reporter: Mujtaba Chohan
> Assignee: Mujtaba Chohan
> Attachments: PHOENIX-2182.patch
>
>
> Add ability to compare of run(s) and generate warning if performance degrades
> beyond set threshold. This would also need that runs can be labeled for known
> baselines.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)