Skip to content

Commit 3800e92

Browse files
committed
Merge branch 'main' into 2025-10-27_js-tokens
2 parents 6e82cba + bb77d06 commit 3800e92

Some content is hidden

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

55 files changed

+120032
-37
lines changed

JetStreamDriver.js

Lines changed: 101 additions & 24 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.
@@ -906,7 +906,8 @@ class Benchmark {
906906
if (this.plan.preload) {
907907
let preloadCode = "";
908908
for (let [ variableName, blobURLOrPath ] of this.preloads) {
909-
console.log(variableName, blobURLOrPath);
909+
console.assert(variableName?.length > 0, "Invalid preload name.");
910+
console.assert(blobURLOrPath?.length > 0, "Invalid preload data.");
910911
preloadCode += `JetStream.preload[${JSON.stringify(variableName)}] = "${blobURLOrPath}";\n`;
911912
}
912913
scripts.add(preloadCode);
@@ -1062,8 +1063,8 @@ class Benchmark {
10621063

10631064
if (this.plan.preload) {
10641065
this.preloads = [];
1065-
for (let prop of Object.getOwnPropertyNames(this.plan.preload)) {
1066-
promises.push(this.loadBlob("preload", prop, this.plan.preload[prop]).then((blobData) => {
1066+
for (const [name, resource] of Object.entries(this.plan.preload)) {
1067+
promises.push(this.loadBlob("preload", name, resource).then((blobData) => {
10671068
if (!globalThis.allIsGood)
10681069
return;
10691070
this.preloads.push([ blobData.prop, blobData.blobURL ]);
@@ -1072,7 +1073,7 @@ class Benchmark {
10721073
// We'll try again later in retryPrefetchResourceForBrowser(). Don't throw an error.
10731074
if (!this.failedPreloads)
10741075
this.failedPreloads = { };
1075-
this.failedPreloads[prop] = true;
1076+
this.failedPreloads[name] = true;
10761077
JetStream.counter.failedPreloadResources++;
10771078
}));
10781079
}
@@ -1129,9 +1130,8 @@ class Benchmark {
11291130
}
11301131

11311132
if (this.plan.preload) {
1132-
for (const prop of Object.getOwnPropertyNames(this.plan.preload)) {
1133-
const resource = this.plan.preload[prop];
1134-
const allDone = await this.retryPrefetchResource("preload", prop, resource);
1133+
for (const [name, resource] of Object.entries(this.plan.preload)) {
1134+
const allDone = await this.retryPrefetchResource("preload", name, resource);
11351135
if (allDone)
11361136
return true; // All resources loaded, nothing more to do.
11371137
}
@@ -1151,21 +1151,21 @@ class Benchmark {
11511151
if (!this.plan.preload) {
11521152
return;
11531153
}
1154-
for (let [name, file] of Object.entries(this.plan.preload)) {
1155-
const compressed = isCompressed(file);
1154+
for (let [name, resource] of Object.entries(this.plan.preload)) {
1155+
const compressed = isCompressed(resource);
11561156
if (compressed && !JetStreamParams.prefetchResources) {
1157-
file = uncompressedName(file);
1157+
resource = uncompressedName(resource);
11581158
}
11591159

11601160
if (JetStreamParams.prefetchResources) {
1161-
let bytes = new Int8Array(read(file, "binary"));
1161+
let bytes = new Int8Array(read(resource, "binary"));
11621162
if (compressed) {
11631163
bytes = zlib.decompress(bytes);
11641164
}
1165-
this.shellPrefetchedResources[file] = bytes;
1165+
this.shellPrefetchedResources[resource] = bytes;
11661166
}
11671167

1168-
this.preloads.push([name, file]);
1168+
this.preloads.push([name, resource]);
11691169
}
11701170
}
11711171

@@ -1755,10 +1755,10 @@ class WasmLegacyBenchmark extends Benchmark {
17551755
}
17561756

17571757
str += "};\n";
1758-
1759-
const keys = Object.keys(this.plan.preload);
1760-
for (let i = 0; i < keys.length; ++i) {
1761-
str += `JetStream.loadBlob("${keys[i]}", "${this.plan.preload[keys[i]]}", () => {\n`;
1758+
let preloadCount = 0;
1759+
for (const [name, resource] of Object.entries(this.plan.preload)) {
1760+
preloadCount++;
1761+
str += `JetStream.loadBlob(${JSON.stringify(name)}, "${resource}", () => {\n`;
17621762
}
17631763
if (this.plan.async) {
17641764
str += `doRun().catch((e) => {
@@ -1769,7 +1769,7 @@ class WasmLegacyBenchmark extends Benchmark {
17691769
} else {
17701770
str += `doRun();`
17711771
}
1772-
for (let i = 0; i < keys.length; ++i) {
1772+
for (let i = 0; i < preloadCount; ++i) {
17731773
str += `})`;
17741774
}
17751775
str += `;`;
@@ -2256,6 +2256,21 @@ let BENCHMARKS = [
22562256
],
22572257
tags: ["default", "js", "Proxy"],
22582258
}),
2259+
new AsyncBenchmark({
2260+
name: "mobx-startup",
2261+
files: [
2262+
"./utils/StartupBenchmark.js",
2263+
"./mobx/benchmark.js",
2264+
],
2265+
preload: {
2266+
// Debug Sources for nicer profiling.
2267+
// BUNDLE: "./mobx/dist/bundle.es6.js",
2268+
BUNDLE: "./mobx/dist/bundle.es6.min.js",
2269+
},
2270+
tags: ["default", "js", "mobx", "startup", "es6"],
2271+
iterations: 30,
2272+
worstCaseCount: 3,
2273+
}),
22592274
new AsyncBenchmark({
22602275
name: "jsdom-d3-startup",
22612276
files: [
@@ -2437,7 +2452,7 @@ let BENCHMARKS = [
24372452
new WasmEMCCBenchmark({
24382453
name: "sqlite3-wasm",
24392454
files: [
2440-
"./polyfills/fast-text-encoding/1.0.3/text.js",
2455+
"./utils/polyfills/fast-text-encoding/1.0.3/text.js",
24412456
"./sqlite3/benchmark.js",
24422457
"./sqlite3/build/jswasm/speedtest1.js",
24432458
],
@@ -2502,7 +2517,7 @@ let BENCHMARKS = [
25022517
new AsyncBenchmark({
25032518
name: "transformersjs-bert-wasm",
25042519
files: [
2505-
"./polyfills/fast-text-encoding/1.0.3/text.js",
2520+
"./utils/polyfills/fast-text-encoding/1.0.3/text.js",
25062521
"./transformersjs/benchmark.js",
25072522
"./transformersjs/task-bert.js",
25082523
],
@@ -2524,7 +2539,7 @@ let BENCHMARKS = [
25242539
new AsyncBenchmark({
25252540
name: "transformersjs-whisper-wasm",
25262541
files: [
2527-
"./polyfills/fast-text-encoding/1.0.3/text.js",
2542+
"./utils/polyfills/fast-text-encoding/1.0.3/text.js",
25282543
"./transformersjs/benchmark.js",
25292544
"./transformersjs/task-whisper.js",
25302545
],
@@ -2547,7 +2562,7 @@ let BENCHMARKS = [
25472562
iterations: 5,
25482563
worstCaseCount: 1,
25492564
allowUtf16: true,
2550-
tags: ["default", "Wasm", "transformersjs"],
2565+
tags: ["Wasm", "transformersjs"],
25512566
}),
25522567
new WasmLegacyBenchmark({
25532568
name: "tfjs-wasm",
@@ -2608,6 +2623,68 @@ let BENCHMARKS = [
26082623
allowUtf16: true,
26092624
tags: ["default", "Wasm"],
26102625
}),
2626+
new AsyncBenchmark({
2627+
name: "babylonjs-startup-es5",
2628+
files: [
2629+
"./utils/StartupBenchmark.js",
2630+
"./babylonjs/benchmark/startup.js",
2631+
],
2632+
preload: {
2633+
BUNDLE: "./babylonjs/dist/bundle.es5.min.js",
2634+
},
2635+
arguments: {
2636+
expectedCacheCommentCount: 23988,
2637+
},
2638+
tags: ["startup", "js", "class", "es5", "babylonjs"],
2639+
iterations: 10,
2640+
}),
2641+
new AsyncBenchmark({
2642+
name: "babylonjs-startup-es6",
2643+
files: [
2644+
"./utils/StartupBenchmark.js",
2645+
"./babylonjs/benchmark/startup.js",
2646+
],
2647+
preload: {
2648+
BUNDLE: "./babylonjs/dist/bundle.es6.min.js",
2649+
},
2650+
arguments: {
2651+
expectedCacheCommentCount: 21222,
2652+
},
2653+
tags: ["Default", "js", "startup", "class", "es6", "babylonjs"],
2654+
iterations: 10,
2655+
}),
2656+
new AsyncBenchmark({
2657+
name: "babylonjs-scene-es5",
2658+
files: [
2659+
// Use non-minified sources for easier profiling:
2660+
// "./babylonjs/dist/bundle.es5.js",
2661+
"./babylonjs/dist/bundle.es5.min.js",
2662+
"./babylonjs/benchmark/scene.js",
2663+
],
2664+
preload: {
2665+
PARTICLES_BLOB: "./babylonjs/data/particles.json",
2666+
PIRATE_FORT_BLOB: "./babylonjs/data/pirateFort.glb",
2667+
CANNON_BLOB: "./babylonjs/data/cannon.glb",
2668+
},
2669+
tags: ["scene", "js", "es5", "babylonjs"],
2670+
iterations: 5,
2671+
}),
2672+
new AsyncBenchmark({
2673+
name: "babylonjs-scene-es6",
2674+
files: [
2675+
// Use non-minified sources for easier profiling:
2676+
// "./babylonjs/dist/bundle.es6.js",
2677+
"./babylonjs/dist/bundle.es6.min.js",
2678+
"./babylonjs/benchmark/scene.js",
2679+
],
2680+
preload: {
2681+
PARTICLES_BLOB: "./babylonjs/data/particles.json",
2682+
PIRATE_FORT_BLOB: "./babylonjs/data/pirateFort.glb",
2683+
CANNON_BLOB: "./babylonjs/data/cannon.glb",
2684+
},
2685+
tags: ["Default", "js", "scene", "es6", "babylonjs"],
2686+
iterations: 5,
2687+
}),
26112688
// WorkerTests
26122689
new AsyncBenchmark({
26132690
name: "bomb-workers",
@@ -2817,7 +2894,7 @@ let BENCHMARKS = [
28172894
new WasmEMCCBenchmark({
28182895
name: "8bitbench-wasm",
28192896
files: [
2820-
"./polyfills/fast-text-encoding/1.0.3/text.js",
2897+
"./utils/polyfills/fast-text-encoding/1.0.3/text.js",
28212898
"./8bitbench/build/rust/pkg/emu_bench.js",
28222899
"./8bitbench/benchmark.js",
28232900
],

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)