| "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 += `<p> ${category}: ${uiFriendlyNumber(geomean(scores))}</p>` |
| |
| 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 = `<label>Running...</label>`; |
| } 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 = "<div class=\"score\">" + uiFriendlyNumber(geomean(allScores)) + "</div><label>Score</label>"; |
| 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 = "<iframe id=\"magicframe\" frameborder=\"0\">"; |
| |
| var magicFrame = magic.contentDocument.getElementById("magicframe"); |
| magicFrame.contentDocument.open(); |
| magicFrame.contentDocument.write("<!DOCTYPE html><head><title>benchmark payload</title></head><body>\n" + string + "</body></html>"); |
| |
| return magicFrame; |
| } |
| |
| prepareToRun() |
| { |
| this.benchmarks.sort((a, b) => a.plan.name.toLowerCase() < b.plan.name.toLowerCase() ? 1 : -1); |
| |
| let text = ""; |
| let newBenchmarks = []; |
| for (let benchmark of this.benchmarks) { |
| let id = JSON.stringify(benchmark.constructor.scoreDescription()); |
| let description = JSON.parse(id); |
| |
| newBenchmarks.push(benchmark); |
| let scoreIds = benchmark.scoreIdentifiers() |
| let overallScoreId = scoreIds.pop(); |
| |
| if (isInBrowser) { |
| text += |
| `<div class="benchmark" id="benchmark-${benchmark.name}"> |
| <h3 class="benchmark-name"><a href="in-depth.html#${benchmark.name}">${benchmark.name}</a></h3> |
| <h4 class="score" id="${overallScoreId}">___</h4><p>`; |
| for (let i = 0; i < scoreIds.length; i++) { |
| let id = scoreIds[i]; |
| let label = description[i]; |
| text += `<span class="result"><span id="${id}">___</span><label>${label}</label></span>` |
| } |
| text += `</p></div>`; |
| } |
| } |
| |
| if (!isInBrowser) |
| return; |
| |
| for (let f = 0; f < 5; f++) |
| text += `<div class="benchmark fill"></div>`; |
| |
| let timestamp = Date.now(); |
| document.getElementById('jetstreams').style.backgroundImage = `url('jetstreams.svg?${timestamp}')`; |
| let resultsTable = document.getElementById("results"); |
| resultsTable.innerHTML = text; |
| |
| document.getElementById("magic").textContent = ""; |
| document.addEventListener('keypress', function (e) { |
| if (e.which === 13) |
| JetStream.start(); |
| }); |
| } |
| |
| reportError(benchmark) |
| { |
| for (let id of benchmark.scoreIdentifiers()) |
| document.getElementById(id).innerHTML = "error"; |
| } |
| |
| async initialize() { |
| await this.fetchResources(); |
| this.prepareToRun(); |
| if (isInBrowser && window.location.search == '?report=true') { |
| setTimeout(() => this.start(), 4000); |
| } |
| } |
| |
| async fetchResources() { |
| for (let benchmark of this.benchmarks) |
| await benchmark.fetchResources(); |
| |
| if (!isInBrowser) |
| return; |
| |
| let statusElement = document.getElementById("status"); |
| statusElement.classList.remove('loading'); |
| statusElement.innerHTML = `<a href="javascript:JetStream.start()" class="button">Start Test</a>`; |
| statusElement.onclick = () => { |
| statusElement.onclick = null; |
| JetStream.start(); |
| return false; |
| } |
| } |
| |
| resultsJSON() |
| { |
| let results = {}; |
| for (let benchmark of this.benchmarks) { |
| const subResults = {} |
| const subTimes = benchmark.subTimes(); |
| for (const name in subTimes) { |
| subResults[name] = {"metrics": {"Time": {"current": [toTimeValue(subTimes[name])]}}}; |
| } |
| results[benchmark.name] = { |
| "metrics" : { |
| "Score" : {"current" : [benchmark.score]}, |
| "Time": ["Geometric"], |
| }, |
| "tests": subResults, |
| }; |
| } |
| |
| results = {"JetStream2.0": {"metrics" : {"Score" : ["Geometric"]}, "tests" : results}}; |
| |
| return JSON.stringify(results); |
| } |
| |
| dumpJSONResultsIfNeeded() |
| { |
| if (dumpJSONResults) { |
| console.log("\n"); |
| console.log(this.resultsJSON()); |
| console.log("\n"); |
| } |
| } |
| |
| async reportScoreToRunBenchmarkRunner() |
| { |
| if (!isInBrowser) |
| return; |
| |
| if (window.location.search !== '?report=true') |
| return; |
| |
| const content = this.resultsJSON(); |
| await fetch("/report", { |
| method: "POST", |
| heeaders: { |
| "Content-Type": "application/json", |
| "Content-Length": content.length, |
| "Connection": "close", |
| }, |
| body: content, |
| }); |
| } |
| }; |
| |
| class Benchmark { |
| constructor(plan) |
| { |
| this.plan = plan; |
| this.iterations = getIterationCount(plan); |
| this.isAsync = !!plan.isAsync; |
| |
| this.scripts = null; |
| |
| this._resourcesPromise = null; |
| this.fetchResources(); |
| } |
| |
| get name() { return this.plan.name; } |
| |
| get runnerCode() { |
| return ` |
| let __benchmark = new Benchmark(${this.iterations}); |
| let results = []; |
| for (let i = 0; i < ${this.iterations}; i++) { |
| if (__benchmark.prepareForNextIteration) |
| __benchmark.prepareForNextIteration(); |
| |
| let start = Date.now(); |
| __benchmark.runIteration(); |
| let end = Date.now(); |
| |
| results.push(Math.max(1, end - start)); |
| } |
| if (__benchmark.validate) |
| __benchmark.validate(); |
| top.currentResolve(results);`; |
| } |
| |
| processResults() { |
| throw new Error("Subclasses need to implement this"); |
| } |
| |
| get score() { |
| throw new Error("Subclasses need to implement this"); |
| } |
| |
| get prerunCode() { return null; } |
| |
| async run() { |
| let code; |
| if (isInBrowser) |
| code = ""; |
| else |
| code = []; |
| |
| let addScript = (text) => { |
| if (isInBrowser) |
| code += `<script>${text}</script>`; |
| else |
| code.push(text); |
| }; |
| |
| let addScriptWithURL = (url) => { |
| if (isInBrowser) |
| code += `<script src="${url}"></script>`; |
| else |
| assert(false, "Should not reach here in CLI"); |
| }; |
| |
| addScript(`const isInBrowser = ${isInBrowser}; let performance = {now: Date.now.bind(Date)};`); |
| |
| if (!!this.plan.deterministicRandom) { |
| addScript(` |
| Math.random = (function() { |
| var seed = 49734321; |
| return function() { |
| // Robert Jenkins' 32 bit integer hash function. |
| seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff; |
| seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff; |
| seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff; |
| seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff; |
| seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff; |
| seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff; |
| return (seed & 0xfffffff) / 0x10000000; |
| }; |
| })(); |
| `); |
| |
| } |
| |
| if (this.plan.preload) { |
| let str = ""; |
| for (let [variableName, blobUrl] of this.preloads) |
| str += `const ${variableName} = "${blobUrl}";\n`; |
| addScript(str); |
| } |
| |
| let prerunCode = this.prerunCode; |
| if (prerunCode) |
| addScript(prerunCode); |
| |
| if (preloadResources) { |
| assert(this.scripts && this.scripts.length === this.plan.files.length); |
| |
| for (let text of this.scripts) |
| addScript(text); |
| } else { |
| for (let file of this.plan.files) |
| addScriptWithURL(file); |
| } |
| |
| let promise = new Promise((resolve, reject) => { |
| currentResolve = resolve; |
| currentReject = reject; |
| }); |
| |
| if (isInBrowser) { |
| code = ` |
| <script> window.onerror = top.currentReject; </script> |
| ${code} |
| `; |
| } |
| addScript(this.runnerCode); |
| |
| this.startTime = new Date(); |
| |
| if (RAMification) |
| resetMemoryPeak(); |
| |
| let magicFrame; |
| try { |
| magicFrame = JetStream.runCode(code); |
| } catch(e) { |
| console.log("Error in runCode: ", e); |
| throw e; |
| } |
| let results = await promise; |
| |
| this.endTime = new Date(); |
| |
| if (RAMification) { |
| let memoryFootprint = MemoryFootprint(); |
| this.currentFootprint = memoryFootprint.current; |
| this.peakFootprint = memoryFootprint.peak; |
| } |
| |
| this.processResults(results); |
| if (isInBrowser) |
| magicFrame.contentDocument.close(); |
| else if (isD8) |
| Realm.dispose(magicFrame); |
| } |
| |
| fetchResources() { |
| if (this._resourcesPromise) |
| return this._resourcesPromise; |
| |
| let filePromises = preloadResources ? this.plan.files.map((file) => fileLoader.load(file)) : []; |
| let preloads = []; |
| let preloadVariableNames = []; |
| |
| if (isInBrowser && this.plan.preload) { |
| for (let prop of Object.getOwnPropertyNames(this.plan.preload)) { |
| preloadVariableNames.push(prop); |
| preloads.push(this.plan.preload[prop]); |
| } |
| } |
| |
| preloads = preloads.map((file) => fileLoader.load(file)); |
| |
| let p1 = Promise.all(filePromises).then((texts) => { |
| if (!preloadResources) |
| return; |
| this.scripts = []; |
| assert(texts.length === this.plan.files.length); |
| for (let text of texts) |
| this.scripts.push(text); |
| }); |
| |
| let p2 = Promise.all(preloads).then((data) => { |
| this.preloads = []; |
| this.blobs = []; |
| for (let i = 0; i < data.length; ++i) { |
| let item = data[i]; |
| |
| let blob; |
| if (typeof item === "string") { |
| blob = new Blob([item], {type : 'application/javascript'}); |
| } else if (item instanceof ArrayBuffer) { |
| blob = new Blob([item], {type : 'application/octet-stream'}); |
| } else |
| throw new Error("Unexpected item!"); |
| |
| this.blobs.push(blob); |
| this.preloads.push([preloadVariableNames[i], URL.createObjectURL(blob)]); |
| } |
| }); |
| |
| this._resourcesPromise = Promise.all([p1, p2]); |
| return this._resourcesPromise; |
| } |
| |
| static scoreDescription() { throw new Error("Must be implemented by subclasses."); } |
| scoreIdentifiers() { throw new Error("Must be implemented by subclasses"); } |
| |
| updateUIBeforeRun() { |
| if (!isInBrowser) { |
| console.log(`Running ${this.name}:`); |
| return; |
| } |
| |
| let containerUI = document.getElementById("results"); |
| let resultsBenchmarkUI = document.getElementById(`benchmark-${this.name}`); |
| containerUI.insertBefore(resultsBenchmarkUI, containerUI.firstChild); |
| resultsBenchmarkUI.classList.add("benchmark-running"); |
| |
| for (let id of this.scoreIdentifiers()) |
| document.getElementById(id).innerHTML = "..."; |
| } |
| |
| updateUIAfterRun() { |
| if (!isInBrowser) |
| return; |
| |
| let benchmarkResultsUI = document.getElementById(`benchmark-${this.name}`); |
| benchmarkResultsUI.classList.remove("benchmark-running"); |
| benchmarkResultsUI.classList.add("benchmark-done"); |
| |
| } |
| }; |
| |
| class DefaultBenchmark extends Benchmark { |
| constructor(...args) { |
| super(...args); |
| |
| this.worstCaseCount = getWorstCaseCount(this.plan); |
| this.firstIteration = null; |
| this.worst4 = null; |
| this.average = null; |
| } |
| |
| processResults(results) { |
| function copyArray(a) { |
| let result = []; |
| for (let x of a) |
| result.push(x); |
| return result; |
| } |
| results = copyArray(results); |
| |
| this.firstIteration = toScore(results[0]); |
| |
| results = results.slice(1); |
| results.sort((a, b) => a < b ? 1 : -1); |
| for (let i = 0; i + 1 < results.length; ++i) |
| assert(results[i] >= results[i + 1]); |
| |
| let worstCase = []; |
| for (let i = 0; i < this.worstCaseCount; ++i) |
| worstCase.push(results[i]); |
| this.worst4 = toScore(mean(worstCase)); |
| this.average = toScore(mean(results)); |
| } |
| |
| get score() { |
| return geomean([this.firstIteration, this.worst4, this.average]); |
| } |
| |
| subTimes() { |
| return { |
| "First": this.firstIteration, |
| "Worst": this.worst4, |
| "Average": this.average, |
| }; |
| } |
| |
| static scoreDescription() { |
| return ["First", "Worst", "Average", "Score"]; |
| } |
| |
| scoreIdentifiers() { |
| return [firstID(this), worst4ID(this), avgID(this), scoreID(this)]; |
| } |
| |
| updateUIAfterRun() { |
| super.updateUIAfterRun(); |
| |
| if (isInBrowser) { |
| document.getElementById(firstID(this)).innerHTML = uiFriendlyNumber(this.firstIteration); |
| document.getElementById(worst4ID(this)).innerHTML = uiFriendlyNumber(this.worst4); |
| document.getElementById(avgID(this)).innerHTML = uiFriendlyNumber(this.average); |
| document.getElementById(scoreID(this)).innerHTML = uiFriendlyNumber(this.score); |
| return; |
| } |
| |
| console.log(" Startup:", uiFriendlyNumber(this.firstIteration)); |
| console.log(" Worst Case:", uiFriendlyNumber(this.worst4)); |
| console.log(" Average:", uiFriendlyNumber(this.average)); |
| console.log(" Score:", uiFriendlyNumber(this.score)); |
| if (RAMification) { |
| console.log(" Current Footprint:", uiFriendlyNumber(this.currentFootprint)); |
| console.log(" Peak Footprint:", uiFriendlyNumber(this.peakFootprint)); |
| } |
| console.log(" Wall time:", uiFriendlyDuration(new Date(this.endTime - this.startTime))); |
| } |
| } |
| |
| class AsyncBenchmark extends DefaultBenchmark { |
| get runnerCode() { |
| return ` |
| async function doRun() { |
| let __benchmark = new Benchmark(); |
| let results = []; |
| for (let i = 0; i < ${this.iterations}; i++) { |
| let start = Date.now(); |
| await __benchmark.runIteration(); |
| let end = Date.now(); |
| results.push(Math.max(1, end - start)); |
| } |
| if (__benchmark.validate) |
| __benchmark.validate(); |
| top.currentResolve(results); |
| } |
| doRun();` |
| } |
| }; |
| |
| class WSLBenchmark extends Benchmark { |
| constructor(...args) { |
| super(...args); |
| |
| this.stdlib = null; |
| this.mainRun = null; |
| } |
| |
| processResults(results) { |
| this.stdlib = toScore(results[0]); |
| this.mainRun = toScore(results[1]); |
| } |
| |
| get score() { |
| return geomean([this.stdlib, this.mainRun]); |
| } |
| |
| get runnerCode() { |
| return ` |
| let benchmark = new Benchmark(); |
| let results = []; |
| { |
| let start = Date.now(); |
| benchmark.buildStdlib(); |
| results.push(Date.now() - start); |
| } |
| |
| { |
| let start = Date.now(); |
| benchmark.run(); |
| results.push(Date.now() - start); |
| } |
| |
| top.currentResolve(results); |
| `; |
| } |
| |
| subTimes() { |
| return { |
| "Stdlib": this.stdlib, |
| "MainRun": this.mainRun, |
| }; |
| } |
| |
| static scoreDescription() { |
| return ["Stdlib", "MainRun", "Score"]; |
| } |
| |
| scoreIdentifiers() { |
| return ["wsl-stdlib-score", "wsl-tests-score", "wsl-score-score"]; |
| } |
| |
| updateUIAfterRun() { |
| super.updateUIAfterRun(); |
| |
| if (isInBrowser) { |
| document.getElementById("wsl-stdlib-score").innerHTML = uiFriendlyNumber(this.stdlib); |
| document.getElementById("wsl-tests-score").innerHTML = uiFriendlyNumber(this.mainRun); |
| document.getElementById("wsl-score-score").innerHTML = uiFriendlyNumber(this.score); |
| return; |
| } |
| |
| console.log(" Stdlib:", uiFriendlyNumber(this.stdlib)); |
| console.log(" Tests:", uiFriendlyNumber(this.mainRun)); |
| console.log(" Score:", uiFriendlyNumber(this.score)); |
| if (RAMification) { |
| console.log(" Current Footprint:", uiFriendlyNumber(this.currentFootprint)); |
| console.log(" Peak Footprint:", uiFriendlyNumber(this.peakFootprint)); |
| } |
| console.log(" Wall time:", uiFriendlyDuration(new Date(this.endTime - this.startTime))); |
| } |
| }; |
| |
| class WasmBenchmark extends Benchmark { |
| constructor(...args) { |
| super(...args); |
| |
| this.startupTime = null; |
| this.runTime = null; |
| } |
| |
| processResults(results) { |
| this.startupTime = toScore(results[0]); |
| this.runTime = toScore(results[1]); |
| } |
| |
| get score() { |
| return geomean([this.startupTime, this.runTime]); |
| } |
| |
| get wasmPath() { |
| return this.plan.wasmPath; |
| } |
| |
| get prerunCode() { |
| let str = ` |
| let verbose = false; |
| |
| let compileTime = null; |
| let runTime = null; |
| |
| let globalObject = this; |
| |
| globalObject.benchmarkTime = Date.now.bind(Date); |
| |
| globalObject.reportCompileTime = (t) => { |
| if (compileTime !== null) |
| throw new Error("called report compile time twice"); |
| compileTime = t; |
| }; |
| |
| globalObject.reportRunTime = (t) => { |
| if (runTime !== null) |
| throw new Error("called report run time twice") |
| runTime = t; |
| top.currentResolve([compileTime, runTime]); |
| }; |
| |
| abort = quit = function() { |
| if (verbose) |
| console.log('Intercepted quit/abort'); |
| }; |
| |
| oldPrint = globalObject.print; |
| globalObject.print = globalObject.printErr = (...args) => { |
| if (verbose) |
| console.log('Intercepted print: ', ...args); |
| }; |
| |
| let Module = { |
| preRun: [], |
| postRun: [], |
| print: function() { }, |
| printErr: function() { }, |
| setStatus: function(text) { |
| }, |
| totalDependencies: 0, |
| monitorRunDependencies: function(left) { |
| this.totalDependencies = Math.max(this.totalDependencies, left); |
| Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.'); |
| } |
| }; |
| globalObject.Module = Module; |
| `; |
| return str; |
| } |
| |
| get runnerCode() { |
| let str = ""; |
| if (isInBrowser) { |
| str += ` |
| var xhr = new XMLHttpRequest(); |
| xhr.open('GET', wasmBlobURL, true); |
| xhr.responseType = 'arraybuffer'; |
| xhr.onload = function() { |
| Module.wasmBinary = xhr.response; |
| doRun(); |
| }; |
| xhr.send(null); |
| `; |
| } else { |
| str += ` |
| Module.wasmBinary = read("${this.wasmPath}", "binary"); |
| globalObject.read = (...args) => { |
| console.log("should not be inside read: ", ...args); |
| throw new Error; |
| }; |
| |
| Module.setStatus = null; |
| Module.monitorRunDependencies = null; |
| |
| Promise.resolve(42).then(() => { |
| try { |
| doRun(); |
| } catch(e) { |
| console.log("error running wasm:", e); |
| throw e; |
| } |
| }) |
| `; |
| } |
| return str; |
| } |
| |
| subTimes() { |
| return { |
| "Startup": this.startupTime, |
| "Runtime": this.runTime, |
| }; |
| } |
| |
| static scoreDescription() { |
| return ["Startup", "Runtime", "Score"]; |
| } |
| |
| get startupID() { |
| return `wasm-startup-id${this.name}`; |
| } |
| get runID() { |
| return `wasm-run-id${this.name}`; |
| } |
| get scoreID() { |
| return `wasm-score-id${this.name}`; |
| } |
| |
| scoreIdentifiers() { |
| return [this.startupID, this.runID, this.scoreID]; |
| } |
| |
| updateUIAfterRun() { |
| super.updateUIAfterRun(); |
| |
| if (isInBrowser) { |
| document.getElementById(this.startupID).innerHTML = uiFriendlyNumber(this.startupTime); |
| document.getElementById(this.runID).innerHTML = uiFriendlyNumber(this.runTime); |
| document.getElementById(this.scoreID).innerHTML = uiFriendlyNumber(this.score); |
| return; |
| } |
| console.log(" Startup:", uiFriendlyNumber(this.startupTime)); |
| console.log(" Run time:", uiFriendlyNumber(this.runTime)); |
| if (RAMification) { |
| console.log(" Current Footprint:", uiFriendlyNumber(this.currentFootprint)); |
| console.log(" Peak Footprint:", uiFriendlyNumber(this.peakFootprint)); |
| } |
| console.log(" Score:", uiFriendlyNumber(this.score)); |
| } |
| }; |
| |
| const ARESGroup = Symbol.for("ARES"); |
| const CDJSGroup = Symbol.for("CDJS"); |
| const CodeLoadGroup = Symbol.for("CodeLoad"); |
| const LuaJSFightGroup = Symbol.for("LuaJSFight"); |
| const OctaneGroup = Symbol.for("Octane"); |
| const RexBenchGroup = Symbol.for("RexBench"); |
| const SeaMonsterGroup = Symbol.for("SeaMonster"); |
| const SimpleGroup = Symbol.for("Simple"); |
| const SunSpiderGroup = Symbol.for("SunSpider"); |
| const WasmGroup = Symbol.for("Wasm"); |
| const WorkerTestsGroup = Symbol.for("WorkerTests"); |
| const WSLGroup = Symbol.for("WSL"); |
| const WTBGroup = Symbol.for("WTB"); |
| |
| |
| let testPlans = [ |
| // ARES |
| { |
| name: "Air", |
| files: [ |
| "./ARES-6/Air/symbols.js" |
| , "./ARES-6/Air/tmp_base.js" |
| , "./ARES-6/Air/arg.js" |
| , "./ARES-6/Air/basic_block.js" |
| , "./ARES-6/Air/code.js" |
| , "./ARES-6/Air/frequented_block.js" |
| , "./ARES-6/Air/inst.js" |
| , "./ARES-6/Air/opcode.js" |
| , "./ARES-6/Air/reg.js" |
| , "./ARES-6/Air/stack_slot.js" |
| , "./ARES-6/Air/tmp.js" |
| , "./ARES-6/Air/util.js" |
| , "./ARES-6/Air/custom.js" |
| , "./ARES-6/Air/liveness.js" |
| , "./ARES-6/Air/insertion_set.js" |
| , "./ARES-6/Air/allocate_stack.js" |
| , "./ARES-6/Air/payload-gbemu-executeIteration.js" |
| , "./ARES-6/Air/payload-imaging-gaussian-blur-gaussianBlur.js" |
| , "./ARES-6/Air/payload-airjs-ACLj8C.js" |
| , "./ARES-6/Air/payload-typescript-scanIdentifier.js" |
| , "./ARES-6/Air/benchmark.js" |
| ], |
| testGroup: ARESGroup |
| }, |
| { |
| name: "Basic", |
| files: [ |
| "./ARES-6/Basic/ast.js" |
| , "./ARES-6/Basic/basic.js" |
| , "./ARES-6/Basic/caseless_map.js" |
| , "./ARES-6/Basic/lexer.js" |
| , "./ARES-6/Basic/number.js" |
| , "./ARES-6/Basic/parser.js" |
| , "./ARES-6/Basic/random.js" |
| , "./ARES-6/Basic/state.js" |
| , "./ARES-6/Basic/util.js" |
| , "./ARES-6/Basic/benchmark.js" |
| ], |
| testGroup: ARESGroup |
| }, |
| { |
| name: "ML", |
| files: [ |
| "./ARES-6/ml/index.js" |
| , "./ARES-6/ml/benchmark.js" |
| ], |
| iterations: 60, |
| testGroup: ARESGroup |
| }, |
| { |
| name: "Babylon", |
| files: [ |
| "./ARES-6/Babylon/index.js" |
| , "./ARES-6/Babylon/benchmark.js" |
| ], |
| preload: { |
| airBlob: "./ARES-6/Babylon/air-blob.js", |
| basicBlob: "./ARES-6/Babylon/basic-blob.js", |
| inspectorBlob: "./ARES-6/Babylon/inspector-blob.js", |
| babylonBlob: "./ARES-6/Babylon/babylon-blob.js" |
| }, |
| testGroup: ARESGroup |
| }, |
| // CDJS |
| { |
| name: "cdjs", |
| files: [ |
| "./cdjs/constants.js" |
| , "./cdjs/util.js" |
| , "./cdjs/red_black_tree.js" |
| , "./cdjs/call_sign.js" |
| , "./cdjs/vector_2d.js" |
| , "./cdjs/vector_3d.js" |
| , "./cdjs/motion.js" |
| , "./cdjs/reduce_collision_set.js" |
| , "./cdjs/simulator.js" |
| , "./cdjs/collision.js" |
| , "./cdjs/collision_detector.js" |
| , "./cdjs/benchmark.js" |
| ], |
| iterations: 60, |
| worstCaseCount: 3, |
| testGroup: CDJSGroup |
| }, |
| // CodeLoad |
| { |
| name: "first-inspector-code-load", |
| files: [ |
| "./code-load/code-first-load.js" |
| ], |
| preload: { |
| inspectorPayloadBlob: "./code-load/inspector-payload-minified.js" |
| }, |
| testGroup: CodeLoadGroup |
| }, |
| { |
| name: "multi-inspector-code-load", |
| files: [ |
| "./code-load/code-multi-load.js" |
| ], |
| preload: { |
| inspectorPayloadBlob: "./code-load/inspector-payload-minified.js" |
| }, |
| testGroup: CodeLoadGroup |
| }, |
| // Octane |
| { |
| name: "Box2D", |
| files: [ |
| "./Octane/box2d.js" |
| ], |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| { |
| name: "octane-code-load", |
| files: [ |
| "./Octane/code-first-load.js" |
| ], |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| { |
| name: "crypto", |
| files: [ |
| "./Octane/crypto.js" |
| ], |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| { |
| name: "delta-blue", |
| files: [ |
| "./Octane/deltablue.js" |
| ], |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| { |
| name: "earley-boyer", |
| files: [ |
| "./Octane/earley-boyer.js" |
| ], |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| { |
| name: "gbemu", |
| files: [ |
| "./Octane/gbemu-part1.js" |
| , "./Octane/gbemu-part2.js" |
| ], |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| { |
| name: "mandreel", |
| files: [ |
| "./Octane/mandreel.js" |
| ], |
| iterations: 80, |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| { |
| name: "navier-stokes", |
| files: [ |
| "./Octane/navier-stokes.js" |
| ], |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| { |
| name: "pdfjs", |
| files: [ |
| "./Octane/pdfjs.js" |
| ], |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| { |
| name: "raytrace", |
| files: [ |
| "./Octane/raytrace.js" |
| ], |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| { |
| name: "regexp", |
| files: [ |
| "./Octane/regexp.js" |
| ], |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| { |
| name: "richards", |
| files: [ |
| "./Octane/richards.js" |
| ], |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| { |
| name: "splay", |
| files: [ |
| "./Octane/splay.js" |
| ], |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| { |
| name: "typescript", |
| files: [ |
| "./Octane/typescript-compiler.js" |
| , "./Octane/typescript-input.js" |
| , "./Octane/typescript.js" |
| ], |
| iterations: 15, |
| worstCaseCount: 2, |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| { |
| name: "octane-zlib", |
| files: [ |
| "./Octane/zlib-data.js" |
| , "./Octane/zlib.js" |
| ], |
| iterations: 15, |
| worstCaseCount: 2, |
| deterministicRandom: true, |
| testGroup: OctaneGroup |
| }, |
| // RexBench |
| { |
| name: "FlightPlanner", |
| files: [ |
| "./RexBench/FlightPlanner/airways.js" |
| , "./RexBench/FlightPlanner/waypoints.js" |
| , "./RexBench/FlightPlanner/flight_planner.js" |
| , "./RexBench/FlightPlanner/expectations.js" |
| , "./RexBench/FlightPlanner/benchmark.js" |
| ], |
| testGroup: RexBenchGroup |
| }, |
| { |
| name: "OfflineAssembler", |
| files: [ |
| "./RexBench/OfflineAssembler/registers.js" |
| , "./RexBench/OfflineAssembler/instructions.js" |
| , "./RexBench/OfflineAssembler/ast.js" |
| , "./RexBench/OfflineAssembler/parser.js" |
| , "./RexBench/OfflineAssembler/file.js" |
| , "./RexBench/OfflineAssembler/LowLevelInterpreter.js" |
| , "./RexBench/OfflineAssembler/LowLevelInterpreter32_64.js" |
| , "./RexBench/OfflineAssembler/LowLevelInterpreter64.js" |
| , "./RexBench/OfflineAssembler/InitBytecodes.js" |
| , "./RexBench/OfflineAssembler/expected.js" |
| , "./RexBench/OfflineAssembler/benchmark.js" |
| ], |
| iterations: 80, |
| testGroup: RexBenchGroup |
| }, |
| { |
| name: "UniPoker", |
| files: [ |
| "./RexBench/UniPoker/poker.js" |
| , "./RexBench/UniPoker/expected.js" |
| , "./RexBench/UniPoker/benchmark.js" |
| ], |
| deterministicRandom: true, |
| testGroup: RexBenchGroup |
| }, |
| // Simple |
| { |
| name: "async-fs", |
| files: [ |
| "./simple/file-system.js" |
| ], |
| iterations: 40, |
| worstCaseCount: 3, |
| benchmarkClass: AsyncBenchmark, |
| testGroup: SimpleGroup |
| }, |
| { |
| name: "float-mm.c", |
| files: [ |
| "./simple/float-mm.c.js" |
| ], |
| iterations: 15, |
| worstCaseCount: 2, |
| testGroup: SimpleGroup |
| }, |
| { |
| name: "hash-map", |
| files: [ |
| "./simple/hash-map.js" |
| ], |
| testGroup: SimpleGroup |
| }, |
| // SeaMonster |
| { |
| name: "ai-astar", |
| files: [ |
| "./SeaMonster/ai-astar.js" |
| ], |
| testGroup: SeaMonsterGroup |
| }, |
| { |
| name: "gaussian-blur", |
| files: [ |
| "./SeaMonster/gaussian-blur.js" |
| ], |
| testGroup: SeaMonsterGroup |
| }, |
| { |
| name: "stanford-crypto-aes", |
| files: [ |
| "./SeaMonster/sjlc.js" |
| , "./SeaMonster/stanford-crypto-aes.js" |
| ], |
| testGroup: SeaMonsterGroup |
| }, |
| { |
| name: "stanford-crypto-pbkdf2", |
| files: [ |
| "./SeaMonster/sjlc.js" |
| , "./SeaMonster/stanford-crypto-pbkdf2.js" |
| ], |
| testGroup: SeaMonsterGroup |
| }, |
| { |
| name: "stanford-crypto-sha256", |
| files: [ |
| "./SeaMonster/sjlc.js" |
| , "./SeaMonster/stanford-crypto-sha256.js" |
| ], |
| testGroup: SeaMonsterGroup |
| }, |
| { |
| name: "json-stringify-inspector", |
| files: [ |
| "./SeaMonster/inspector-json-payload.js" |
| , "./SeaMonster/json-stringify-inspector.js" |
| ], |
| iterations: 20, |
| worstCaseCount: 2, |
| testGroup: SeaMonsterGroup |
| }, |
| { |
| name: "json-parse-inspector", |
| files: [ |
| "./SeaMonster/inspector-json-payload.js" |
| , "./SeaMonster/json-parse-inspector.js" |
| ], |
| iterations: 20, |
| worstCaseCount: 2, |
| testGroup: SeaMonsterGroup |
| }, |
| // Wasm |
| { |
| name: "HashSet-wasm", |
| wasmPath: "./wasm/HashSet.wasm", |
| files: [ |
| "./wasm/HashSet.js" |
| ], |
| preload: { |
| wasmBlobURL: "./wasm/HashSet.wasm" |
| }, |
| benchmarkClass: WasmBenchmark, |
| testGroup: WasmGroup |
| }, |
| { |
| name: "tsf-wasm", |
| wasmPath: "./wasm/tsf.wasm", |
| files: [ |
| "./wasm/tsf.js" |
| ], |
| preload: { |
| wasmBlobURL: "./wasm/tsf.wasm" |
| }, |
| benchmarkClass: WasmBenchmark, |
| testGroup: WasmGroup |
| }, |
| { |
| name: "quicksort-wasm", |
| wasmPath: "./wasm/quicksort.wasm", |
| files: [ |
| "./wasm/quicksort.js" |
| ], |
| preload: { |
| wasmBlobURL: "./wasm/quicksort.wasm" |
| }, |
| benchmarkClass: WasmBenchmark, |
| testGroup: WasmGroup |
| }, |
| { |
| name: "gcc-loops-wasm", |
| wasmPath: "./wasm/gcc-loops.wasm", |
| files: [ |
| "./wasm/gcc-loops.js" |
| ], |
| preload: { |
| wasmBlobURL: "./wasm/gcc-loops.wasm" |
| }, |
| benchmarkClass: WasmBenchmark, |
| testGroup: WasmGroup |
| }, |
| { |
| name: "richards-wasm", |
| wasmPath: "./wasm/richards.wasm", |
| files: [ |
| "./wasm/richards.js" |
| ], |
| preload: { |
| wasmBlobURL: "./wasm/richards.wasm" |
| }, |
| benchmarkClass: WasmBenchmark, |
| testGroup: WasmGroup |
| }, |
| // WorkerTests |
| { |
| name: "bomb-workers", |
| files: [ |
| "./worker/bomb.js" |
| ], |
| iterations: 80, |
| preload: { |
| rayTrace3D: "./worker/bomb-subtests/3d-raytrace.js" |
| , accessNbody: "./worker/bomb-subtests/access-nbody.js" |
| , morph3D: "./worker/bomb-subtests/3d-morph.js" |
| , cube3D: "./worker/bomb-subtests/3d-cube.js" |
| , accessFunnkuch: "./worker/bomb-subtests/access-fannkuch.js" |
| , accessBinaryTrees: "./worker/bomb-subtests/access-binary-trees.js" |
| , accessNsieve: "./worker/bomb-subtests/access-nsieve.js" |
| , bitopsBitwiseAnd: "./worker/bomb-subtests/bitops-bitwise-and.js" |
| , bitopsNsieveBits: "./worker/bomb-subtests/bitops-nsieve-bits.js" |
| , controlflowRecursive: "./worker/bomb-subtests/controlflow-recursive.js" |
| , bitops3BitBitsInByte: "./worker/bomb-subtests/bitops-3bit-bits-in-byte.js" |
| , botopsBitsInByte: "./worker/bomb-subtests/bitops-bits-in-byte.js" |
| , cryptoAES: "./worker/bomb-subtests/crypto-aes.js" |
| , cryptoMD5: "./worker/bomb-subtests/crypto-md5.js" |
| , cryptoSHA1: "./worker/bomb-subtests/crypto-sha1.js" |
| , dateFormatTofte: "./worker/bomb-subtests/date-format-tofte.js" |
| , dateFormatXparb: "./worker/bomb-subtests/date-format-xparb.js" |
| , mathCordic: "./worker/bomb-subtests/math-cordic.js" |
| , mathPartialSums: "./worker/bomb-subtests/math-partial-sums.js" |
| , mathSpectralNorm: "./worker/bomb-subtests/math-spectral-norm.js" |
| , stringBase64: "./worker/bomb-subtests/string-base64.js" |
| , stringFasta: "./worker/bomb-subtests/string-fasta.js" |
| , stringValidateInput: "./worker/bomb-subtests/string-validate-input.js" |
| , stringTagcloud: "./worker/bomb-subtests/string-tagcloud.js" |
| , stringUnpackCode: "./worker/bomb-subtests/string-unpack-code.js" |
| , regexpDNA: "./worker/bomb-subtests/regexp-dna.js" |
| }, |
| benchmarkClass: AsyncBenchmark, |
| testGroup: WorkerTestsGroup |
| }, |
| { |
| name: "segmentation", |
| files: [ |
| "./worker/segmentation.js" |
| ], |
| preload: { |
| asyncTaskBlob: "./worker/async-task.js" |
| }, |
| iterations: 36, |
| worstCaseCount: 3, |
| benchmarkClass: AsyncBenchmark, |
| testGroup: WorkerTestsGroup |
| }, |
| // WSL |
| { |
| name: "WSL", |
| files: ["./WSL/Node.js" ,"./WSL/Type.js" ,"./WSL/ReferenceType.js" ,"./WSL/Value.js" ,"./WSL/Expression.js" ,"./WSL/Rewriter.js" ,"./WSL/Visitor.js" ,"./WSL/CreateLiteral.js" ,"./WSL/CreateLiteralType.js" ,"./WSL/PropertyAccessExpression.js" ,"./WSL/AddressSpace.js" ,"./WSL/AnonymousVariable.js" ,"./WSL/ArrayRefType.js" ,"./WSL/ArrayType.js" ,"./WSL/Assignment.js" ,"./WSL/AutoWrapper.js" ,"./WSL/Block.js" ,"./WSL/BoolLiteral.js" ,"./WSL/Break.js" ,"./WSL/CallExpression.js" ,"./WSL/CallFunction.js" ,"./WSL/Check.js" ,"./WSL/CheckLiteralTypes.js" ,"./WSL/CheckLoops.js" ,"./WSL/CheckRecursiveTypes.js" ,"./WSL/CheckRecursion.js" ,"./WSL/CheckReturns.js" ,"./WSL/CheckUnreachableCode.js" ,"./WSL/CheckWrapped.js" ,"./WSL/Checker.js" ,"./WSL/CloneProgram.js" ,"./WSL/CommaExpression.js" ,"./WSL/ConstexprFolder.js" ,"./WSL/ConstexprTypeParameter.js" ,"./WSL/Continue.js" ,"./WSL/ConvertPtrToArrayRefExpression.js" ,"./WSL/DereferenceExpression.js" ,"./WSL/DoWhileLoop.js" ,"./WSL/DotExpression.js" ,"./WSL/DoubleLiteral.js" ,"./WSL/DoubleLiteralType.js" ,"./WSL/EArrayRef.js" ,"./WSL/EBuffer.js" ,"./WSL/EBufferBuilder.js" ,"./WSL/EPtr.js" ,"./WSL/EnumLiteral.js" ,"./WSL/EnumMember.js" ,"./WSL/EnumType.js" ,"./WSL/EvaluationCommon.js" ,"./WSL/Evaluator.js" ,"./WSL/ExpressionFinder.js" ,"./WSL/ExternalOrigin.js" ,"./WSL/Field.js" ,"./WSL/FindHighZombies.js" ,"./WSL/FlattenProtocolExtends.js" ,"./WSL/FlattenedStructOffsetGatherer.js" ,"./WSL/FloatLiteral.js" ,"./WSL/FloatLiteralType.js" ,"./WSL/FoldConstexprs.js" ,"./WSL/ForLoop.js" ,"./WSL/Func.js" ,"./WSL/FuncDef.js" ,"./WSL/FuncInstantiator.js" ,"./WSL/FuncParameter.js" ,"./WSL/FunctionLikeBlock.js" ,"./WSL/HighZombieFinder.js" ,"./WSL/IdentityExpression.js" ,"./WSL/IfStatement.js" ,"./WSL/IndexExpression.js" ,"./WSL/InferTypesForCall.js" ,"./WSL/Inline.js" ,"./WSL/Inliner.js" ,"./WSL/InstantiateImmediates.js" ,"./WSL/IntLiteral.js" ,"./WSL/IntLiteralType.js" ,"./WSL/Intrinsics.js" ,"./WSL/LateChecker.js" ,"./WSL/Lexer.js" ,"./WSL/LexerToken.js" ,"./WSL/LiteralTypeChecker.js" ,"./WSL/LogicalExpression.js" ,"./WSL/LogicalNot.js" ,"./WSL/LoopChecker.js" ,"./WSL/MakeArrayRefExpression.js" ,"./WSL/MakePtrExpression.js" ,"./WSL/NameContext.js" ,"./WSL/NameFinder.js" ,"./WSL/NameResolver.js" ,"./WSL/NativeFunc.js" ,"./WSL/NativeFuncInstance.js" ,"./WSL/NativeType.js" ,"./WSL/NativeTypeInstance.js" ,"./WSL/NormalUsePropertyResolver.js" ,"./WSL/NullLiteral.js" ,"./WSL/NullType.js" ,"./WSL/OriginKind.js" ,"./WSL/OverloadResolutionFailure.js" ,"./WSL/Parse.js" ,"./WSL/Prepare.js" ,"./WSL/Program.js" ,"./WSL/ProgramWithUnnecessaryThingsRemoved.js" ,"./WSL/PropertyResolver.js" ,"./WSL/Protocol.js" ,"./WSL/ProtocolDecl.js" ,"./WSL/ProtocolFuncDecl.js" ,"./WSL/ProtocolRef.js" ,"./WSL/PtrType.js" ,"./WSL/ReadModifyWriteExpression.js" ,"./WSL/RecursionChecker.js" ,"./WSL/RecursiveTypeChecker.js" ,"./WSL/ResolveNames.js" ,"./WSL/ResolveOverloadImpl.js" ,"./WSL/ResolveProperties.js" ,"./WSL/ResolveTypeDefs.js" ,"./WSL/Return.js" ,"./WSL/ReturnChecker.js" ,"./WSL/ReturnException.js" ,"./WSL/StandardLibrary.js" ,"./WSL/StatementCloner.js" ,"./WSL/StructLayoutBuilder.js" ,"./WSL/StructType.js" ,"./WSL/Substitution.js" ,"./WSL/SwitchCase.js" ,"./WSL/SwitchStatement.js" ,"./WSL/SynthesizeEnumFunctions.js" ,"./WSL/SynthesizeStructAccessors.js" ,"./WSL/TrapStatement.js" ,"./WSL/TypeDef.js" ,"./WSL/TypeDefResolver.js" ,"./WSL/TypeOrVariableRef.js" ,"./WSL/TypeParameterRewriter.js" ,"./WSL/TypeRef.js" ,"./WSL/TypeVariable.js" ,"./WSL/TypeVariableTracker.js" ,"./WSL/TypedValue.js" ,"./WSL/UintLiteral.js" ,"./WSL/UintLiteralType.js" ,"./WSL/UnificationContext.js" ,"./WSL/UnreachableCodeChecker.js" ,"./WSL/VariableDecl.js" ,"./WSL/VariableRef.js" ,"./WSL/VisitingSet.js" ,"./WSL/WSyntaxError.js" ,"./WSL/WTrapError.js" ,"./WSL/WTypeError.js" ,"./WSL/WhileLoop.js" ,"./WSL/WrapChecker.js", "./WSL/Test.js"], |
| benchmarkClass: WSLBenchmark, |
| testGroup: WSLGroup |
| } |
| ]; |
| |
| // LuaJSFight tests |
| let luaJSFightTests = [ |
| "hello_world" |
| , "list_search" |
| , "lists" |
| , "string_lists" |
| ]; |
| for (let test of luaJSFightTests) { |
| testPlans.push({ |
| name: `${test}-LJF`, |
| files: [ |
| `./LuaJSFight/${test}.js` |
| ], |
| testGroup: LuaJSFightGroup |
| }); |
| } |
| |
| // SunSpider tests |
| let sunSpiderTests = [ |
| "3d-cube" |
| , "3d-raytrace" |
| , "base64" |
| , "crypto-aes" |
| , "crypto-md5" |
| , "crypto-sha1" |
| , "date-format-tofte" |
| , "date-format-xparb" |
| , "n-body" |
| , "regex-dna" |
| , "string-unpack-code" |
| , "tagcloud" |
| ]; |
| for (let test of sunSpiderTests) { |
| testPlans.push({ |
| name: `${test}-SP`, |
| files: [ |
| `./SunSpider/${test}.js` |
| ], |
| testGroup: SunSpiderGroup |
| }); |
| } |
| |
| // WTB (Web Tooling Benchmark) tests |
| let WTBTests = [ |
| "acorn" |
| , "babylon" |
| , "chai" |
| , "coffeescript" |
| , "espree" |
| , "jshint" |
| , "lebab" |
| , "prepack" |
| , "uglify-js" |
| ]; |
| for (let name of WTBTests) { |
| testPlans.push({ |
| name: `${name}-wtb`, |
| files: [ |
| isInBrowser ? "./web-tooling-benchmark/browser.js" : "./web-tooling-benchmark/cli.js" |
| , `./web-tooling-benchmark/${name}.js` |
| ], |
| iterations: 5, |
| worstCaseCount: 1, |
| testGroup: WTBGroup |
| }); |
| } |
| |
| |
| let testsByName = new Map(); |
| let testsByGroup = new Map(); |
| |
| for (let plan of testPlans) { |
| let testName = plan.name; |
| |
| if (testsByName.has(plan.name)) |
| throw "Duplicate test plan with name \"" + testName + "\""; |
| else |
| testsByName.set(testName, plan); |
| |
| let group = plan.testGroup; |
| |
| if (testsByGroup.has(group)) |
| testsByGroup.get(group).push(testName); |
| else |
| testsByGroup.set(group, [testName]); |
| } |
| |
| this.JetStream = new Driver(); |
| |
| function addTestByName(testName) |
| { |
| let plan = testsByName.get(testName); |
| |
| if (plan) |
| JetStream.addPlan(plan, plan.benchmarkClass); |
| else |
| throw "Couldn't find test named \"" + testName + "\""; |
| } |
| |
| function addTestsByGroup(group) |
| { |
| let testList = testsByGroup.get(group); |
| |
| if (!testList) |
| throw "Couldn't find test group named: \"" + Symbol.keyFor(group) + "\""; |
| |
| for (let testName of testList) |
| addTestByName(testName); |
| } |
| |
| function processTestList(testList) |
| { |
| let tests = []; |
| |
| if (testList instanceof Array) |
| tests = testList; |
| else |
| tests = testList.split(/[\s,]/); |
| |
| for (let testName of tests) { |
| let groupTest = testsByGroup.get(Symbol.for(testName)); |
| |
| if (groupTest) { |
| for (let testName of groupTest) |
| addTestByName(testName); |
| } else |
| addTestByName(testName); |
| } |
| } |
| |
| let runOctane = true; |
| let runARES = true; |
| let runWSL = true; |
| let runRexBench = true; |
| let runWTB = true; |
| let runSunSpider = true; |
| let runSimple = true; |
| let runCDJS = true; |
| let runWorkerTests = !!isInBrowser; |
| let runSeaMonster = true; |
| let runCodeLoad = true; |
| let runWasm = true; |
| if (typeof WebAssembly === "undefined") |
| runWasm = false; |
| |
| if (false) { |
| runOctane = false; |
| runARES = false; |
| runWSL = false; |
| runRexBench = false; |
| runWTB = false; |
| runSunSpider = false; |
| runSimple = false; |
| runCDJS = false; |
| runWorkerTests = false; |
| runSeaMonster = false; |
| runCodeLoad = false; |
| runWasm = false; |
| } |
| |
| if (typeof testList !== "undefined") { |
| processTestList(testList); |
| } else { |
| if (runARES) |
| addTestsByGroup(ARESGroup); |
| |
| if (runCDJS) |
| addTestsByGroup(CDJSGroup); |
| |
| if (runCodeLoad) |
| addTestsByGroup(CodeLoadGroup); |
| |
| if (runOctane) |
| addTestsByGroup(OctaneGroup); |
| |
| if (runRexBench) |
| addTestsByGroup(RexBenchGroup); |
| |
| if (runSeaMonster) |
| addTestsByGroup(SeaMonsterGroup); |
| |
| if (runSimple) |
| addTestsByGroup(SimpleGroup); |
| |
| if (runSunSpider) |
| addTestsByGroup(SunSpiderGroup); |
| |
| if (runWasm) |
| addTestsByGroup(WasmGroup); |
| |
| if (runWorkerTests) |
| addTestsByGroup(WorkerTestsGroup); |
| |
| if (runWSL) |
| addTestsByGroup(WSLGroup); |
| |
| if (runWTB) |
| addTestsByGroup(WTBGroup); |
| } |