| window.benchmarkClient = { |
| displayUnit: 'runs/min', |
| iterationCount: 10, |
| stepCount: null, |
| suitesCount: null, |
| _measuredValuesList: [], |
| _finishedTestCount: 0, |
| _progressCompleted: null, |
| willAddTestFrame: function (frame) { |
| var main = document.querySelector('main'); |
| var style = getComputedStyle(main); |
| frame.style.left = main.offsetLeft + parseInt(style.borderLeftWidth) + parseInt(style.paddingLeft) + 'px'; |
| frame.style.top = main.offsetTop + parseInt(style.borderTopWidth) + parseInt(style.paddingTop) + 'px'; |
| }, |
| willRunTest: function (suite, test) { |
| document.getElementById('info').textContent = suite.name + ' ( ' + this._finishedTestCount + ' / ' + this.stepCount + ' )'; |
| }, |
| didRunTest: function () { |
| this._finishedTestCount++; |
| this._progressCompleted.style.width = (this._finishedTestCount * 100 / this.stepCount) + '%'; |
| }, |
| didRunSuites: function (measuredValues) { |
| this._measuredValuesList.push(measuredValues); |
| }, |
| willStartFirstIteration: function () { |
| this._measuredValuesList = []; |
| this._finishedTestCount = 0; |
| this._progressCompleted = document.getElementById('progress-completed'); |
| document.getElementById('logo-link').onclick = function (event) { event.preventDefault(); return false; } |
| }, |
| didFinishLastIteration: function () { |
| document.getElementById('logo-link').onclick = null; |
| |
| var results = this._computeResults(this._measuredValuesList, this.displayUnit); |
| |
| this._updateGaugeNeedle(results.mean); |
| document.getElementById('result-number').textContent = results.formattedMean; |
| if (results.formattedDelta) |
| document.getElementById('confidence-number').textContent = '\u00b1 ' + results.formattedDelta; |
| |
| this._populateDetailedResults(results.formattedValues); |
| document.getElementById('results-with-statistics').textContent = results.formattedMeanAndDelta; |
| |
| if (this.displayUnit == 'ms') { |
| document.getElementById('show-summary').style.display = 'none'; |
| showResultDetails(); |
| } else |
| showResultsSummary(); |
| }, |
| _computeResults: function (measuredValuesList, displayUnit) { |
| var suitesCount = this.suitesCount; |
| function valueForUnit(measuredValues) { |
| if (displayUnit == 'ms') |
| return measuredValues.geomean; |
| return measuredValues.score; |
| } |
| |
| function sigFigFromPercentDelta(percentDelta) { |
| return Math.ceil(-Math.log(percentDelta)/Math.log(10)) + 3; |
| } |
| |
| function toSigFigPrecision(number, sigFig) { |
| var nonDecimalDigitCount = number < 1 ? 0 : (Math.floor(Math.log(number)/Math.log(10)) + 1); |
| return number.toPrecision(Math.max(nonDecimalDigitCount, Math.min(6, sigFig))); |
| } |
| |
| var values = measuredValuesList.map(valueForUnit); |
| var sum = values.reduce(function (a, b) { return a + b; }, 0); |
| var arithmeticMean = sum / values.length; |
| var meanSigFig = 4; |
| var formattedDelta; |
| var formattedPercentDelta; |
| if (window.Statistics) { |
| var delta = Statistics.confidenceIntervalDelta(0.95, values.length, sum, Statistics.squareSum(values)); |
| if (!isNaN(delta)) { |
| var percentDelta = delta * 100 / arithmeticMean; |
| meanSigFig = sigFigFromPercentDelta(percentDelta); |
| formattedDelta = toSigFigPrecision(delta, 2); |
| formattedPercentDelta = toSigFigPrecision(percentDelta, 2) + '%'; |
| } |
| } |
| |
| var formattedMean = toSigFigPrecision(arithmeticMean, Math.max(meanSigFig, 3)); |
| |
| return { |
| formattedValues: values.map(function (value) { |
| return toSigFigPrecision(value, 4) + ' ' + displayUnit; |
| }), |
| mean: arithmeticMean, |
| formattedMean: formattedMean, |
| formattedDelta: formattedDelta, |
| formattedMeanAndDelta: formattedMean + (formattedDelta ? ' \xb1 ' + formattedDelta + ' (' + formattedPercentDelta + ')' : ''), |
| }; |
| }, |
| _addDetailedResultsRow: function (table, iterationNumber, value) { |
| var row = document.createElement('tr'); |
| var th = document.createElement('th'); |
| th.textContent = 'Iteration ' + (iterationNumber + 1); |
| var td = document.createElement('td'); |
| td.textContent = value; |
| row.appendChild(th); |
| row.appendChild(td); |
| table.appendChild(row); |
| }, |
| _updateGaugeNeedle: function (rpm) { |
| var needleAngle = Math.max(0, Math.min(rpm, 140)) - 70; |
| var needleRotationValue = 'rotate(' + needleAngle + 'deg)'; |
| |
| var gaugeNeedleElement = document.querySelector('#summarized-results > .gauge .needle'); |
| gaugeNeedleElement.style.setProperty('-webkit-transform', needleRotationValue); |
| gaugeNeedleElement.style.setProperty('-moz-transform', needleRotationValue); |
| gaugeNeedleElement.style.setProperty('-ms-transform', needleRotationValue); |
| gaugeNeedleElement.style.setProperty('transform', needleRotationValue); |
| }, |
| _populateDetailedResults: function (formattedValues) { |
| var resultsTables = document.querySelectorAll('.results-table'); |
| var i = 0; |
| resultsTables[0].innerHTML = ''; |
| for (; i < Math.ceil(formattedValues.length / 2); i++) |
| this._addDetailedResultsRow(resultsTables[0], i, formattedValues[i]); |
| resultsTables[1].innerHTML = ''; |
| for (; i < formattedValues.length; i++) |
| this._addDetailedResultsRow(resultsTables[1], i, formattedValues[i]); |
| }, |
| prepareUI: function () { |
| window.addEventListener('popstate', function (event) { |
| if (event.state) { |
| var sectionToShow = event.state.section; |
| if (sectionToShow) { |
| var sections = document.querySelectorAll('main > section'); |
| for (var i = 0; i < sections.length; i++) { |
| if (sections[i].id === sectionToShow) |
| return showSection(sectionToShow, false); |
| } |
| } |
| } |
| return showSection('home', false); |
| }, false); |
| |
| function updateScreenSize() { |
| // FIXME: Detect when the window size changes during the test. |
| var screenIsTooSmall = window.innerWidth < 850 || window.innerHeight < 650; |
| document.getElementById('screen-size').textContent = window.innerWidth + 'px by ' + window.innerHeight + 'px'; |
| document.getElementById('screen-size-warning').style.display = screenIsTooSmall ? null : 'none'; |
| } |
| |
| window.addEventListener('resize', updateScreenSize); |
| updateScreenSize(); |
| } |
| } |
| |
| function enableOneSuite(suites, suiteToEnable) |
| { |
| suiteToEnable = suiteToEnable.toLowerCase(); |
| var found = false; |
| for (var i = 0; i < suites.length; i++) { |
| var currentSuite = suites[i]; |
| if (currentSuite.name.toLowerCase() == suiteToEnable) { |
| currentSuite.disabled = false; |
| found = true; |
| } else |
| currentSuite.disabled = true; |
| } |
| return found; |
| } |
| |
| function startBenchmark() { |
| if (location.search.length > 1) { |
| var parts = location.search.substring(1).split('&'); |
| for (var i = 0; i < parts.length; i++) { |
| var keyValue = parts[i].split('='); |
| var key = keyValue[0]; |
| var value = keyValue[1]; |
| switch (key) { |
| case 'unit': |
| if (value == 'ms') |
| benchmarkClient.displayUnit = 'ms'; |
| else |
| console.error('Invalid unit: ' + value); |
| break; |
| case 'iterationCount': |
| var parsedValue = parseInt(value); |
| if (!isNaN(parsedValue)) |
| benchmarkClient.iterationCount = parsedValue; |
| else |
| console.error('Invalid iteration count: ' + value); |
| break; |
| case 'suite': |
| if (!enableOneSuite(Suites, value)) { |
| alert('Suite "' + value + '" does not exist. No tests to run.'); |
| return false; |
| } |
| break; |
| } |
| } |
| } |
| |
| var enabledSuites = Suites.filter(function (suite) { return !suite.disabled; }); |
| var totalSubtestsCount = enabledSuites.reduce(function (testsCount, suite) { return testsCount + suite.tests.length; }, 0); |
| benchmarkClient.stepCount = benchmarkClient.iterationCount * totalSubtestsCount; |
| benchmarkClient.suitesCount = enabledSuites.length; |
| var runner = new BenchmarkRunner(Suites, benchmarkClient); |
| runner.runMultipleIterations(benchmarkClient.iterationCount); |
| |
| return true; |
| } |
| |
| function showSection(sectionIdentifier, pushState) { |
| var currentSectionElement = document.querySelector('section.selected'); |
| console.assert(currentSectionElement); |
| |
| var newSectionElement = document.getElementById(sectionIdentifier); |
| console.assert(newSectionElement); |
| |
| currentSectionElement.classList.remove('selected'); |
| newSectionElement.classList.add('selected'); |
| |
| if (pushState) |
| history.pushState({section: sectionIdentifier}, document.title); |
| } |
| |
| function showHome() { |
| showSection('home', true); |
| } |
| |
| function startTest() { |
| if (startBenchmark()) |
| showSection('running'); |
| } |
| |
| function showResultsSummary() { |
| showSection('summarized-results', true); |
| } |
| |
| function showResultDetails() { |
| showSection('detailed-results', true); |
| } |
| |
| function showAbout() { |
| showSection('about', true); |
| } |
| |
| window.addEventListener('DOMContentLoaded', function () { |
| if (benchmarkClient.prepareUI) |
| benchmarkClient.prepareUI(); |
| }); |