"use strict"; /* * Copyright (C) 2018 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ const preloadResources = !isInBrowser; const measureTotalTimeAsSubtest = false; // Once we move to preloading all resources, it would be good to turn this on. if (typeof RAMification === "undefined") var RAMification = false; if (typeof testIterationCount === "undefined") var testIterationCount = undefined; if (typeof testIterationCountMap === "undefined") var testIterationCountMap = new Map; if (typeof testWorstCaseCountMap === "undefined") var testWorstCaseCountMap = new Map; if (typeof dumpJSONResults === "undefined") var dumpJSONResults = false; // Used for the promise representing the current benchmark run. this.currentResolve = null; this.currentReject = null; const defaultIterationCount = 120; const defaultWorstCaseCount = 4; let showScoreDetails = false; let categoryScores = null; function displayCategoryScores() { if (!categoryScores) return; let summaryElement = document.getElementById("result-summary"); for (let [category, scores] of categoryScores) summaryElement.innerHTML += `

${category}: ${uiFriendlyNumber(geomean(scores))}

` categoryScores = null; } function getIterationCount(plan) { if (testIterationCountMap.has(plan.name)) return testIterationCountMap.get(plan.name); if (testIterationCount) return testIterationCount; if (plan.iterations) return plan.iterations; return defaultIterationCount; } function getWorstCaseCount(plan) { if (testWorstCaseCountMap.has(plan.name)) return testWorstCaseCountMap.get(plan.name); if (plan.worstCaseCount) return plan.worstCaseCount; return defaultWorstCaseCount; } if (isInBrowser) { document.onkeydown = (keyboardEvent) => { let key = keyboardEvent.key; if (key === "d" || key === "D") { showScoreDetails = true; displayCategoryScores(); } }; } function assert(b, m = "") { if (!b) throw new Error("Bad assertion: " + m); } function firstID(benchmark) { return `results-cell-${benchmark.name}-first`; } function worst4ID(benchmark) { return `results-cell-${benchmark.name}-worst4`; } function avgID(benchmark) { return `results-cell-${benchmark.name}-avg`; } function scoreID(benchmark) { return `results-cell-${benchmark.name}-score`; } function mean(values) { assert(values instanceof Array); let sum = 0; for (let x of values) sum += x; return sum / values.length; } function geomean(values) { assert(values instanceof Array); let product = 1; for (let x of values) product *= x; return product ** (1 / values.length); } function toScore(timeValue) { return 5000 / timeValue; } function toTimeValue(score) { return 5000 / score; } function updateUI() { return new Promise((resolve) => { if (isInBrowser) requestAnimationFrame(() => setTimeout(resolve, 0)); else resolve(); }); } function uiFriendlyNumber(num) { if (Number.isInteger(num)) return num; return num.toFixed(3); } function uiFriendlyDuration(time) { let minutes = time.getMinutes(); let seconds = time.getSeconds(); let milliSeconds = time.getMilliseconds(); let result = "" + minutes + ":"; result = result + (seconds < 10 ? "0" : "") + seconds + "."; result = result + (milliSeconds < 10 ? "00" : (milliSeconds < 100 ? "0" : "")) + milliSeconds; return result; } const fileLoader = (function() { class Loader { constructor() { this.requests = new Map; } async _loadInternal(url) { if (!isInBrowser) return Promise.resolve(readFile(url)); let fetchResponse = await fetch(new Request(url)); if (url.indexOf(".js") !== -1) return await fetchResponse.text(); else if (url.indexOf(".wasm") !== -1) return await fetchResponse.arrayBuffer(); throw new Error("should not be reached!"); } async load(url) { if (this.requests.has(url)) return (await this.requests.get(url)); let promise = this._loadInternal(url); this.requests.set(url, promise); return (await promise); } } return new Loader; })(); class Driver { constructor() { this.benchmarks = []; } addPlan(plan, BenchmarkClass = DefaultBenchmark) { this.benchmarks.push(new BenchmarkClass(plan)); } async start() { let statusElement = false; let summaryElement = false; if (isInBrowser) { statusElement = document.getElementById("status"); summaryElement = document.getElementById("result-summary"); statusElement.innerHTML = ``; } else { console.log("Starting JetStream2"); } await updateUI(); let start = Date.now(); for (let benchmark of this.benchmarks) { benchmark.updateUIBeforeRun(); await updateUI(); try { await benchmark.run(); } catch(e) { JetStream.reportError(benchmark); throw e; } benchmark.updateUIAfterRun(); } let totalTime = Date.now() - start; if (measureTotalTimeAsSubtest) { if (isInBrowser) document.getElementById("benchmark-total-time-score").innerHTML = uiFriendlyNumber(totalTime); else console.log("Total time:", uiFriendlyNumber(totalTime)); allScores.push(totalTime); } let allScores = []; for (let benchmark of this.benchmarks) allScores.push(benchmark.score); categoryScores = new Map; for (let benchmark of this.benchmarks) { for (let category of Object.keys(benchmark.subTimes())) categoryScores.set(category, []); } for (let benchmark of this.benchmarks) { for (let [category, value] of Object.entries(benchmark.subTimes())) { let arr = categoryScores.get(category); arr.push(value); } } if (isInBrowser) { summaryElement.classList.add('done'); summaryElement.innerHTML = "
" + uiFriendlyNumber(geomean(allScores)) + "
"; summaryElement.onclick = displayCategoryScores; if (showScoreDetails) displayCategoryScores(); statusElement.innerHTML = ''; } else { console.log("\n"); for (let [category, scores] of categoryScores) console.log(`${category}: ${uiFriendlyNumber(geomean(scores))}`); console.log("\nTotal Score: ", uiFriendlyNumber(geomean(allScores)), "\n"); } this.reportScoreToRunBenchmarkRunner(); this.dumpJSONResultsIfNeeded(); } runCode(string) { if (!isInBrowser) { let scripts = string; let globalObject; let realm; if (isD8) { realm = Realm.createAllowCrossRealmAccess(); globalObject = Realm.global(realm); globalObject.loadString = function(s) { return Realm.eval(realm, s); }; globalObject.readFile = read; } else globalObject = runString(""); globalObject.console = {log:globalObject.print} globalObject.top = { currentResolve, currentReject }; for (let script of scripts) globalObject.loadString(script); return isD8 ? realm : globalObject; } var magic = document.getElementById("magic"); magic.contentDocument.body.textContent = ""; magic.contentDocument.body.innerHTML = "