Skip to content

Commit 30ea5a3

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 64c9041 commit 30ea5a3

File tree

6 files changed

+4092
-44
lines changed

6 files changed

+4092
-44
lines changed

JetStreamDriver.js

+125-20
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,11 +986,12 @@ 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();
979-
results.push(Math.max(1, end - start));
993+
${this.postIterationCode}
994+
results.push(end - start);
980995
}
981996
if (__benchmark.validate)
982997
__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

@@ -1775,16 +1880,16 @@ let testPlans = [
17751880
preload: {
17761881
wasmBinary: "./wasm/HashSet.wasm"
17771882
},
1778-
benchmarkClass: WasmBenchmark,
1883+
benchmarkClass: WasmLegacyBenchmark,
17791884
testGroup: WasmGroup
17801885
},
17811886
{
17821887
name: "tsf-wasm",
17831888
files: [
1784-
"./wasm/tsf.js"
1889+
"./wasm/TSF/tsf.js"
17851890
],
17861891
preload: {
1787-
wasmBinary: "./wasm/tsf.wasm"
1892+
wasmBinary: "./wasm/TSF/tsf.wasm"
17881893
},
17891894
benchmarkClass: WasmBenchmark,
17901895
testGroup: WasmGroup
@@ -1797,7 +1902,7 @@ let testPlans = [
17971902
preload: {
17981903
wasmBinary: "./wasm/quicksort.wasm"
17991904
},
1800-
benchmarkClass: WasmBenchmark,
1905+
benchmarkClass: WasmLegacyBenchmark,
18011906
testGroup: WasmGroup
18021907
},
18031908
{
@@ -1808,7 +1913,7 @@ let testPlans = [
18081913
preload: {
18091914
wasmBinary: "./wasm/gcc-loops.wasm"
18101915
},
1811-
benchmarkClass: WasmBenchmark,
1916+
benchmarkClass: WasmLegacyBenchmark,
18121917
testGroup: WasmGroup
18131918
},
18141919
{
@@ -1819,7 +1924,7 @@ let testPlans = [
18191924
preload: {
18201925
wasmBinary: "./wasm/richards.wasm"
18211926
},
1822-
benchmarkClass: WasmBenchmark,
1927+
benchmarkClass: WasmLegacyBenchmark,
18231928
testGroup: WasmGroup
18241929
},
18251930
{
@@ -1838,7 +1943,7 @@ let testPlans = [
18381943
preload: {
18391944
tfjsBackendWasmBlob: "./wasm/tfjs-backend-wasm.wasm",
18401945
},
1841-
benchmarkClass: WasmBenchmark,
1946+
benchmarkClass: WasmLegacyBenchmark,
18421947
async: true,
18431948
deterministicRandom: true,
18441949
testGroup: WasmGroup
@@ -1859,7 +1964,7 @@ let testPlans = [
18591964
preload: {
18601965
tfjsBackendWasmSimdBlob: "./wasm/tfjs-backend-wasm-simd.wasm",
18611966
},
1862-
benchmarkClass: WasmBenchmark,
1967+
benchmarkClass: WasmLegacyBenchmark,
18631968
async: true,
18641969
deterministicRandom: true,
18651970
testGroup: WasmGroup
@@ -1874,7 +1979,7 @@ let testPlans = [
18741979
preload: {
18751980
argon2WasmBlob: "./wasm/argon2.wasm",
18761981
},
1877-
benchmarkClass: WasmBenchmark,
1982+
benchmarkClass: WasmLegacyBenchmark,
18781983
testGroup: WasmGroup
18791984
},
18801985
{
@@ -1887,7 +1992,7 @@ let testPlans = [
18871992
preload: {
18881993
argon2WasmSimdBlob: "./wasm/argon2-simd.wasm",
18891994
},
1890-
benchmarkClass: WasmBenchmark,
1995+
benchmarkClass: WasmLegacyBenchmark,
18911996
testGroup: WasmGroup
18921997
},
18931998
// WorkerTests
@@ -1961,7 +2066,7 @@ let testPlans = [
19612066
romBinary: "./8bitbench/assets/program.bin"
19622067
},
19632068
async: true,
1964-
benchmarkClass: WasmBenchmark,
2069+
benchmarkClass: WasmLegacyBenchmark,
19652070
testGroup: WasmGroup
19662071
}
19672072
];

wasm/TSF/build.sh

+24-1
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)