Add branch for JetStream v2.2 This is a copy of JetStream v2.2 as of https://commits.webkit.org/277529@main
diff --git a/JetStreamDriver.js b/JetStreamDriver.js index e1a6683..2dca23e 100644 --- a/JetStreamDriver.js +++ b/JetStreamDriver.js
@@ -42,6 +42,15 @@ if (typeof dumpJSONResults === "undefined") var dumpJSONResults = false; +let shouldReport = false; +let customTestList = []; +if (typeof(URLSearchParams) !== "undefined") { + const urlParameters = new URLSearchParams(window.location.search); + shouldReport = urlParameters.has('report') && urlParameters.get('report').toLowerCase() == 'true'; + if (urlParameters.has('test')) + customTestList = urlParameters.getAll("test"); +} + // Used for the promise representing the current benchmark run. this.currentResolve = null; this.currentReject = null; @@ -130,7 +139,7 @@ } function toScore(timeValue) { - return 5000 / timeValue; + return 5000 / Math.max(timeValue, 1); } function toTimeValue(score) { @@ -323,6 +332,10 @@ return Realm.eval(realm, s); }; globalObject.readFile = read; + } else if (isSpiderMonkey) { + globalObject = newGlobal(); + globalObject.loadString = globalObject.evaluate; + globalObject.readFile = globalObject.readRelativeToScript; } else globalObject = runString(""); @@ -404,7 +417,7 @@ await this.prefetchResourcesForBrowser(); await this.fetchResources(); this.prepareToRun(); - if (isInBrowser && window.location.search == '?report=true') { + if (isInBrowser && shouldReport) { setTimeout(() => this.start(), 4000); } } @@ -494,7 +507,7 @@ if (!isInBrowser) return; - if (window.location.search !== '?report=true') + if (!shouldReport) return; const content = this.resultsJSON(); @@ -1844,6 +1857,8 @@ if (typeof testList !== "undefined") { processTestList(testList); +} else if (customTestList.length) { + processTestList(customTestList); } else { if (runARES) addTestsByGroup(ARESGroup);
diff --git a/RAMification.py b/RAMification.py index 51edf1c..bac0e70 100644 --- a/RAMification.py +++ b/RAMification.py
@@ -29,6 +29,7 @@ import re import subprocess import sys +import time jitTests = ["3d-cube-SP", "3d-raytrace-SP", "acorn-wtb", "ai-astar", "Air", "async-fs", "Babylon", "babylon-wtb", "base64-SP", "Basic", "Box2D", "cdjs", "chai-wtb", "coffeescript-wtb", "crypto", "crypto-aes-SP", "crypto-md5-SP", "crypto-sha1-SP", "date-format-tofte-SP", "date-format-xparb-SP", "delta-blue", "earley-boyer", "espree-wtb", "first-inspector-code-load", "FlightPlanner", "float-mm.c", "gaussian-blur", "gbemu", "gcc-loops-wasm", "hash-map", "HashSet-wasm", "jshint-wtb", "json-parse-inspector", "json-stringify-inspector", "lebab-wtb", "mandreel", "ML", "multi-inspector-code-load", "n-body-SP", "navier-stokes", "octane-code-load", "octane-zlib", "OfflineAssembler", "pdfjs", "prepack-wtb", "quicksort-wasm", "raytrace", "regex-dna-SP", "regexp", "richards", "richards-wasm", "splay", "stanford-crypto-aes", "stanford-crypto-pbkdf2", "stanford-crypto-sha256", "string-unpack-code-SP", "tagcloud-SP", "tsf-wasm", "typescript", "uglify-js-wtb", "UniPoker", "WSL"] @@ -120,7 +121,10 @@ parser.add_argument("-l", "--lua", dest="runLuaTests", nargs="?", const=True, default=None, type=optStrToBool, metavar="true / false", help="Run Lua comparison tests [default]") parser.add_argument("-n", "--run-no-jit", dest="runNoJITTests", nargs="?", const=True, default=None, type=optStrToBool, metavar="true / false", help="Run no JIT tests [default]") parser.add_argument("-o", "--output", dest="jsonFilename", type=str, default=None, metavar="JSON-output-file", help="Path to JSON output") + parser.add_argument("--diagnostics-dir", dest="diagnosticDir", type=str, default="/tmp/RAMification-diagnostics/", metavar="diagnostic-dir", help="Path to a directory to dump diagnostic output.") parser.add_argument("-m", "--vmmap", dest="takeVmmap", action="store_true", default=False, help="Take a vmmap after each test") + parser.add_argument("--detailed-vmmap", dest="takeDetailedVmmap", action="store_true", default=False, help="Take a vmmap after each test including regions") + parser.add_argument("--memgraph", dest="takeMemgraph", action="store_true", default=False, help="Take a memgraph after each test") parser.add_argument("--smaps", dest="takeSmaps", action="store_true", default=False, help="Take a smaps rollup after each test") args = parser.parse_args() @@ -149,7 +153,15 @@ self.rootDir = args.testDir self.environmentVars = {} self.vmmapOutput = "" if args.takeVmmap else None + self.takeDetailedVmmap = args.takeDetailedVmmap self.smapsOutput = "" if args.takeSmaps else None + self.takeMemgraph = args.takeMemgraph + self.diagnosticDir = args.diagnosticDir + + if (self.takeDetailedVmmap or self.takeMemgraph) and not os.path.exists(self.diagnosticDir): + os.makedirs(self.diagnosticDir) + if not os.path.exists(self.diagnosticDir): + raise Exception("Couldn't create diagnostic dir {}".format(self.diagnosticDir)) def setup(self): pass @@ -190,9 +202,14 @@ BaseRunner.__init__(self, args) self.jscCommand = args.jscCommand + def runOneTest(self, test, extraOptions=None, useJetStream2Harness=True): self.resetForTest(test) + if self.takeMemgraph: + self.environmentVars["MallocStackLogging"] = "1" + self.environmentVars["__XPC_MallocStackLogging"] = "1" + args = [self.jscCommand] if extraOptions: args.extend(extraOptions) @@ -202,6 +219,11 @@ else: args.extend(["--footprint", "{test}".format(test=test)]) + if self.takeDetailedVmmap or self.takeMemgraph: + test_diagnostic_dir = os.path.dirname(os.path.join(self.diagnosticDir, test)) + if not os.path.exists(test_diagnostic_dir): + os.makedirs(test_diagnostic_dir) + self.resetForTest(test) proc = subprocess.Popen(args, cwd=self.rootDir, env=self.environmentVars, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=None, shell=False) @@ -217,8 +239,18 @@ self.vmmapOutput = subprocess.Popen(['vmmap', '--summary', '{}'.format(proc.pid)], shell=False, stderr=subprocess.PIPE, stdout=subprocess.PIPE).stdout.read() if sys.version_info[0] >= 3: self.vmmapOutput = str(self.vmmapOutput, "utf-8") + if self.takeDetailedVmmap: + vmmap_filename = os.path.join(self.diagnosticDir, "{}-{}.vmmap".format(test, int(time.time()))) + print("Collecting detailed vmmap at {}".format(vmmap_filename)) + self.vmmapDetailedOutput = subprocess.Popen(['vmmap', '{}'.format(proc.pid)], shell=False, stderr=subprocess.PIPE, stdout=subprocess.PIPE).stdout.read() + with open(vmmap_filename, 'wb') as f: + f.write(self.vmmapDetailedOutput) if self.smapsOutput is not None: self.smapsOutput = subprocess.Popen(['cat', '/proc/{}/smaps_rollup'.format(proc.pid)], shell=False, stderr=subprocess.PIPE, stdout=subprocess.PIPE).stdout.read() + if self.takeMemgraph: + memgraph_filename = os.path.join(self.diagnosticDir, "{}-{}.memgraph".format(test, int(time.time()))) + print("Collecting memgraph at {}".format(memgraph_filename)) + subprocess.call(['/usr/bin/leaks', str(proc.pid), '--fullContent', '--forkCorpse', "--outputGraph={}".format(memgraph_filename)], shell=False, stderr=subprocess.PIPE, stdout=subprocess.PIPE) proc.stdin.write(b"done\n") proc.stdin.flush() @@ -240,7 +272,7 @@ testRunner = args.runner(args) - if args.takeVmmap or args.takeSmaps: + if args.takeVmmap or args.takeDetailedVmmap or args.takeMemgraph or args.takeSmaps: testRunner.setEnv("JS_SHELL_WAIT_FOR_INPUT_TO_EXIT", "1") dyldFrameworkPath = frameworkPathFromExecutablePath(args.jscCommand)
diff --git a/cli.js b/cli.js index df7676a..8c76669 100644 --- a/cli.js +++ b/cli.js
@@ -30,7 +30,10 @@ const isD8 = typeof Realm !== "undefined"; if (isD8) - readFile = read; + globalThis.readFile = read; +const isSpiderMonkey = typeof newGlobal !== "undefined"; +if (isSpiderMonkey) + globalThis.readFile = readRelativeToScript; if (typeof testList === "undefined") testList = undefined;
diff --git a/in-depth.html b/in-depth.html index 9def091..be3d365 100644 --- a/in-depth.html +++ b/in-depth.html
@@ -1,5 +1,5 @@ <!-- - Copyright (C) 2019-2022 Apple Inc. All rights reserved. + Copyright (C) 2019-2024 Apple Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -27,7 +27,7 @@ <head> <meta charset="utf-8" /> - <title>JetStream 2.1 In-Depth Analysis</title> + <title>JetStream 2.2 In-Depth Analysis</title> <link rel="stylesheet" href="JetStream.css"> @@ -35,7 +35,7 @@ <body> <h1 class="logo"> <div id="jetstreams"> - <a href="index.html" class="logo-image">JetStream 2.1</a> + <a href="index.html" class="logo-image">JetStream 2.2</a> </div> </h1> <main> @@ -113,19 +113,20 @@ </p> <p> - JetStream 2.1 runs the same benchmarks as JetStream 2, but updates the benchmark driver to - improve score stability. This is achieved by pre-fetching network resources prior to running - the benchmarks. This can reduce perturbations on the measurement of JavaScript execution - time due to second order effects of pause times induced by network latency. + JetStream 2.2 runs the same benchmarks as JetStream 2.1, but includes fixes for several minor issues. + One such issue happened when running on fast hardware where the timer resolution, as returned by the VM, was occasionally 0. + This causes a problem when calculating a scores. There were two issues with the sub-test segmentation, where the code didn’t + create the initial Float32Array for the test, and the second a race condition in the task queue code. + The command line scripts cli.js and wasm-cli.js had issues with the D8 and SpiderMonkey shell programs. </p> <p> - Note that scores from JetStream 2.1 are not comparable to scores to other versions + Note that scores from JetStream 2.2 are not comparable to scores to other versions of any JetStream benchmark. </p> <h3> - JetStream 2.1 has 64 subtests: + JetStream 2.2 has 64 subtests: </h3> <dl>
diff --git a/index.html b/index.html index 54cfffa..5b40123 100644 --- a/index.html +++ b/index.html
@@ -1,5 +1,5 @@ <!-- - Copyright (C) 2019-2022 Apple Inc. All rights reserved. + Copyright (C) 2019-2024 Apple Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -27,7 +27,7 @@ <head> <meta charset="utf-8" /> - <title>JetStream 2.1</title> + <title>JetStream 2.2</title> <link rel="stylesheet" href="JetStream.css"> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes, viewport-fit=cover"> @@ -74,7 +74,7 @@ </h1> <main> - <p class="summary">JetStream 2.1 is a JavaScript and WebAssembly benchmark suite focused on the most advanced web applications. It rewards browsers that start up quickly, execute code quickly, and run smoothly. For more information, read the <a href="in-depth.html">in-depth analysis</a>. Bigger scores are better.</p> + <p class="summary">JetStream 2.2 is a JavaScript and WebAssembly benchmark suite focused on the most advanced web applications. It rewards browsers that start up quickly, execute code quickly, and run smoothly. For more information, read the <a href="in-depth.html">in-depth analysis</a>. Bigger scores are better.</p> <p class="summary" id="mode-description"></p> <div id="result-summary"></div>
diff --git a/wasm-cli.js b/wasm-cli.js index 8020303..f39b818 100644 --- a/wasm-cli.js +++ b/wasm-cli.js
@@ -24,6 +24,8 @@ */ const isInBrowser = false; +const isD8 = false; +const isSpiderMonkey = false; console = { log: () => { } }
diff --git a/worker/async-task.js b/worker/async-task.js index e80e703..9ca2675 100644 --- a/worker/async-task.js +++ b/worker/async-task.js
@@ -390,7 +390,7 @@ function findOptimalSegmentationInternal(cost, previousNode, values, costMatrix, segmentCount) { - cost[0] = [0]; // The cost of segmenting single value is always 0. + cost[0] = new Float32Array([0]); // The cost of segmenting single value is always 0. previousNode[0] = [-1]; for (var segmentStart = 0; segmentStart < values.length; segmentStart++) { var costOfOptimalSegmentationThatEndAtCurrentStart = cost[segmentStart]; @@ -522,7 +522,8 @@ var worker = this._makeWorkerEventuallyAvailable(); if (worker) callback(worker); - this._queue.push(callback); + else + this._queue.push(callback); } static _makeWorkerEventuallyAvailable() @@ -537,6 +538,8 @@ if (this._latestStartTime > Date.now() - 50) { setTimeout(function () { + if (!AsyncTaskWorker._queue.length) + return; var worker = AsyncTaskWorker._findAvailableWorker(); if (worker) AsyncTaskWorker._queue.pop()(worker);
diff --git a/worker/segmentation.js b/worker/segmentation.js index 0b2955d..51fbdce 100644 --- a/worker/segmentation.js +++ b/worker/segmentation.js
@@ -392,7 +392,7 @@ function findOptimalSegmentationInternal(cost, previousNode, values, costMatrix, segmentCount) { - cost[0] = [0]; // The cost of segmenting single value is always 0. + cost[0] = new Float32Array([0]); // The cost of segmenting single value is always 0. previousNode[0] = [-1]; for (var segmentStart = 0; segmentStart < values.length; segmentStart++) { var costOfOptimalSegmentationThatEndAtCurrentStart = cost[segmentStart]; @@ -522,7 +522,8 @@ var worker = this._makeWorkerEventuallyAvailable(); if (worker) callback(worker); - this._queue.push(callback); + else + this._queue.push(callback); } static _makeWorkerEventuallyAvailable() @@ -537,6 +538,8 @@ if (this._latestStartTime > Date.now() - 50) { setTimeout(function () { + if (!AsyncTaskWorker._queue.length) + return; var worker = AsyncTaskWorker._findAvailableWorker(); if (worker) AsyncTaskWorker._queue.pop()(worker);