Files
workinf_Blender_Wasm/tools/web/check-release-performance.mjs
2026-08-12 04:47:48 -04:00

82 lines
3.8 KiB
JavaScript

import assert from "node:assert/strict";
import fs from "node:fs";
import { performance } from "node:perf_hooks";
import factory from "../../web/app/src/vendor/blender/web_engine.js";
const wasmBinary = fs.readFileSync(new URL("../../web/app/src/vendor/blender/web_engine.wasm", import.meta.url));
const limits = {
100000: Number(process.env.WEB_PERF_100K_MS ?? 120_000),
1000000: Number(process.env.WEB_PERF_1M_MS ?? 180_000),
heapBytes: Number(process.env.WEB_PERF_MAX_HEAP_BYTES ?? 1_610_612_736),
};
function grid(targetTriangles) {
const columns = Math.ceil(Math.sqrt(targetTriangles / 2));
const rows = Math.ceil(targetTriangles / (columns * 2));
const positions = new Float32Array((columns + 1) * (rows + 1) * 3);
for (let y = 0; y <= rows; y++) {
for (let x = 0; x <= columns; x++) {
const offset = (y * (columns + 1) + x) * 3;
positions[offset] = x / columns;
positions[offset + 1] = y / rows;
positions[offset + 2] = Math.sin(x * 0.03) * Math.cos(y * 0.03) * 0.01;
}
}
const triangleCount = Math.min(targetTriangles, columns * rows * 2);
const indices = new Uint32Array(triangleCount * 3);
for (let triangle = 0; triangle < triangleCount; triangle++) {
const cell = Math.floor(triangle / 2);
const x = cell % columns;
const y = Math.floor(cell / columns);
const a = y * (columns + 1) + x;
const offset = triangle * 3;
if (triangle % 2 === 0) indices.set([a, a + 1, a + columns + 2], offset);
else indices.set([a, a + columns + 2, a + columns + 1], offset);
}
return { positions, indices, triangleCount };
}
function alloc(engine, typed) {
const pointer = engine._malloc(typed.byteLength);
assert.ok(pointer > 0, `WASM allocation failed for ${typed.byteLength} bytes`);
engine.HEAPU8.set(new Uint8Array(typed.buffer, typed.byteOffset, typed.byteLength), pointer);
return pointer;
}
const results = [];
for (const target of [100_000, 1_000_000]) {
const engine = await factory({ wasmBinary });
const source = grid(target);
const pointers = [];
try {
const positions = alloc(engine, source.positions); pointers.push(positions);
const indices = alloc(engine, source.indices); pointers.push(indices);
const positionsOut = engine._malloc(source.positions.byteLength); pointers.push(positionsOut);
const indicesOut = engine._malloc(source.indices.byteLength); pointers.push(indicesOut);
const counts = Array.from({ length: 6 }, () => engine._malloc(4)); pointers.push(...counts);
const started = performance.now();
const ratio = target === 100_000 ? 0.9 : 1;
const result = engine._web_engine_decimate_apply(
positions, source.positions.length / 3, indices, source.triangleCount,
0, ratio, 1, 0, 0, 0, 0, -1, 1e-4,
0, 1, 0, 0, 0, 0,
positionsOut, source.positions.length, counts[0],
indicesOut, source.indices.length, counts[1],
0, 0, counts[2], 0, 0, counts[3], 0, 0, counts[4], counts[5],
);
const elapsedMs = performance.now() - started;
assert.equal(result, 0, `native decimate failed for ${target} triangles with code ${result}`);
const outputTriangles = engine.HEAPU32[counts[1] >>> 2] / 3;
assert.ok(outputTriangles > 0 && outputTriangles <= source.triangleCount, "invalid performance-gate output topology");
const heapBytes = engine.HEAPU8.byteLength;
assert.ok(elapsedMs <= limits[target], `${target} triangle gate exceeded ${limits[target]}ms: ${elapsedMs.toFixed(1)}ms`);
assert.ok(heapBytes <= limits.heapBytes, `${target} triangle gate exceeded WASM heap limit: ${heapBytes}`);
results.push({ target, ratio, outputTriangles, elapsedMs: Math.round(elapsedMs), heapBytes });
}
finally {
for (const pointer of pointers.reverse()) if (pointer) engine._free(pointer);
}
}
process.stdout.write(`release-performance-ok ${JSON.stringify(results)}\n`);