Skip to content

Commit cb53112

Browse files
committed
WIP
Move existing benchmarks to WasmLegacyBenchamrk and add a new WasmBenchmark that supports running iterations. It's currently an async benchmark subclass since the compile is async. As a proof of concept this patch converts tsf-wasm to use the new scoring. As part of this process tsf needed to be recompiled so I added a step to the build.sh script which wraps emcc's output .js file with some glue code. This should make it easier to rebuild in the future too since we're not directly editing the module loading file. I went with this route rather than hooking into emcc's API since I wanted to use the js glue as close to "out of the box" as possible. Lastly, get emcc to ouput the .symbols object so we know which wasm function is which index. We could emit a name section into he binary but my assumption is that most production code does not ship with that so it could change the benchmark in an unrealistic way. TODO: * Profile perf differences * Generalize the wrapping process * Remove postIterationHook code for a different PR.
1 parent 274bf50 commit cb53112

File tree

6 files changed

+4091
-43
lines changed

6 files changed

+4091
-43
lines changed

JetStreamDriver.js

Lines changed: 124 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"use strict";
22

33
/*
4-
* Copyright (C) 2018-2022 Apple Inc. All rights reserved.
4+
* Copyright (C) 2018-2024 Apple Inc. All rights reserved.
55
*
66
* Redistribution and use in source and binary forms, with or without
77
* modification, are permitted provided that the following conditions
@@ -330,7 +330,7 @@ class Driver {
330330
} else
331331
globalObject = runString("");
332332

333-
globalObject.console = { log: globalObject.print, warn: (e) => { print("Warn: " + e); /*$vm.abort();*/ } }
333+
globalObject.console = { log: globalObject.print, warn: (e) => { print("Warn: " + e); /*$vm.abort();*/ }, error: (e) => { print("Error: " + e); /*$vm.abort();*/ } }
334334
globalObject.self = globalObject;
335335
globalObject.top = {
336336
currentResolve,
@@ -543,10 +543,11 @@ class Benchmark {
543543
if (__benchmark.prepareForNextIteration)
544544
__benchmark.prepareForNextIteration();
545545
546-
${this.preiterationCode}
546+
${this.preIterationCode}
547547
let start = performance.now();
548548
__benchmark.runIteration();
549549
let end = performance.now();
550+
${this.postIterationCode}
550551
551552
results.push(Math.max(1, end - start));
552553
}
@@ -565,11 +566,24 @@ class Benchmark {
565566

566567
get prerunCode() { return null; }
567568

568-
get preiterationCode() {
569+
get preIterationCode() {
570+
let code = "";
569571
if (this.plan.deterministicRandom)
570-
return `Math.random.__resetSeed();`;
572+
code += `Math.random.__resetSeed();`;
571573

572-
return "";
574+
if (globalThis.customPreIterationCode)
575+
code += customPreIterationCode;
576+
577+
return code;
578+
}
579+
580+
get postIterationCode() {
581+
let code = "";
582+
583+
if (globalThis.customPostIterationCode)
584+
code += customPostIterationCode;
585+
586+
return code;
573587
}
574588

575589
async run() {
@@ -972,10 +986,11 @@ class AsyncBenchmark extends DefaultBenchmark {
972986
let __benchmark = new Benchmark();
973987
let results = [];
974988
for (let i = 0; i < ${this.iterations}; i++) {
975-
${this.preiterationCode}
989+
${this.preIterationCode}
976990
let start = performance.now();
977991
await __benchmark.runIteration();
978992
let end = performance.now();
993+
${this.postIterationCode}
979994
results.push(Math.max(1, end - start));
980995
}
981996
if (__benchmark.validate)
@@ -986,6 +1001,96 @@ class AsyncBenchmark extends DefaultBenchmark {
9861001
}
9871002
};
9881003

1004+
class WasmBenchmark extends AsyncBenchmark {
1005+
get prerunCode() {
1006+
let str = `
1007+
let verbose = true;
1008+
1009+
let globalObject = this;
1010+
1011+
abort = quit = function() {
1012+
if (verbose)
1013+
console.log('Intercepted quit/abort');
1014+
};
1015+
1016+
oldPrint = globalObject.print;
1017+
globalObject.print = globalObject.printErr = (...args) => {
1018+
if (verbose)
1019+
console.log('Intercepted print: ', ...args);
1020+
};
1021+
1022+
let instanceReady;
1023+
let instancePromise = new Promise((resolve) => {
1024+
instanceReady = resolve;
1025+
});
1026+
1027+
let Module = {
1028+
preRun: [],
1029+
postRun: [],
1030+
print: function() { },
1031+
printErr: function() { },
1032+
setStatus: function(text) {
1033+
},
1034+
totalDependencies: 0,
1035+
monitorRunDependencies: function(left) {
1036+
this.totalDependencies = Math.max(this.totalDependencies, left);
1037+
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
1038+
},
1039+
};
1040+
globalObject.Module = Module;
1041+
`;
1042+
return str;
1043+
}
1044+
1045+
get runnerCode() {
1046+
let str = `function loadBlob(key, path, andThen) {`;
1047+
1048+
if (isInBrowser) {
1049+
str += `
1050+
var xhr = new XMLHttpRequest();
1051+
xhr.open('GET', path, true);
1052+
xhr.responseType = 'arraybuffer';
1053+
xhr.onload = function() {
1054+
Module[key] = new Int8Array(xhr.response);
1055+
andThen();
1056+
};
1057+
xhr.send(null);
1058+
`;
1059+
} else {
1060+
str += `
1061+
Module[key] = new Int8Array(read(path, "binary"));
1062+
1063+
Module.setStatus = null;
1064+
Module.monitorRunDependencies = null;
1065+
1066+
Promise.resolve(42).then(() => {
1067+
try {
1068+
andThen();
1069+
} catch(e) {
1070+
console.log("error running wasm:", e);
1071+
console.log(e.stack);
1072+
throw e;
1073+
}
1074+
})
1075+
`;
1076+
}
1077+
1078+
str += "}";
1079+
1080+
let keys = Object.keys(this.plan.preload);
1081+
for (let i = 0; i < keys.length; ++i) {
1082+
str += `loadBlob("${keys[i]}", "${this.plan.preload[keys[i]]}", () => {\n`;
1083+
}
1084+
str += super.runnerCode;
1085+
for (let i = 0; i < keys.length; ++i) {
1086+
str += `})`;
1087+
}
1088+
str += `;`;
1089+
1090+
return str;
1091+
}
1092+
};
1093+
9891094
class WSLBenchmark extends Benchmark {
9901095
constructor(...args) {
9911096
super(...args);
@@ -1062,7 +1167,7 @@ class WSLBenchmark extends Benchmark {
10621167
}
10631168
};
10641169

1065-
class WasmBenchmark extends Benchmark {
1170+
class WasmLegacyBenchmark extends Benchmark {
10661171
constructor(...args) {
10671172
super(...args);
10681173

@@ -1776,16 +1881,16 @@ const testPlans = [
17761881
preload: {
17771882
wasmBinary: "./wasm/HashSet.wasm"
17781883
},
1779-
benchmarkClass: WasmBenchmark,
1884+
benchmarkClass: WasmLegacyBenchmark,
17801885
testGroup: WasmGroup
17811886
},
17821887
{
17831888
name: "tsf-wasm",
17841889
files: [
1785-
"./wasm/tsf.js"
1890+
"./wasm/TSF/tsf.js"
17861891
],
17871892
preload: {
1788-
wasmBinary: "./wasm/tsf.wasm"
1893+
wasmBinary: "./wasm/TSF/tsf.wasm"
17891894
},
17901895
benchmarkClass: WasmBenchmark,
17911896
testGroup: WasmGroup
@@ -1798,7 +1903,7 @@ const testPlans = [
17981903
preload: {
17991904
wasmBinary: "./wasm/quicksort.wasm"
18001905
},
1801-
benchmarkClass: WasmBenchmark,
1906+
benchmarkClass: WasmLegacyBenchmark,
18021907
testGroup: WasmGroup
18031908
},
18041909
{
@@ -1809,7 +1914,7 @@ const testPlans = [
18091914
preload: {
18101915
wasmBinary: "./wasm/gcc-loops.wasm"
18111916
},
1812-
benchmarkClass: WasmBenchmark,
1917+
benchmarkClass: WasmLegacyBenchmark,
18131918
testGroup: WasmGroup
18141919
},
18151920
{
@@ -1820,7 +1925,7 @@ const testPlans = [
18201925
preload: {
18211926
wasmBinary: "./wasm/richards.wasm"
18221927
},
1823-
benchmarkClass: WasmBenchmark,
1928+
benchmarkClass: WasmLegacyBenchmark,
18241929
testGroup: WasmGroup
18251930
},
18261931
{
@@ -1852,7 +1957,7 @@ const testPlans = [
18521957
preload: {
18531958
tfjsBackendWasmBlob: "./wasm/tfjs-backend-wasm.wasm",
18541959
},
1855-
benchmarkClass: WasmBenchmark,
1960+
benchmarkClass: WasmLegacyBenchmark,
18561961
async: true,
18571962
deterministicRandom: true,
18581963
testGroup: WasmGroup
@@ -1873,7 +1978,7 @@ const testPlans = [
18731978
preload: {
18741979
tfjsBackendWasmSimdBlob: "./wasm/tfjs-backend-wasm-simd.wasm",
18751980
},
1876-
benchmarkClass: WasmBenchmark,
1981+
benchmarkClass: WasmLegacyBenchmark,
18771982
async: true,
18781983
deterministicRandom: true,
18791984
testGroup: WasmGroup
@@ -1888,7 +1993,7 @@ const testPlans = [
18881993
preload: {
18891994
argon2WasmBlob: "./wasm/argon2.wasm",
18901995
},
1891-
benchmarkClass: WasmBenchmark,
1996+
benchmarkClass: WasmLegacyBenchmark,
18921997
testGroup: WasmGroup
18931998
},
18941999
{
@@ -1901,7 +2006,7 @@ const testPlans = [
19012006
preload: {
19022007
argon2WasmSimdBlob: "./wasm/argon2-simd.wasm",
19032008
},
1904-
benchmarkClass: WasmBenchmark,
2009+
benchmarkClass: WasmLegacyBenchmark,
19052010
testGroup: WasmGroup
19062011
},
19072012
// WorkerTests
@@ -1975,7 +2080,7 @@ const testPlans = [
19752080
romBinary: "./8bitbench/assets/program.bin"
19762081
},
19772082
async: true,
1978-
benchmarkClass: WasmBenchmark,
2083+
benchmarkClass: WasmLegacyBenchmark,
19792084
testGroup: WasmGroup
19802085
}
19812086
];

wasm/TSF/build.sh

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#!/bin/sh
2+
3+
set -euo pipefail
4+
25
emcc \
3-
-o tsf.html -o tsf.js -O2 -s WASM=1 -s TOTAL_MEMORY=52428800 -g1 \
6+
-o tsf.js -O2 -s WASM=1 -s TOTAL_MEMORY=52428800 -g1 --emit-symbol-map -s EXPORTED_FUNCTIONS=_main,_runIteration \
47
-I. -DTSF_BUILD_SYSTEM=1 \
58
tsf_asprintf.c\
69
tsf_buffer.c\
@@ -53,3 +56,23 @@ emcc \
5356
tsf_ir_different.c\
5457
tsf_ir_speed.c
5558

59+
TEMPFILE=`mktemp /tmp/tsf.XXXXXX`
60+
61+
(echo 'function setup(Module) {'; cat tsf.js; echo '}
62+
63+
class Benchmark {
64+
async runIteration() {
65+
if (!Module["_main"]) {
66+
let runtimeInitializedCallback;
67+
let runtimeInitialized = new Promise((success) => runtimeInitializedCallback = success);
68+
Module.onRuntimeInitialized = function() {
69+
runtimeInitializedCallback();
70+
}
71+
setup(Module);
72+
await runtimeInitialized;
73+
}
74+
75+
Module["_runIteration"]();
76+
}
77+
}') > $TEMPFILE
78+
mv $TEMPFILE tsf.js

0 commit comments

Comments
 (0)