Skip to content

Commit 591842d

Browse files
committed
Merge branch 'main' into 2025-10-14_simpler_startup
2 parents db30420 + bb77d06 commit 591842d

63 files changed

Lines changed: 120063 additions & 94 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

JetStreamDriver.js

Lines changed: 108 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ if (!isInBrowser && JetStreamParams.prefetchResources) {
4040

4141
// Load a polyfill for TextEncoder/TextDecoder in shells. Used when
4242
// decompressing a prefetched resource and converting it to text.
43-
load("./polyfills/fast-text-encoding/1.0.3/text.js");
43+
load("./utils/polyfills/fast-text-encoding/1.0.3/text.js");
4444
}
4545

4646
// Used for the promise representing the current benchmark run.
@@ -913,8 +913,11 @@ class Benchmark {
913913
}
914914
if (this.plan.preload) {
915915
let preloadCode = "";
916-
for (let [ variableName, blobURLOrPath ] of this.preloads)
916+
for (let [ variableName, blobURLOrPath ] of this.preloads) {
917+
console.assert(variableName?.length > 0, "Invalid preload name.");
918+
console.assert(blobURLOrPath?.length > 0, "Invalid preload data.");
917919
preloadCode += `JetStream.preload[${JSON.stringify(variableName)}] = "${blobURLOrPath}";\n`;
920+
}
918921
scripts.add(preloadCode);
919922
}
920923

