From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- .../MotionMark/resources/runner/animometer.js | 626 +++++++++++++++++++++ 1 file changed, 626 insertions(+) create mode 100644 third_party/webkit/PerformanceTests/MotionMark/resources/runner/animometer.js (limited to 'third_party/webkit/PerformanceTests/MotionMark/resources/runner/animometer.js') diff --git a/third_party/webkit/PerformanceTests/MotionMark/resources/runner/animometer.js b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/animometer.js new file mode 100644 index 0000000000..65e8c5450d --- /dev/null +++ b/third_party/webkit/PerformanceTests/MotionMark/resources/runner/animometer.js @@ -0,0 +1,626 @@ +ResultsDashboard = Utilities.createClass( + function(options, testData) + { + this._iterationsSamplers = []; + this._options = options; + this._results = null; + if (testData) { + this._iterationsSamplers = testData; + this._processData(); + } + }, { + + push: function(suitesSamplers) + { + this._iterationsSamplers.push(suitesSamplers); + }, + + _processData: function() + { + this._results = {}; + this._results[Strings.json.results.iterations] = []; + + var iterationsScores = []; + this._iterationsSamplers.forEach(function(iteration, index) { + var testsScores = []; + var testsLowerBoundScores = []; + var testsUpperBoundScores = []; + + var result = {}; + this._results[Strings.json.results.iterations][index] = result; + + var suitesResult = {}; + result[Strings.json.results.tests] = suitesResult; + + for (var suiteName in iteration) { + var suiteData = iteration[suiteName]; + + var suiteResult = {}; + suitesResult[suiteName] = suiteResult; + + for (var testName in suiteData) { + if (!suiteData[testName][Strings.json.result]) + this.calculateScore(suiteData[testName]); + + suiteResult[testName] = suiteData[testName][Strings.json.result]; + delete suiteData[testName][Strings.json.result]; + + testsScores.push(suiteResult[testName][Strings.json.score]); + testsLowerBoundScores.push(suiteResult[testName][Strings.json.scoreLowerBound]); + testsUpperBoundScores.push(suiteResult[testName][Strings.json.scoreUpperBound]); + } + } + + result[Strings.json.score] = Statistics.geometricMean(testsScores); + result[Strings.json.scoreLowerBound] = Statistics.geometricMean(testsLowerBoundScores); + result[Strings.json.scoreUpperBound] = Statistics.geometricMean(testsUpperBoundScores); + iterationsScores.push(result[Strings.json.score]); + }, this); + + this._results[Strings.json.score] = Statistics.sampleMean(iterationsScores.length, iterationsScores.reduce(function(a, b) { return a + b; })); + this._results[Strings.json.scoreLowerBound] = this._results[Strings.json.results.iterations][0][Strings.json.scoreLowerBound]; + this._results[Strings.json.scoreUpperBound] = this._results[Strings.json.results.iterations][0][Strings.json.scoreUpperBound]; + }, + + calculateScore: function(data) + { + var result = {}; + data[Strings.json.result] = result; + var samples = data[Strings.json.samples]; + + var desiredFrameLength = 1000/60; + if (this._options["controller"] == "ramp30") + desiredFrameLength = 1000/30; + + function findRegression(series, profile) { + var minIndex = Math.round(.025 * series.length); + var maxIndex = Math.round(.975 * (series.length - 1)); + var minComplexity = series.getFieldInDatum(minIndex, Strings.json.complexity); + var maxComplexity = series.getFieldInDatum(maxIndex, Strings.json.complexity); + + if (Math.abs(maxComplexity - minComplexity) < 20 && maxIndex - minIndex < 20) { + minIndex = 0; + maxIndex = series.length - 1; + minComplexity = series.getFieldInDatum(minIndex, Strings.json.complexity); + maxComplexity = series.getFieldInDatum(maxIndex, Strings.json.complexity); + } + + var complexityIndex = series.fieldMap[Strings.json.complexity]; + var frameLengthIndex = series.fieldMap[Strings.json.frameLength]; + var regressionOptions = { desiredFrameLength: desiredFrameLength }; + if (profile) + regressionOptions.preferredProfile = profile; + return { + minComplexity: minComplexity, + maxComplexity: maxComplexity, + samples: series.slice(minIndex, maxIndex + 1), + regression: new Regression( + series.data, + function (data, i) { return data[i][complexityIndex]; }, + function (data, i) { return data[i][frameLengthIndex]; }, + minIndex, maxIndex, regressionOptions) + }; + } + + var complexitySamples; + // Convert these samples into SampleData objects if needed + [Strings.json.complexity, Strings.json.complexityAverage, Strings.json.controller].forEach(function(seriesName) { + var series = samples[seriesName]; + if (series && !(series instanceof SampleData)) + samples[seriesName] = new SampleData(series.fieldMap, series.data); + }); + + var isRampController = ["ramp", "ramp30"].indexOf(this._options["controller"]) != -1; + var predominantProfile = ""; + if (isRampController) { + var profiles = {}; + data[Strings.json.controller].forEach(function(regression) { + if (regression[Strings.json.regressions.profile]) { + var profile = regression[Strings.json.regressions.profile]; + profiles[profile] = (profiles[profile] || 0) + 1; + } + }); + + var maxProfileCount = 0; + for (var profile in profiles) { + if (profiles[profile] > maxProfileCount) { + predominantProfile = profile; + maxProfileCount = profiles[profile]; + } + } + } + + [Strings.json.complexity, Strings.json.complexityAverage].forEach(function(seriesName) { + if (!(seriesName in samples)) + return; + + var regression = {}; + result[seriesName] = regression; + var regressionResult = findRegression(samples[seriesName], predominantProfile); + if (seriesName == Strings.json.complexity) + complexitySamples = regressionResult.samples; + var calculation = regressionResult.regression; + regression[Strings.json.regressions.segment1] = [ + [regressionResult.minComplexity, calculation.s1 + calculation.t1 * regressionResult.minComplexity], + [calculation.complexity, calculation.s1 + calculation.t1 * calculation.complexity] + ]; + regression[Strings.json.regressions.segment2] = [ + [calculation.complexity, calculation.s2 + calculation.t2 * calculation.complexity], + [regressionResult.maxComplexity, calculation.s2 + calculation.t2 * regressionResult.maxComplexity] + ]; + regression[Strings.json.complexity] = calculation.complexity; + regression[Strings.json.measurements.stdev] = Math.sqrt(calculation.error / samples[seriesName].length); + }); + + if (isRampController) { + var timeComplexity = new Experiment; + data[Strings.json.controller].forEach(function(regression) { + timeComplexity.sample(regression[Strings.json.complexity]); + }); + + var experimentResult = {}; + result[Strings.json.controller] = experimentResult; + experimentResult[Strings.json.score] = timeComplexity.mean(); + experimentResult[Strings.json.measurements.average] = timeComplexity.mean(); + experimentResult[Strings.json.measurements.stdev] = timeComplexity.standardDeviation(); + experimentResult[Strings.json.measurements.percent] = timeComplexity.percentage(); + + const bootstrapIterations = 2500; + var bootstrapResult = Regression.bootstrap(complexitySamples.data, bootstrapIterations, function(resampleData) { + var complexityIndex = complexitySamples.fieldMap[Strings.json.complexity]; + resampleData.sort(function(a, b) { + return a[complexityIndex] - b[complexityIndex]; + }); + + var resample = new SampleData(complexitySamples.fieldMap, resampleData); + var regressionResult = findRegression(resample, predominantProfile); + return regressionResult.regression.complexity; + }, .8); + + result[Strings.json.complexity][Strings.json.bootstrap] = bootstrapResult; + result[Strings.json.score] = bootstrapResult.median; + result[Strings.json.scoreLowerBound] = bootstrapResult.confidenceLow; + result[Strings.json.scoreUpperBound] = bootstrapResult.confidenceHigh; + } else { + var marks = data[Strings.json.marks]; + var samplingStartIndex = 0, samplingEndIndex = -1; + if (Strings.json.samplingStartTimeOffset in marks) + samplingStartIndex = marks[Strings.json.samplingStartTimeOffset].index; + if (Strings.json.samplingEndTimeOffset in marks) + samplingEndIndex = marks[Strings.json.samplingEndTimeOffset].index; + + var averageComplexity = new Experiment; + var averageFrameLength = new Experiment; + var controllerSamples = samples[Strings.json.controller]; + controllerSamples.forEach(function (sample, i) { + if (i >= samplingStartIndex && (samplingEndIndex == -1 || i < samplingEndIndex)) { + averageComplexity.sample(controllerSamples.getFieldInDatum(sample, Strings.json.complexity)); + var smoothedFrameLength = controllerSamples.getFieldInDatum(sample, Strings.json.smoothedFrameLength); + if (smoothedFrameLength && smoothedFrameLength != -1) + averageFrameLength.sample(smoothedFrameLength); + } + }); + + var experimentResult = {}; + result[Strings.json.controller] = experimentResult; + experimentResult[Strings.json.measurements.average] = averageComplexity.mean(); + experimentResult[Strings.json.measurements.concern] = averageComplexity.concern(Experiment.defaults.CONCERN); + experimentResult[Strings.json.measurements.stdev] = averageComplexity.standardDeviation(); + experimentResult[Strings.json.measurements.percent] = averageComplexity.percentage(); + + experimentResult = {}; + result[Strings.json.frameLength] = experimentResult; + experimentResult[Strings.json.measurements.average] = 1000 / averageFrameLength.mean(); + experimentResult[Strings.json.measurements.concern] = averageFrameLength.concern(Experiment.defaults.CONCERN); + experimentResult[Strings.json.measurements.stdev] = averageFrameLength.standardDeviation(); + experimentResult[Strings.json.measurements.percent] = averageFrameLength.percentage(); + + result[Strings.json.score] = averageComplexity.score(Experiment.defaults.CONCERN); + result[Strings.json.scoreLowerBound] = result[Strings.json.score] - averageFrameLength.standardDeviation(); + result[Strings.json.scoreUpperBound] = result[Strings.json.score] + averageFrameLength.standardDeviation(); + } + }, + + get data() + { + return this._iterationsSamplers; + }, + + get results() + { + if (this._results) + return this._results[Strings.json.results.iterations]; + this._processData(); + return this._results[Strings.json.results.iterations]; + }, + + get options() + { + return this._options; + }, + + _getResultsProperty: function(property) + { + if (this._results) + return this._results[property]; + this._processData(); + return this._results[property]; + }, + + get score() + { + return this._getResultsProperty(Strings.json.score); + }, + + get scoreLowerBound() + { + return this._getResultsProperty(Strings.json.scoreLowerBound); + }, + + get scoreUpperBound() + { + return this._getResultsProperty(Strings.json.scoreUpperBound); + } +}); + +ResultsTable = Utilities.createClass( + function(element, headers) + { + this.element = element; + this._headers = headers; + + this._flattenedHeaders = []; + this._headers.forEach(function(header) { + if (header.disabled) + return; + + if (header.children) + this._flattenedHeaders = this._flattenedHeaders.concat(header.children); + else + this._flattenedHeaders.push(header); + }, this); + + this._flattenedHeaders = this._flattenedHeaders.filter(function (header) { + return !header.disabled; + }); + + this.clear(); + }, { + + clear: function() + { + this.element.textContent = ""; + }, + + _addHeader: function() + { + var thead = Utilities.createElement("thead", {}, this.element); + var row = Utilities.createElement("tr", {}, thead); + + this._headers.forEach(function (header) { + if (header.disabled) + return; + + var th = Utilities.createElement("th", {}, row); + if (header.title != Strings.text.graph) + th.innerHTML = header.title; + if (header.children) + th.colSpan = header.children.length; + }); + }, + + _addBody: function() + { + this.tbody = Utilities.createElement("tbody", {}, this.element); + }, + + _addEmptyRow: function() + { + var row = Utilities.createElement("tr", {}, this.tbody); + this._flattenedHeaders.forEach(function (header) { + return Utilities.createElement("td", { class: "suites-separator" }, row); + }); + }, + + _addTest: function(testName, testResult, options) + { + var row = Utilities.createElement("tr", {}, this.tbody); + + this._flattenedHeaders.forEach(function (header) { + var td = Utilities.createElement("td", {}, row); + if (header.text == Strings.text.testName) { + td.textContent = testName; + } else if (typeof header.text == "string") { + var data = testResult[header.text]; + if (typeof data == "number") + data = data.toFixed(2); + td.innerHTML = data; + } else + td.innerHTML = header.text(testResult); + }, this); + }, + + _addIteration: function(iterationResult, iterationData, options) + { + var testsResults = iterationResult[Strings.json.results.tests]; + for (var suiteName in testsResults) { + this._addEmptyRow(); + var suiteResult = testsResults[suiteName]; + var suiteData = iterationData[suiteName]; + for (var testName in suiteResult) + this._addTest(testName, suiteResult[testName], options, suiteData[testName]); + } + }, + + showIterations: function(dashboard) + { + this.clear(); + this._addHeader(); + this._addBody(); + + var iterationsResults = dashboard.results; + iterationsResults.forEach(function(iterationResult, index) { + this._addIteration(iterationResult, dashboard.data[index], dashboard.options); + }, this); + } +}); + +window.benchmarkRunnerClient = { + iterationCount: 1, + options: null, + results: null, + + initialize: function(suites, options) + { + this.options = options; + }, + + willStartFirstIteration: function() + { + this.results = new ResultsDashboard(this.options); + }, + + didRunSuites: function(suitesSamplers) + { + this.results.push(suitesSamplers); + }, + + didRunTest: function(testData) + { + this.results.calculateScore(testData); + }, + + didFinishLastIteration: function() + { + benchmarkController.showResults(); + } +}; + +window.sectionsManager = +{ + showSection: function(sectionIdentifier, pushState) + { + var sections = document.querySelectorAll("main > section"); + for (var i = 0; i < sections.length; ++i) { + document.body.classList.remove("showing-" + sections[i].id); + } + document.body.classList.add("showing-" + sectionIdentifier); + + 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); + }, + + setSectionScore: function(sectionIdentifier, score, confidence) + { + document.querySelector("#" + sectionIdentifier + " .score").textContent = score; + if (confidence) + document.querySelector("#" + sectionIdentifier + " .confidence").textContent = confidence; + }, + + populateTable: function(tableIdentifier, headers, dashboard) + { + var table = new ResultsTable(document.getElementById(tableIdentifier), headers); + table.showIterations(dashboard); + } +}; + +window.benchmarkController = { + initialize: function() + { + benchmarkController.addOrientationListenerIfNecessary(); + }, + + determineCanvasSize: function() { + var match = window.matchMedia("(max-device-width: 760px)"); + if (match.matches) { + document.body.classList.add("small"); + return; + } + + match = window.matchMedia("(max-device-width: 1600px)"); + if (match.matches) { + document.body.classList.add("medium"); + return; + } + + match = window.matchMedia("(max-width: 1600px)"); + if (match.matches) { + document.body.classList.add("medium"); + return; + } + + document.body.classList.add("large"); + }, + + addOrientationListenerIfNecessary: function() { + if (!("orientation" in window)) + return; + + this.orientationQuery = window.matchMedia("(orientation: landscape)"); + this._orientationChanged(this.orientationQuery); + this.orientationQuery.addListener(this._orientationChanged); + }, + + _orientationChanged: function(match) + { + benchmarkController.isInLandscapeOrientation = match.matches; + if (match.matches) + document.querySelector(".start-benchmark p").classList.add("hidden"); + else + document.querySelector(".start-benchmark p").classList.remove("hidden"); + benchmarkController.updateStartButtonState(); + }, + + updateStartButtonState: function() + { + document.getElementById("run-benchmark").disabled = !this.isInLandscapeOrientation; + }, + + _startBenchmark: function(suites, options, frameContainerID) + { + benchmarkController.determineCanvasSize(); + + var configuration = document.body.className.match(/small|medium|large/); + if (configuration) + options[Strings.json.configuration] = configuration[0]; + + benchmarkRunnerClient.initialize(suites, options); + var frameContainer = document.getElementById(frameContainerID); + var runner = new BenchmarkRunner(suites, frameContainer, benchmarkRunnerClient); + runner.runMultipleIterations(); + + sectionsManager.showSection("test-container"); + }, + + startBenchmark: function() + { + var options = { + "test-interval": 30, + "display": "minimal", + "tiles": "big", + "controller": "ramp", + "kalman-process-error": 1, + "kalman-measurement-error": 4, + "time-measurement": "performance" + }; + this._startBenchmark(Suites, options, "test-container"); + }, + + showResults: function() + { + if (!this.addedKeyEvent) { + document.addEventListener("keypress", this.handleKeyPress, false); + this.addedKeyEvent = true; + } + + var dashboard = benchmarkRunnerClient.results; + var score = dashboard.score; + var confidence = "±" + (Statistics.largestDeviationPercentage(dashboard.scoreLowerBound, score, dashboard.scoreUpperBound) * 100).toFixed(2) + "%"; + sectionsManager.setSectionScore("results", score.toFixed(2), confidence); + sectionsManager.populateTable("results-header", Headers.testName, dashboard); + sectionsManager.populateTable("results-score", Headers.score, dashboard); + sectionsManager.populateTable("results-data", Headers.details, dashboard); + sectionsManager.showSection("results", true); + }, + + handleKeyPress: function(event) + { + switch (event.charCode) + { + case 27: // esc + benchmarkController.hideDebugInfo(); + break; + case 106: // j + benchmarkController.showDebugInfo(); + break; + case 115: // s + benchmarkController.selectResults(event.target); + break; + } + }, + + hideDebugInfo: function() + { + var overlay = document.getElementById("overlay"); + if (!overlay) + return; + document.body.removeChild(overlay); + }, + + showDebugInfo: function() + { + if (document.getElementById("overlay")) + return; + + var overlay = Utilities.createElement("div", { + id: "overlay" + }, document.body); + var container = Utilities.createElement("div", {}, overlay); + + var header = Utilities.createElement("h3", {}, container); + header.textContent = "Debug Output"; + + var data = Utilities.createElement("div", {}, container); + data.textContent = "Please wait..."; + setTimeout(function() { + var output = { + options: benchmarkRunnerClient.results.options, + data: benchmarkRunnerClient.results.data + }; + data.textContent = JSON.stringify(output, function(key, value) { + if (typeof value === 'number') + return Utilities.toFixedNumber(value, 3); + return value; + }, 1); + }, 0); + data.onclick = function() { + var selection = window.getSelection(); + selection.removeAllRanges(); + var range = document.createRange(); + range.selectNode(data); + selection.addRange(range); + }; + + var button = Utilities.createElement("button", {}, container); + button.textContent = "Done"; + button.onclick = function() { + benchmarkController.hideDebugInfo(); + }; + }, + + selectResults: function(target) + { + target.selectRange = ((target.selectRange || 0) + 1) % 3; + + var selection = window.getSelection(); + selection.removeAllRanges(); + var range = document.createRange(); + switch (target.selectRange) { + case 0: { + range.selectNode(document.getElementById("results-score")); + break; + } + case 1: { + range.setStart(document.querySelector("#results .score"), 0); + range.setEndAfter(document.querySelector("#results-score"), 0); + break; + } + case 2: { + range.selectNodeContents(document.querySelector("#results .score")); + break; + } + } + selection.addRange(range); + } +}; + +window.addEventListener("load", function() { benchmarkController.initialize(); }); -- cgit v1.2.3