| |
| |
| |
| |
| |
| |
|
|
| import * as ort from '../vendor/ort/ort.wasm.bundle.min.mjs'; |
|
|
| |
| |
| |
| ort.env.wasm.numThreads = 1; |
| |
| |
| |
| ort.env.wasm.wasmPaths = new URL('../vendor/ort/', import.meta.url).href; |
|
|
| export class Policy { |
| constructor(session, name, inputName, outputName) { |
| this.session = session; |
| this.name = name; |
| this.inputName = inputName; |
| this.outputName = outputName; |
| this.lastMs = 0; |
| this.emaMs = 0; |
| } |
|
|
| static async load(url, name) { |
| const session = await ort.InferenceSession.create(url, { |
| executionProviders: ['wasm'], |
| graphOptimizationLevel: 'all', |
| }); |
| return new Policy(session, name, session.inputNames[0], session.outputNames[0]); |
| } |
|
|
| |
| async act(obs) { |
| const tensor = new ort.Tensor('float32', obs, [1, obs.length]); |
| const t0 = performance.now(); |
| const out = await this.session.run({ [this.inputName]: tensor }); |
| this.lastMs = performance.now() - t0; |
| |
| this.emaMs = this.emaMs === 0 ? this.lastMs : 0.9 * this.emaMs + 0.1 * this.lastMs; |
| return out[this.outputName].data; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| async benchmark(obs, { warmup = 100, iterations = 1000, blockSize = 50 } = {}) { |
| for (let i = 0; i < warmup; i++) await this.act(obs); |
|
|
| const blocks = []; |
| const nBlocks = Math.max(1, Math.floor(iterations / blockSize)); |
| for (let b = 0; b < nBlocks; b++) { |
| const t0 = performance.now(); |
| for (let i = 0; i < blockSize; i++) { |
| const tensor = new ort.Tensor('float32', obs, [1, obs.length]); |
| await this.session.run({ [this.inputName]: tensor }); |
| } |
| blocks.push((performance.now() - t0) / blockSize); |
| } |
|
|
| const sorted = [...blocks].sort((a, b) => a - b); |
| const mean = blocks.reduce((a, b) => a + b, 0) / blocks.length; |
| const quantile = (q) => sorted[Math.min(sorted.length - 1, Math.floor(q * sorted.length))]; |
| return { |
| scheme: this.name, |
| iterations: nBlocks * blockSize, |
| warmup, |
| block_size: blockSize, |
| blocks: nBlocks, |
| |
| mean_ms: mean, |
| block_median_ms: quantile(0.5), |
| block_p95_ms: quantile(0.95), |
| block_min_ms: sorted[0], |
| block_max_ms: sorted[sorted.length - 1], |
| timer_resolution_note: |
| 'per-call latency is below the browser timer resolution; figures are ' + |
| 'block totals divided by block size, and the spread is across blocks', |
| }; |
| } |
| } |
|
|
| |
| export function environmentReport() { |
| return { |
| user_agent: navigator.userAgent, |
| hardware_concurrency: navigator.hardwareConcurrency ?? null, |
| wasm_threads: ort.env.wasm.numThreads, |
| |
| |
| platform: navigator.platform ?? null, |
| }; |
| } |
|
|