blob: c89c2b68bbb96c621053d8f6088e4713242c1b3e [file] [log] [blame]
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
//
// Licensed 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.
/**
* @fileoverview A table for showing the results of performance testing.
*
* {@see goog.testing.benchmark} for an easy way to use this functionality.
*
* @author attila@google.com (Attila Bodis)
* @author nicksantos@google.com (Nick Santos)
*/
goog.provide('goog.testing.PerformanceTable');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.testing.PerformanceTimer');
/**
* A UI widget that runs performance tests and displays the results.
* @param {Element} root The element where the table should be attached.
* @param {goog.testing.PerformanceTimer=} opt_timer A timer to use for
* executing functions and profiling them.
* @param {number=} opt_precision Number of digits of precision to include in
* results. Defaults to 0.
* @param {number=} opt_numSamples The number of samples to take. Defaults to 5.
* @constructor
* @final
*/
goog.testing.PerformanceTable = function(
root, opt_timer, opt_precision, opt_numSamples) {
/**
* Where the table should be attached.
* @private {Element}
*/
this.root_ = root;
/**
* Number of digits of precision to include in results.
* Defaults to 0.
* @private {number}
*/
this.precision_ = opt_precision || 0;
var timer = opt_timer;
if (!timer) {
timer = new goog.testing.PerformanceTimer();
timer.setNumSamples(opt_numSamples || 5);
timer.setDiscardOutliers(true);
}
/**
* A timer for running the tests.
* @private {goog.testing.PerformanceTimer}
*/
this.timer_ = timer;
this.initRoot_();
};
/**
* @return {goog.testing.PerformanceTimer} The timer being used.
*/
goog.testing.PerformanceTable.prototype.getTimer = function() {
return this.timer_;
};
/**
* Render the initial table.
* @private
*/
goog.testing.PerformanceTable.prototype.initRoot_ = function() {
this.root_.innerHTML =
'<table class="test-results" cellspacing="1">' +
' <thead>' +
' <tr>' +
' <th rowspan="2">Test Description</th>' +
' <th rowspan="2">Runs</th>' +
' <th colspan="4">Results (ms)</th>' +
' </tr>' +
' <tr>' +
' <th>Average</th>' +
' <th>Std Dev</th>' +
' <th>Minimum</th>' +
' <th>Maximum</th>' +
' </tr>' +
' </thead>' +
' <tbody>' +
' </tbody>' +
'</table>';
};
/**
* @return {Element} The body of the table.
* @private
*/
goog.testing.PerformanceTable.prototype.getTableBody_ = function() {
return this.root_.getElementsByTagName(goog.dom.TagName.TBODY)[0];
};
/**
* Round to the specified precision.
* @param {number} num The number to round.
* @return {string} The rounded number, as a string.
* @private
*/
goog.testing.PerformanceTable.prototype.round_ = function(num) {
var factor = Math.pow(10, this.precision_);
return String(Math.round(num * factor) / factor);
};
/**
* Run the given function with the performance timer, and show the results.
* @param {Function} fn The function to run.
* @param {string=} opt_desc A description to associate with this run.
*/
goog.testing.PerformanceTable.prototype.run = function(fn, opt_desc) {
this.runTask(
new goog.testing.PerformanceTimer.Task(/** @type {function()} */ (fn)),
opt_desc);
};
/**
* Run the given task with the performance timer, and show the results.
* @param {goog.testing.PerformanceTimer.Task} task The performance timer task
* to run.
* @param {string=} opt_desc A description to associate with this run.
*/
goog.testing.PerformanceTable.prototype.runTask = function(task, opt_desc) {
var results = this.timer_.runTask(task);
this.recordResults(results, opt_desc);
};
/**
* Record a performance timer results object to the performance table. See
* {@code goog.testing.PerformanceTimer} for details of the format of this
* object.
* @param {Object} results The performance timer results object.
* @param {string=} opt_desc A description to associate with these results.
*/
goog.testing.PerformanceTable.prototype.recordResults = function(
results, opt_desc) {
var average = results['average'];
var standardDeviation = results['standardDeviation'];
var isSuspicious = average < 0 || standardDeviation > average * .5;
var resultsRow = goog.dom.createDom('tr', null,
goog.dom.createDom('td', 'test-description',
opt_desc || 'No description'),
goog.dom.createDom('td', 'test-count', String(results['count'])),
goog.dom.createDom('td', 'test-average', this.round_(average)),
goog.dom.createDom('td', 'test-standard-deviation',
this.round_(standardDeviation)),
goog.dom.createDom('td', 'test-minimum', String(results['minimum'])),
goog.dom.createDom('td', 'test-maximum', String(results['maximum'])));
if (isSuspicious) {
resultsRow.className = 'test-suspicious';
}
this.getTableBody_().appendChild(resultsRow);
};
/**
* Report an error in the table.
* @param {*} reason The reason for the error.
*/
goog.testing.PerformanceTable.prototype.reportError = function(reason) {
this.getTableBody_().appendChild(
goog.dom.createDom('tr', null,
goog.dom.createDom('td', {'class': 'test-error', 'colSpan': 5},
String(reason))));
};