Bug 60091 - Report / Dashboard : Have a new report containing min/max and percentiles graphs

Bugzilla Id: 60091

git-svn-id: https://svn.apache.org/repos/asf/jmeter/trunk@1759482 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Philippe Mouawad 2016-09-06 18:46:27 +00:00
parent 56adf7e455
commit 11cfa7eebb
9 changed files with 406 additions and 4 deletions

View File

@ -676,7 +676,7 @@ var responseTimesOverTimeInfos = {
axisLabelPadding: 20,
},
yaxis: {
axisLabel: "Average response time in ms",
axisLabel: "Response time in ms",
axisLabelUseCanvas: true,
axisLabelFontSizePixels: 12,
axisLabelFontFamily: 'Verdana, Arial',
@ -753,7 +753,7 @@ var latenciesOverTimeInfos = {
axisLabelPadding: 20,
},
yaxis: {
axisLabel: "Average Response latencies in ms",
axisLabel: "Response latencies in ms",
axisLabelUseCanvas: true,
axisLabelFontSizePixels: 12,
axisLabelFontFamily: 'Verdana, Arial',
@ -885,6 +885,85 @@ function refreshConnectTimeOverTime(fixTimestamps) {
}
};
var responseTimePercentilesOverTimeInfos = {
data: ${responseTimePercentilesOverTime!"{}"},
getOptions: function() {
return {
series: {
lines: {
show: true,
fill: true
},
points: {
show: true
}
},
xaxis: {
mode: "time",
timeformat: "%H:%M:%S",
axisLabel: getElapsedTimeLabel(this.data.result.granularity),
axisLabelUseCanvas: true,
axisLabelFontSizePixels: 12,
axisLabelFontFamily: 'Verdana, Arial',
axisLabelPadding: 20,
},
yaxis: {
axisLabel: "Response Time in ms",
axisLabelUseCanvas: true,
axisLabelFontSizePixels: 12,
axisLabelFontFamily: 'Verdana, Arial',
axisLabelPadding: 20,
},
legend: {
noColumns: 2,
show: true,
container: '#legendResponseTimePercentilesOverTime'
},
selection: {
mode: 'xy'
},
grid: {
hoverable: true // IMPORTANT! this is needed for tooltip to
// work
},
tooltip: true,
tooltipOpts: {
content: "%s : at %x Response time was %y ms"
}
};
},
createGraph: function () {
var data = this.data;
var dataset = prepareData(data.result.series, $("#choicesResponseTimePercentilesOverTime"));
var options = this.getOptions();
prepareOptions(options, data);
$.plot($("#flotResponseTimePercentilesOverTime"), dataset, options);
// setup overview
$.plot($("#overviewResponseTimePercentilesOverTime"), dataset, prepareOverviewOptions(options));
}
};
// Response Time Percentiles Over Time
function refreshResponseTimePercentilesOverTime(fixTimestamps) {
var infos = responseTimePercentilesOverTimeInfos;
prepareSeries(infos.data);
if(fixTimestamps) {
fixTimeStamps(infos.data.result.series, ${(timeZoneOffset?c)!0});
}
if(isGraph($("#flotResponseTimePercentilesOverTime"))) {
infos.createGraph();
}else {
var choiceContainer = $("#choicesResponseTimePercentilesOverTime");
createLegend(choiceContainer, infos);
infos.createGraph();
setGraphZoomable("#flotResponseTimePercentilesOverTime", "#overviewResponseTimePercentilesOverTime");
$('#footerResponseTimePercentilesOverTime .legendColorBox > div').each(function(i){
$(this).clone().prependTo(choiceContainer.find("li").eq(i));
});
}
};
var responseTimeVsRequestInfos = {
data: ${responseTimeVsRequest!"{}"},
getOptions: function() {
@ -1278,6 +1357,11 @@ function collapse(elem, collapsed){
refreshConnectTimeOverTime(true);
}
document.location.href="#connectTimeOverTime";
} else if (elem.id == "bodyResponseTimePercentilesOverTime") {
if (isGraph($(elem).find('.flot-chart-content')) == false) {
refreshResponseTimePercentilesOverTime(true);
}
document.location.href="#connectTimeOverTime";
} else if (elem.id == "bodyResponseTimeDistribution") {
if (isGraph($(elem).find('.flot-chart-content')) == false) {
refreshResponseTimeDistribution();
@ -1364,6 +1448,9 @@ function toggleAll(id, checked){
} else if ( id == "choicesConnectTimeOverTime"){
choiceContainer = $("#choicesConnectTimeOverTime");
refreshConnectTimeOverTime(false);
} else if ( id == "responseTimePercentilesOverTime"){
choiceContainer = $("#choicesResponseTimePercentilesOverTime");
refreshResponseTimePercentilesOverTime(false);
} else if ( id == "choicesResponseTimePercentiles"){
choiceContainer = $("#choicesResponseTimePercentiles");
refreshResponseTimePercentiles();

View File

@ -72,6 +72,11 @@
Response Times Over Time
</a>
</li>
<li>
<a href="OverTime.html#responseTimePercentilesOverTime" onclick="$('#bodyResponseTimePercentilesOverTime').collapse('show');">
Response Time Percentiles Over Time (successful responses)
</a>
</li>
<li>
<a href="OverTime.html#bytesThroughputOverTime" onclick="$('#bodyBytesThroughputOverTime').collapse('show');">
Bytes Throughput Over Time
@ -214,6 +219,56 @@
<!-- /.panel -->
</div>
<!-- /.col-lg-12 -->
<!-- /.col-lg-12 -->
<div class="col-lg-12 portlet" id="responseTimePercentilesOverTime">
<div class="panel panel-default">
<div class="panel-heading portlet-header">
<i class="fa fa-bar-chart-o fa-fw"></i>
<span type="button" class="dropdown-toggle click-title span-title" data-toggle="collapse" href="#bodyResponseTimePercentilesOverTime" aria-expanded="true" aria-controls="bodyResponseTimePercentilesOverTime">Response Time Percentiles Over Time</span>
<div class="pull-right">
<div class="btn-group">
<a class="btn btn-link btn-xs">
<i class="glyphicon glyphicon-resize-vertical"></i>
</a>
<button type="button" class="btn btn-link btn-xs dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-wrench"></i>
</button>
<ul class="dropdown-menu dropdown-user">
<li><a href="#responseTimePercentilesOverTime" onClick="checkAll('choicesResponseTimePercentilesOverTime');">Display all samples</a>
</li>
<li><a href="#responseTimePercentilesOverTime" onClick="uncheckAll('choicesResponseTimePercentilesOverTime');">Hide all samples</a>
</li>
<li><a href="#responseTimePercentilesOverTime" onclick="exportToPNG('flotResponseTimePercentilesOverTime', this);">Save as PNG</a></li>
</ul>
<button type="button" class="btn btn-link btn-xs dropdown-toggle" data-toggle="collapse" href="#bodyResponseTimePercentilesOverTime" aria-expanded="true" aria-controls="bodyResponseTimePercentilesOverTime">
<i class="fa fa-chevron-down"></i>
</button>
</div>
</div>
</div>
<!-- /.panel-heading -->
<div class="collapse out portlet-content" id="bodyResponseTimePercentilesOverTime">
<div class="panel-body" id="collapseConnectTime">
<div class="flot-chart">
<div class="flot-chart-content" id="flotResponseTimePercentilesOverTime" style="float: left; width:80%;"></div>
<div style="float:left;margin-left:5px">
<p>Zoom :</p>
<div id="overviewResponseTimePercentilesOverTime" style="width:190px;height:100px;"></div>
</div>
</div>
</div>
<div class="panel-footer" id="footerResponseTimePercentilesOverTime">
<p id="legendResponseTimePercentilesOverTime" hidden></p>
<ul id="choicesResponseTimePercentilesOverTime" class="legend"></ul>
</div>
</div>
<!-- /.panel-body -->
</div>
<!-- /.panel -->
</div>
<!-- /.col-lg-12 -->
<div class="col-lg-12 portlet" id="bytesThroughputOverTime">
<div class="panel panel-default">
@ -359,8 +414,6 @@
<!-- /.panel -->
</div>
<!-- /.col-lg-6 -->
<!-- /.col-lg-6 -->
</div>
<!-- /.row -->
</div>

View File

@ -89,6 +89,11 @@ jmeter.reportgenerator.graph.responseTimesOverTime.classname=org.apache.jmeter.r
jmeter.reportgenerator.graph.responseTimesOverTime.title=Response Time Over Time
jmeter.reportgenerator.graph.responseTimesOverTime.property.set_granularity=${jmeter.reportgenerator.overall_granularity}
# Percentiles Response Times over time
jmeter.reportgenerator.graph.responseTimePercentilesOverTime.classname=org.apache.jmeter.report.processor.graph.impl.ResponseTimePercentilesOverTimeGraphConsumer
jmeter.reportgenerator.graph.responseTimePercentilesOverTime.title Response Time Percentiles Over Time
jmeter.reportgenerator.graph.responseTimePercentilesOverTime.property.set_granularity=${jmeter.reportgenerator.overall_granularity}
# Synthetic Response Time Distribution
jmeter.reportgenerator.graph.syntheticResponseTimeDistribution.classname=org.apache.jmeter.report.processor.graph.impl.SyntheticResponseTimeDistributionGraphConsumer
jmeter.reportgenerator.graph.syntheticResponseTimeDistribution.title=Synthetic Response Times Distribution

View File

@ -0,0 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.jmeter.report.processor;
/**
* A factory for creating MaxAggregator objects.
*
* @since 3.1
*/
public class MaxAggregatorFactory extends AbstractAggregatorFactory {
/*
* (non-Javadoc)
*
* @see
* org.apache.jmeter.report.core.AbstractAggregatorFactory#createAggregator
* ()
*/
@Override
protected Aggregator createAggregator() {
return new MaxAggregator();
}
}

View File

@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.jmeter.report.processor;
/**
* A factory for creating MinAggregator objects.
*
* @since 3.1
*/
public class MinAggregatorFactory extends AbstractAggregatorFactory {
/**
* @see
* org.apache.jmeter.report.core.AbstractAggregatorFactory#createAggregator
* ()
*/
@Override
protected Aggregator createAggregator() {
return new MinAggregator();
}
}

View File

@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.jmeter.report.processor.graph;
import org.apache.jmeter.report.core.Sample;
/**
* The class ElapsedTimeValueSelector provides a projection from a sample to its
* elapsed time only if sample is not an empty transaction Controller and sample is successful
*
* @since 3.1
*/
public class SuccessfulElapsedTimeValueSelector extends ElapsedTimeValueSelector {
/**
* @see
* org.apache.jmeter.report.csv.processor.GraphValueSelector#select(java
* .lang.String, java.lang.Object, org.apache.jmeter.report.csv.core.Sample)
*/
@Override
public Double select(String series, Sample sample) {
if(!sample.isEmptyController() && sample.getSuccess()) {
return Double.valueOf(sample.getElapsedTime());
} else {
return null;
}
}
}

View File

@ -0,0 +1,132 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.jmeter.report.processor.graph.impl;
import java.util.HashMap;
import java.util.Map;
import org.apache.jmeter.report.processor.MaxAggregatorFactory;
import org.apache.jmeter.report.processor.MinAggregatorFactory;
import org.apache.jmeter.report.processor.PercentileAggregatorFactory;
import org.apache.jmeter.report.processor.graph.AbstractOverTimeGraphConsumer;
import org.apache.jmeter.report.processor.graph.GroupInfo;
import org.apache.jmeter.report.processor.graph.StaticSeriesSelector;
import org.apache.jmeter.report.processor.graph.SuccessfulElapsedTimeValueSelector;
import org.apache.jmeter.report.processor.graph.TimeStampKeysSelector;
import org.apache.jmeter.util.JMeterUtils;
/**
* The class ResponseTimePercentilesOverTimeGraphConsumer provides a graph to visualize percentiles
* over time period.
* Only successful responses are taken into account for computations
*
* @since 3.1
*/
public class ResponseTimePercentilesOverTimeGraphConsumer extends
AbstractOverTimeGraphConsumer {
private static final String PERCENTILE_FORMAT = "%dth percentile";
/*
* (non-Javadoc)
*
* @see
* org.apache.jmeter.report.csv.processor.impl.AbstractOverTimeGraphConsumer
* #createTimeStampKeysSelector()
*/
@Override
protected TimeStampKeysSelector createTimeStampKeysSelector() {
TimeStampKeysSelector keysSelector = new TimeStampKeysSelector();
keysSelector.setSelectBeginTime(false);
return keysSelector;
}
/**
* Creates the group info for elapsed time percentile depending on jmeter
* properties.
*
* @param propertyKey
* the property key
* @param defaultValue
* the default value
* @param serieName Serie name
* @return the group info
*/
private GroupInfo createPercentileGroupInfo(String propertyKey, int defaultValue, String serieName) {
int property = JMeterUtils.getPropDefault(propertyKey, defaultValue);
PercentileAggregatorFactory factory = new PercentileAggregatorFactory();
factory.setPercentileIndex(property);
StaticSeriesSelector seriesSelector = new StaticSeriesSelector();
seriesSelector.setSeriesName(serieName);
return new GroupInfo(factory, seriesSelector,
new SuccessfulElapsedTimeValueSelector(), false, false);
}
/**
* Creates the group info for min elapsed time
* @return the group info
*/
private GroupInfo createMinGroupInfo() {
StaticSeriesSelector seriesSelector = new StaticSeriesSelector();
seriesSelector.setSeriesName("Min");
return new GroupInfo(new MinAggregatorFactory(), seriesSelector,
new SuccessfulElapsedTimeValueSelector(), false, false);
}
/**
* Creates the group info for max elapsed time
* @return the group info
*/
private GroupInfo createMaxGroupInfo() {
StaticSeriesSelector seriesSelector = new StaticSeriesSelector();
seriesSelector.setSeriesName("Max");
return new GroupInfo(new MaxAggregatorFactory(), seriesSelector,
new SuccessfulElapsedTimeValueSelector(), false, false);
}
/**
*
* @see org.apache.jmeter.report.csv.processor.impl.AbstractGraphConsumer#createGroupInfos()
*/
@Override
protected Map<String, GroupInfo> createGroupInfos() {
HashMap<String, GroupInfo> groupInfos = new HashMap<>(2);
groupInfos.put("aggregate_report_min", //$NON-NLS-1$
createMinGroupInfo());
groupInfos.put("aggregate_report_max", //$NON-NLS-1$
createMaxGroupInfo());
groupInfos.put("aggregate_rpt_pct1", //$NON-NLS-1$
createPercentileGroupInfo("aggregate_rpt_pct1", 90, //$NON-NLS-1$
String.format(
PERCENTILE_FORMAT, Integer.valueOf(90))));
groupInfos.put("aggregate_rpt_pct2", //$NON-NLS-1$
createPercentileGroupInfo("aggregate_rpt_pct2", 95, //$NON-NLS-1$
String.format(
PERCENTILE_FORMAT, Integer.valueOf(95))));
groupInfos.put("aggregate_rpt_pct3", //$NON-NLS-1$
createPercentileGroupInfo("aggregate_rpt_pct3", 99,//$NON-NLS-1$
String.format(
PERCENTILE_FORMAT, Integer.valueOf(99))));
return groupInfos;
}
}

View File

@ -140,6 +140,7 @@ Summary
<li><bug>60065</bug>Report / Dashboard : Improve Dashboard Error Summary by adding response message to "Type of error". Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
<li><bug>60079</bug>Report / Dashboard : Add a new "Response Time Overview" graph</li>
<li><bug>60080</bug>Report / Dashboard : Add a new "Connect Time Over Time " graph. Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
<li><bug>60091</bug>Report / Dashboard : Have a new report containing min/max and percentiles graphs.</li>
</ul>
<ch_section>Non-functional changes</ch_section>

View File

@ -612,6 +612,11 @@ jmeter.reportgenerator.exporter.html.filters_only_sample_series=true
over time.</td>
<td>True</td>
</tr>
<tr>
<td>ResponseTimePercentilesOverTimeGraphConsumer</td>
<td>This graph shows Min/Max and 3 percentiles response time over time.</td>
<td>True</td>
</tr>
<tr>
<td>ResponseTimeVSRequestGraphConsumer</td>
<td>This graph represents the median and average response time