Files
Mujoco_WASM/wasm/tests/benchmark_test.ts
T
Matias Manevi 76e64d96bb Add JavaScript bindings and WASM support
Co-authored-by: Matija Kecman <matijak@google.com>
Co-authored-by: Sebastian Noreña Rendón <sebas.norena@creativa77.com.ar>
Co-authored-by: Kyle Bayes <kylebayes@google.com>
PiperOrigin-RevId: 826094938
Change-Id: Id2658a187bc078056f4410c71202696753319e64
2025-10-30 10:38:16 -07:00

114 lines
3.6 KiB
TypeScript

// Copyright 2025 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import 'jasmine';
import { MainModule, DoubleBuffer } from "../dist/mujoco_wasm_benchmark"
import loadMujoco from "../dist/mujoco_wasm_benchmark.js"
describe('MuJoCo WASM Benchmark Tests', () => {
let mujoco: MainModule;
function isNumberArraySorted(arr: number[]): boolean {
for (let i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
return false;
}
}
return true;
}
function verifySorted(state: any, kind: string): void {
let array: number[] = [];
if (kind === 'NumberArray') {
array = state as number[];
} else {
const bufferView = (state as DoubleBuffer).GetView();
array = Array.from(bufferView) as number[];
}
const sorted = isNumberArraySorted(array);
if (!sorted) {
console.error(` Verification failed for ${kind}. Array was ${array}`);
}
}
function runBenchmark(iterations: number, items: number, kind: string) {
let state: any;
let func: (state: any) => any;
if (kind === 'NumberArray') {
state = new Array(items).map(() => Math.random())
func = (state) => mujoco.SortNumberArray(state);
} else if (kind === 'DoubleBuffer') {
state = mujoco.DoubleBuffer.FromArray(
new Array(items).map(() => Math.random()));
func = (state) => mujoco.SortDoubleBuffer(state);
} else {
throw new Error(`Unsupported benchmark type: ${kind}`);
}
// Warmup JIT compiler to get stable results
for (let i = 0; i < 1000; i++) {
const sortedState = func(state);
verifySorted(sortedState, kind);
}
// Measurement
const totalStartTime = performance.now();
for (let i = 0; i < iterations; i++) {
func(state);
}
const totalEndTime = performance.now();
if (kind === 'DoubleBuffer') {
state.delete();
}
// Report results
const totalTime = totalEndTime - totalStartTime;
const avgTimeMilliseconds = totalTime / iterations;
console.log(`Benchmark: "Sort ${kind} ${iterations} iterations with ${
items} items" - AVG time per call: ${
avgTimeMilliseconds.toFixed(2)} ms`);
return {
totalTime, avgTimeMilliseconds,
}
}
beforeAll(async () => {
mujoco = await loadMujoco();
});
it('should benchmark NumberArray and DoubleBuffer and compare results',
() => {
const na1 = runBenchmark(100, 1_000, 'NumberArray');
const na2 = runBenchmark(100, 400_000, 'NumberArray');
const db1 = runBenchmark(100, 1_000, 'DoubleBuffer');
const db2 = runBenchmark(100, 400_000, 'DoubleBuffer');
// The actual time should be much faster than that but the intention of
// the check is to catch huge regressions without a flakey test
const _100ms = 100;
expect(db2.avgTimeMilliseconds).toBeLessThan(_100ms);
expect(db1.totalTime).toBeLessThan(na1.totalTime);
expect(db2.totalTime).toBeLessThan(na2.totalTime);
expect(db1.avgTimeMilliseconds).toBeLessThan(na1.avgTimeMilliseconds);
expect(db2.avgTimeMilliseconds).toBeLessThan(na2.avgTimeMilliseconds);
});
});