phoenix-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "ASF GitHub Bot (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (PHOENIX-2182) Pherf - Add ability to compare of run(s) and generate warning if performance degrades beyond set threshold
Date Tue, 01 Sep 2015 21:53:45 GMT

    [ 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)

Mime
View raw message