@@ -1068,8 +1071,8 @@ class Benchmark {
10681071

10691072
if (this.plan.preload) {
10701073
this.preloads = [];
1071-
for (let prop of Object.getOwnPropertyNames(this.plan.preload)) {
1072-
promises.push(this.loadBlob("preload", prop, this.plan.preload[prop]).then((blobData) => {
1074+
for (const [name, resource] of Object.entries(this.plan.preload)) {
1075+
promises.push(this.loadBlob("preload", name, resource).then((blobData) => {
10731076
if (!globalThis.allIsGood)
10741077
return;
10751078
this.preloads.push([ blobData.prop, blobData.blobURL ]);
@@ -1078,7 +1081,7 @@ class Benchmark {
10781081
// We'll try again later in retryPrefetchResourceForBrowser(). Don't throw an error.
10791082
if (!this.failedPreloads)
10801083
this.failedPreloads = { };
1081-
this.failedPreloads[prop] = true;
1084+
this.failedPreloads[name] = true;
10821085
JetStream.counter.failedPreloadResources++;
10831086
}));
10841087
}
@@ -1135,9 +1138,8 @@ class Benchmark {
11351138
}
11361139

11371140
if (this.plan.preload) {
1138-
for (const prop of Object.getOwnPropertyNames(this.plan.preload)) {
1139-
const resource = this.plan.preload[prop];
1140-
const allDone = await this.retryPrefetchResource("preload", prop, resource);
1141+
for (const [name, resource] of Object.entries(this.plan.preload)) {
1142+
const allDone = await this.retryPrefetchResource("preload", name, resource);
11411143
if (allDone)
11421144
return true; // All resources loaded, nothing more to do.
11431145
}
@@ -1157,21 +1159,21 @@ class Benchmark {
11571159
if (!this.plan.preload) {
11581160
return;
11591161
}
1160-
for (let [name, file] of Object.entries(this.plan.preload)) {
1161-
const compressed = isCompressed(file);
1162+
for (let [name, resource] of Object.entries(this.plan.preload)) {
1163+
const compressed = isCompressed(resource);
11621164
if (compressed && !JetStreamParams.prefetchResources) {
1163-
file = uncompressedName(file);
1165+
resource = uncompressedName(resource);
11641166
}
11651167

11661168
if (JetStreamParams.prefetchResources) {
1167-
let bytes = new Int8Array(read(file, "binary"));
1169+
let bytes = new Int8Array(read(resource, "binary"));
11681170
if (compressed) {
11691171
bytes = zlib.decompress(bytes);
11701172
}
1171-
this.shellPrefetchedResources[file] = bytes;
1173+
this.shellPrefetchedResources[resource] = bytes;
11721174
}
11731175

1174-
this.preloads.push([name, file]);
1176+
this.preloads.push([name, resource]);
11751177
}
11761178
}
11771179

@@ -1761,10 +1763,10 @@ class WasmLegacyBenchmark extends Benchmark {
17611763
}
17621764

17631765
str += "};\n";
1764-
1765-
const keys = Object.keys(this.plan.preload);
1766-
for (let i = 0; i < keys.length; ++i) {
1767-
str += `JetStream.loadBlob("${keys[i]}", "${this.plan.preload[keys[i]]}", () => {\n`;
1766+
let preloadCount = 0;
1767+
for (const [name, resource] of Object.entries(this.plan.preload)) {
1768+
preloadCount++;
1769+
str += `JetStream.loadBlob(${JSON.stringify(name)}, "${resource}", () => {\n`;
17681770
}
17691771
if (this.plan.async) {
17701772
str += `doRun().catch((e) => {
@@ -1775,7 +1777,7 @@ class WasmLegacyBenchmark extends Benchmark {
17751777
} else {
17761778
str += `doRun();`
17771779
}
1778-
for (let i = 0; i < keys.length; ++i) {
1780+
for (let i = 0; i < preloadCount; ++i) {
17791781
str += `})`;
17801782
}
17811783
str += `;`;
@@ -2262,10 +2264,25 @@ let BENCHMARKS = [
22622264
],
22632265
tags: ["default", "js", "Proxy"],
22642266
}),
2267+
new AsyncBenchmark({
2268+
name: "mobx-startup",
2269+
files: [
2270+
"./utils/StartupBenchmark.js",
2271+
"./mobx/benchmark.js",
2272+
],
2273+
preload: {
2274+
// Debug Sources for nicer profiling.
2275+
// BUNDLE: "./mobx/dist/bundle.es6.js",
2276+
BUNDLE: "./mobx/dist/bundle.es6.min.js",
2277+
},
2278+
tags: ["default", "js", "mobx", "startup", "es6"],
2279+
iterations: 30,
2280+
worstCaseCount: 3,
2281+
}),
22652282
new AsyncBenchmark({
22662283
name: "jsdom-d3-startup",
22672284
files: [
2268-
"./startup-helper/StartupBenchmark.js",
2285+
"./utils/StartupBenchmark.js",
22692286
"./jsdom-d3-startup/benchmark.js",
22702287
],
22712288
preload: {
@@ -2282,12 +2299,13 @@ let BENCHMARKS = [
22822299
new AsyncBenchmark({
22832300
name: "web-ssr",
22842301
files: [
2302+
"./utils/StartupBenchmark.js",
22852303
"./web-ssr/benchmark.js",
22862304
],
22872305
preload: {
22882306
// Debug Sources for nicer profiling.
2289-
// BUNDLE_BLOB: "./web-ssr/dist/bundle.js",
2290-
BUNDLE_BLOB: "./web-ssr/dist/bundle.min.js",
2307+
// BUNDLE: "./web-ssr/dist/bundle.js",
2308+
BUNDLE: "./web-ssr/dist/bundle.min.js",
22912309
},
22922310
tags: ["default", "js", "web", "ssr"],
22932311
iterations: 30,
@@ -2439,7 +2457,7 @@ let BENCHMARKS = [
24392457
new WasmEMCCBenchmark({
24402458
name: "sqlite3-wasm",
24412459
files: [
2442-
"./polyfills/fast-text-encoding/1.0.3/text.js",
2460+
"./utils/polyfills/fast-text-encoding/1.0.3/text.js",
24432461
"./sqlite3/benchmark.js",
24442462
"./sqlite3/build/jswasm/speedtest1.js",
24452463
],
@@ -2504,7 +2522,7 @@ let BENCHMARKS = [
25042522
new AsyncBenchmark({
25052523
name: "transformersjs-bert-wasm",
25062524
files: [
2507-
"./polyfills/fast-text-encoding/1.0.3/text.js",
2525+
"./utils/polyfills/fast-text-encoding/1.0.3/text.js",
25082526
"./transformersjs/benchmark.js",
25092527
"./transformersjs/task-bert.js",
25102528
],
@@ -2526,7 +2544,7 @@ let BENCHMARKS = [
25262544
new AsyncBenchmark({
25272545
name: "transformersjs-whisper-wasm",
25282546
files: [
2529-
"./polyfills/fast-text-encoding/1.0.3/text.js",
2547+
"./utils/polyfills/fast-text-encoding/1.0.3/text.js",
25302548
"./transformersjs/benchmark.js",
25312549
"./transformersjs/task-whisper.js",
25322550
],
@@ -2549,7 +2567,7 @@ let BENCHMARKS = [
25492567
iterations: 5,
25502568
worstCaseCount: 1,
25512569
allowUtf16: true,
2552-
tags: ["default", "Wasm", "transformersjs"],
2570+
tags: ["Wasm", "transformersjs"],
25532571
}),
25542572
new WasmLegacyBenchmark({
25552573
name: "tfjs-wasm",
@@ -2610,6 +2628,68 @@ let BENCHMARKS = [
26102628
allowUtf16: true,
26112629
tags: ["default", "Wasm"],
26122630
}),
2631+
new AsyncBenchmark({
2632+
name: "babylonjs-startup-es5",
2633+
files: [
2634+
"./utils/StartupBenchmark.js",
2635+
"./babylonjs/benchmark/startup.js",
2636+
],
2637+
preload: {
2638+
BUNDLE: "./babylonjs/dist/bundle.es5.min.js",
2639+
},
2640+
arguments: {
2641+
expectedCacheCommentCount: 23988,
2642+
},
2643+
tags: ["startup", "js", "class", "es5", "babylonjs"],
2644+
iterations: 10,
2645+
}),
2646+
new AsyncBenchmark({
2647+
name: "babylonjs-startup-es6",
2648+
files: [
2649+
"./utils/StartupBenchmark.js",
2650+
"./babylonjs/benchmark/startup.js",
2651+
],
2652+
preload: {
2653+
BUNDLE: "./babylonjs/dist/bundle.es6.min.js",
2654+
},
2655+
arguments: {
2656+
expectedCacheCommentCount: 21222,
2657+
},
2658+
tags: ["Default", "js", "startup", "class", "es6", "babylonjs"],
2659+
iterations: 10,
2660+
}),
2661+
new AsyncBenchmark({
2662+
name: "babylonjs-scene-es5",
2663+
files: [
2664+
// Use non-minified sources for easier profiling:
2665+
// "./babylonjs/dist/bundle.es5.js",
2666+
"./babylonjs/dist/bundle.es5.min.js",
2667+
"./babylonjs/benchmark/scene.js",
2668+
],
2669+
preload: {
2670+
PARTICLES_BLOB: "./babylonjs/data/particles.json",
2671+
PIRATE_FORT_BLOB: "./babylonjs/data/pirateFort.glb",
2672+
CANNON_BLOB: "./babylonjs/data/cannon.glb",
2673+
},
2674+
tags: ["scene", "js", "es5", "babylonjs"],
2675+
iterations: 5,
2676+
}),
2677+
new AsyncBenchmark({
2678+
name: "babylonjs-scene-es6",
2679+
files: [
2680+
// Use non-minified sources for easier profiling:
2681+
// "./babylonjs/dist/bundle.es6.js",
2682+
"./babylonjs/dist/bundle.es6.min.js",
2683+
"./babylonjs/benchmark/scene.js",
2684+
],
2685+
preload: {
2686+
PARTICLES_BLOB: "./babylonjs/data/particles.json",
2687+
PIRATE_FORT_BLOB: "./babylonjs/data/pirateFort.glb",
2688+
CANNON_BLOB: "./babylonjs/data/cannon.glb",
2689+
},
2690+
tags: ["Default", "js", "scene", "es6", "babylonjs"],
2691+
iterations: 5,
2692+
}),
26132693
// WorkerTests
26142694
new AsyncBenchmark({
26152695
name: "bomb-workers",
@@ -2819,7 +2899,7 @@ let BENCHMARKS = [
28192899
new WasmEMCCBenchmark({
28202900
name: "8bitbench-wasm",
28212901
files: [
2822-
"./polyfills/fast-text-encoding/1.0.3/text.js",
2902+
"./utils/polyfills/fast-text-encoding/1.0.3/text.js",
28232903
"./8bitbench/build/rust/pkg/emu_bench.js",
28242904
"./8bitbench/benchmark.js",
28252905
],
@@ -2884,7 +2964,7 @@ let BENCHMARKS = [
28842964

28852965

28862966
const PRISM_JS_FILES = [
2887-
"./startup-helper/StartupBenchmark.js",
2967+
"./utils/StartupBenchmark.js",
28882968
"./prismjs/benchmark.js",
28892969
];
28902970
const PRISM_JS_PRELOADS = {

babylonjs/README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Babylon.js Benchmarks for JetStream
2+
3+
This project contains two benchmarks for testing the performance of the Babylon.js 3D engine.
4+
5+
## Build Instructions
6+
7+
```bash
8+
# install required node packages.
9+
npm ci
10+
# build the workload, output is ./dist
11+
npm run build
12+
```
13+
14+
## Workloads
15+
16+
There are two distinct workloads in this benchmark suite:
17+
18+
### 1. Startup Workload
19+
20+
This benchmark measures the time it takes for the Babylon.js engine to initialize. It evaluates a large, bundled source file and measures the time to parse the code and execute a simple test. This workload is primarily focused on parse and startup time.
21+
22+
To run this benchmark in node for testing:
23+
```bash
24+
npm run test:startup
25+
```
26+
27+
### 2. Scene Workload
28+
29+
This benchmark measures the rendering performance of a complex 3D scene. It loads 3D models (`.glb` files), animations, and particle systems, and then renders the scene for a number of frames.
30+
31+
To run this benchmark in node for testing:
32+
```bash
33+
npm run test:scene
34+
```

babylonjs/benchmark/scene-node.mjs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { runComplexScene } from "../src/babylon-js-benchmark.mjs";
2+
import { promises as fs } from "fs";
3+
import path from "path";
4+
import { fileURLToPath } from "url";
5+
6+
const __filename = fileURLToPath(import.meta.url);
7+
const __dirname = path.dirname(__filename);
8+
9+
const fortPath = path.resolve(__dirname, "../data/pirateFort.glb");
10+
const cannonPath = path.resolve(__dirname, "../data/cannon.glb");
11+
const particlePath = path.resolve(__dirname, "../data/particles.json");
12+
13+
async function main() {
14+
try {
15+
const fortBuffer = await fs.readFile(fortPath);
16+
const cannonBuffer = await fs.readFile(cannonPath);
17+
const particleData = JSON.parse(await fs.readFile(particlePath, "utf-8"))
18+
const {classNames, cameraRotationLength} = await runComplexScene(fortBuffer, cannonBuffer, particleData, 1000);
19+
} catch(e) {
20+
console.error(e);
21+
console.error(e.stack);
22+
}
23+
}
24+
25+
main();

babylonjs/benchmark/scene.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// console.log = () => {};
2+
3+
globalThis.setTimeout = (callback, timeout) => callback();
4+
globalThis.requestAnimationFrame = (callback) => callback();
5+
6+
// JetStream benchmark.
7+
class Benchmark {
8+
iterationCount = 0;
9+
preloaded = {
10+
fortData: null,
11+
cannonData: null,
12+
particlesJson: null,
13+
};
14+
15+
constructor(iterationCount) {
16+
this.iterationCount = iterationCount;
17+
}
18+
19+
async init() {
20+
const [fort, cannon, particles] = await Promise.all([
21+
JetStream.getBinary(JetStream.preload.PIRATE_FORT_BLOB),
22+
JetStream.getBinary(JetStream.preload.CANNON_BLOB),
23+
JetStream.getString(JetStream.preload.PARTICLES_BLOB),
24+
]);
25+
this.preloaded.fortData = fort;
26+
this.preloaded.cannonData = cannon;
27+
this.preloaded.particlesJson = JSON.parse(particles);
28+
}
29+
30+
async runIteration() {
31+
const {classNames, cameraRotationLength} = await BabylonJSBenchmark.runComplexScene(
32+
this.preloaded.fortData,
33+
this.preloaded.cannonData,
34+
this.preloaded.particlesJson,
35+
100
36+
);
37+
const lastResult = {
38+
classNames,
39+
cameraRotationLength
40+
};
41+
this.validateIteration(lastResult);
42+
}
43+
44+
validateIteration(lastResult) {
45+
this.expect("this.lastResult.classNames.length", lastResult.classNames.length, 2135);
46+
this.expect("this.lastResult.cameraRotationLength", lastResult.cameraRotationLength, 0);
47+
}
48+
49+
expect(name, value, expected) {
50+
if (value != expected)
51+
throw new Error(`Expected ${name} to be ${expected}, but got ${value}`);
52+
}
53+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { runTest } from "../src/babylon-js-benchmark.mjs";
2+
3+
console.log(runTest());

0 commit comments

Comments
 (0)