1 window.benchmarkClient = {
2 displayUnit: 'runs/min',
8 _progressCompleted: null,
9 willAddTestFrame: function (frame) {
10 var main = document.querySelector('main');
11 var style = getComputedStyle(main);
12 frame.style.left = main.offsetLeft + parseInt(style.borderLeftWidth) + parseInt(style.paddingLeft) + 'px';
13 frame.style.top = main.offsetTop + parseInt(style.borderTopWidth) + parseInt(style.paddingTop) + 'px';
15 willRunTest: function (suite, test) {
16 document.getElementById('info').textContent = suite.name + ' ( ' + this._finishedTestCount + ' / ' + this.testsCount + ' )';
18 didRunTest: function () {
19 this._finishedTestCount++;
20 this._progressCompleted.style.width = (this._finishedTestCount * 100 / this.testsCount) + '%';
22 didRunSuites: function (measuredValues) {
23 this._timeValues.push(measuredValues.total);
25 willStartFirstIteration: function () {
26 this._timeValues = [];
27 this._finishedTestCount = 0;
28 this._progressCompleted = document.getElementById('progress-completed');
29 document.getElementById('logo-link').onclick = function (event) { event.preventDefault(); return false; }
31 didFinishLastIteration: function () {
32 document.getElementById('logo-link').onclick = null;
34 var results = this._computeResults(this._timeValues, this.displayUnit);
36 this._updateGaugeNeedle(results.mean);
37 document.getElementById('result-number').textContent = results.formattedMean;
38 if (results.formattedDelta)
39 document.getElementById('confidence-number').textContent = '\u00b1 ' + results.formattedDelta;
41 this._populateDetailedResults(results.formattedValues);
42 document.getElementById('results-with-statistics').textContent = results.formattedMeanAndDelta;
44 if (this.displayUnit == 'ms') {
45 document.getElementById('show-summary').style.display = 'none';
50 _computeResults: function (timeValues, displayUnit) {
51 var suitesCount = this.suitesCount;
52 function totalTimeInDisplayUnit(time) {
53 if (displayUnit == 'ms')
55 return computeScore(time);
58 function sigFigFromPercentDelta(percentDelta) {
59 return Math.ceil(-Math.log(percentDelta)/Math.log(10)) + 3;
62 function toSigFigPrecision(number, sigFig) {
63 var nonDecimalDigitCount = number < 1 ? 0 : (Math.floor(Math.log(number)/Math.log(10)) + 1);
64 return number.toPrecision(Math.max(nonDecimalDigitCount, Math.min(6, sigFig)));
67 var values = timeValues.map(totalTimeInDisplayUnit);
68 var sum = values.reduce(function (a, b) { return a + b; }, 0);
69 var arithmeticMean = sum / values.length;
72 var formattedPercentDelta;
73 if (window.Statistics) {
74 var delta = Statistics.confidenceIntervalDelta(0.95, values.length, sum, Statistics.squareSum(values));
76 var percentDelta = delta * 100 / arithmeticMean;
77 meanSigFig = sigFigFromPercentDelta(percentDelta);
78 formattedDelta = toSigFigPrecision(delta, 2);
79 formattedPercentDelta = toSigFigPrecision(percentDelta, 2) + '%';
83 var formattedMean = toSigFigPrecision(arithmeticMean, Math.max(meanSigFig, 3));
86 formattedValues: timeValues.map(function (time) {
87 return toSigFigPrecision(totalTimeInDisplayUnit(time), 4) + ' ' + displayUnit;
90 formattedMean: formattedMean,
91 formattedDelta: formattedDelta,
92 formattedMeanAndDelta: formattedMean + (formattedDelta ? ' \xb1 ' + formattedDelta + ' (' + formattedPercentDelta + ')' : ''),
95 _addDetailedResultsRow: function (table, iterationNumber, value) {
96 var row = document.createElement('tr');
97 var th = document.createElement('th');
98 th.textContent = 'Iteration ' + (iterationNumber + 1);
99 var td = document.createElement('td');
100 td.textContent = value;
103 table.appendChild(row);
105 _updateGaugeNeedle: function (rpm) {
106 var needleAngle = Math.max(0, Math.min(rpm, 140)) - 70;
107 var needleRotationValue = 'rotate(' + needleAngle + 'deg)';
109 var gaugeNeedleElement = document.querySelector('#summarized-results > .gauge .needle');
110 gaugeNeedleElement.style.setProperty('-webkit-transform', needleRotationValue);
111 gaugeNeedleElement.style.setProperty('-moz-transform', needleRotationValue);
112 gaugeNeedleElement.style.setProperty('-ms-transform', needleRotationValue);
113 gaugeNeedleElement.style.setProperty('transform', needleRotationValue);
115 _populateDetailedResults: function (formattedValues) {
116 var resultsTables = document.querySelectorAll('.results-table');
118 resultsTables[0].innerHTML = '';
119 for (; i < Math.ceil(formattedValues.length / 2); i++)
120 this._addDetailedResultsRow(resultsTables[0], i, formattedValues[i]);
121 resultsTables[1].innerHTML = '';
122 for (; i < formattedValues.length; i++)
123 this._addDetailedResultsRow(resultsTables[1], i, formattedValues[i]);
125 prepareUI: function () {
126 window.addEventListener('popstate', function (event) {
128 var sectionToShow = event.state.section;
130 var sections = document.querySelectorAll('main > section');
131 for (var i = 0; i < sections.length; i++) {
132 if (sections[i].id === sectionToShow)
133 return showSection(sectionToShow, false);
137 return showSection('home', false);
140 function updateScreenSize() {
141 // FIXME: Detect when the window size changes during the test.
142 var screenIsTooSmall = window.innerWidth < 850 || window.innerHeight < 650;
143 document.getElementById('screen-size').textContent = window.innerWidth + 'px by ' + window.innerHeight + 'px';
144 document.getElementById('screen-size-warning').style.display = screenIsTooSmall ? null : 'none';
147 window.addEventListener('resize', updateScreenSize);
152 function startBenchmark() {
153 if (location.search.length > 1) {
154 var parts = location.search.substring(1).split('&');
155 for (var i = 0; i < parts.length; i++) {
156 var keyValue = parts[i].split('=');
157 var key = keyValue[0];
158 var value = keyValue[1];
162 benchmarkClient.displayUnit = 'ms';
164 console.error('Invalid unit: ' + value);
166 case 'iterationCount':
167 var parsedValue = parseInt(value);
169 benchmarkClient.iterationCount = parsedValue;
171 console.error('Invalid iteration count: ' + value);
177 var enabledSuites = Suites.filter(function (suite) { return !suite.disabled });
178 var totalSubtestCount = enabledSuites.reduce(function (testsCount, suite) { return testsCount + suite.tests.length; }, 0);
179 benchmarkClient.testsCount = benchmarkClient.iterationCount * totalSubtestCount;
180 benchmarkClient.suitesCount = enabledSuites.length;
181 var runner = new BenchmarkRunner(Suites, benchmarkClient);
182 runner.runMultipleIterations(benchmarkClient.iterationCount);
185 function computeScore(time) {
186 return 60 * 1000 * benchmarkClient.suitesCount / time;
189 function showSection(sectionIdentifier, pushState) {
190 var currentSectionElement = document.querySelector('section.selected');
191 console.assert(currentSectionElement);
193 var newSectionElement = document.getElementById(sectionIdentifier);
194 console.assert(newSectionElement);
196 currentSectionElement.classList.remove('selected');
197 newSectionElement.classList.add('selected');
200 history.pushState({section: sectionIdentifier}, document.title);
203 function showHome() {
204 showSection('home', true);
207 function startTest() {
208 showSection('running');
212 function showResultsSummary() {
213 showSection('summarized-results', true);
216 function showResultDetails() {
217 showSection('detailed-results', true);
220 function showAbout() {
221 showSection('about', true);
224 window.addEventListener('DOMContentLoaded', function () {
225 if (benchmarkClient.prepareUI)
226 benchmarkClient.prepareUI();