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);