Choosing an execution model
Choose using your workload, dtype, array size and data lifetime. Small arrays may be faster in JavaScript; native, Wasm, fusion and Workers each have overhead. Measure the complete application path before choosing a more complex API.
Start with the data lifetime
| Workload | Starting point | Main cost to measure |
|---|---|---|
| One operation on existing TypedArrays | Ordinary calls | Binding and allocation overhead |
| Repeated operations on the same data | Resident buffers | Upload, reuse and final download |
| A supported chain of elementwise operations | Fused pipelines | Compilation and complete execution |
| Large pipelines that block interaction | Workers | Submission, total latency and responsiveness |
Reuse an engine and pass { out } when an existing destination is available. Avoid repeatedly creating engines, arenas or executors inside a hot loop.
Native and Wasm transfers
Native TypedArray calls borrow existing memory synchronously. Ordinary Wasm calls copy inputs into backend memory and copy results back. Resident buffers let you upload once, reuse data across calls and download the final result.
Include arena creation, allocation, upload, download and disposal when those happen per job. A fast resident kernel alone does not predict the cost of that lifecycle. Use a persistent arena when data can remain resident across frames or requests.
Fused pipelines
Fusion traverses the input once and avoids full-size intermediate arrays. Compile a plan once and reuse the compiled object. Repeated cache lookups still normalize the definition.
Constant mul → add → clamp chains have a specialized loop. Other supported plans use a bounded interpreter and can cost more than separate calls. Results for one specialized chain do not predict every pipeline's performance.
Query pipeline.capability or engine.getCapability() to inspect actual execution. Selecting a SIMD backend does not make every operation vectorized, and short inputs or vector tails can still run scalar code.
Workers
Workers keep large calculations off the main thread, but submit() still copies input snapshots synchronously. Startup, dispatch and result delivery add overhead. Reuse an executor and measure submission latency separately from completion time.
Measure event-loop or animation-frame gaps when responsiveness is the goal. A workload may become more responsive while taking longer to finish. For small tasks, synchronous operations may be a better fit.
Worker byte budgets bound admitted task payload, not process RSS. Include caller-owned arrays, engine memory, retained Wasm capacity and garbage collection when assessing application memory use.
Compare equivalent work
JavaScript comparisons must preserve each f32 rounding step and integer wrapping rule. Keep numerical accuracy checks separate from timing. Repeat measurements on the same machine with the same assets and include transfer/allocation costs that occur in production.
See running benchmarks for commands, report formats and measurement boundaries.