Measuring GPU acceleration accurately is harder than it looks: JIT compilation, driver warm-up, data-transfer overhead, and JVM garbage collection can all skew results if you measure naively. TornadoVM ships a dedicated benchmarking module —Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Deepak-Sangle/TornadoVM/llms.txt
Use this file to discover all available pages before exploring further.
tornado.benchmarks — that handles warm-up, iteration counting, and baseline comparison automatically. The suite covers a diverse set of compute kernels so you can evaluate TornadoVM across different memory access patterns, arithmetic intensities, and data sizes. This guide explains how to run the standard benchmarks, interpret the output, extend the suite with your own kernels, and use JMH for micro-benchmarking.
The Benchmark Suite
Thetornado-benchmarks module lives at <tornadovm-root>/tornado-benchmarks/ and is compiled as part of the standard TornadoVM build. All benchmarks follow the same structure: a pure-Java sequential baseline alongside a TornadoVM-accelerated version, iterated a configurable number of times with the results reported as average, median, best, and speedup over the sequential baseline.
Available Benchmarks
saxpy
Single-precision
a*x + y vector operation. Classic memory-bandwidth benchmark.addImage
Element-wise addition of two 2D image buffers.
stencil
1D stencil operation — tests cache-friendly sequential access patterns.
convolvearray / convolveimage
2D convolution on flat arrays and image types. Tests spatial locality.
blackscholes
Black-Scholes option pricing — embarrassingly parallel, heavy on transcendentals.
montecarlo
Monte Carlo π estimation — independent random trials, highly parallel.
blurFilter
Gaussian blur on a 2D image — tests 2D stencil with a larger footprint.
nbody
N-body gravitational simulation — O(n²) all-pairs, high arithmetic intensity.
sgemm / dgemm
Single and double-precision matrix–matrix multiplication.
mandelbrot
Mandelbrot set rendering — divergent control flow, per-pixel independence.
dft
Discrete Fourier Transform — O(n²) reference implementation.
euler / renderTrack
Euler integration and ray-casting render tracking kernels.
Running Benchmarks
The tornado-benchmarks.py Runner
After building TornadoVM and sourcing the environment, the benchmark runner is available on your PATH:
Common Invocations
Interpreting Benchmark Output
Each benchmark prints one result line per device. Here is an annotated example:Field definitions
Field definitions
| Field | Meaning |
|---|---|
bm=convolve-array-100-2048-2048-5 | Benchmark name, iteration count (100), data dimensions (2048×2048), filter size (5) |
id=java-reference | This line is the pure-Java sequential baseline |
device=0:0 | TornadoVM backend index : device index (see --devices) |
average | Mean execution time in nanoseconds across all iterations |
median | Median execution time — more robust to outliers than mean |
firstIteration | First-iteration time — includes JIT compilation and driver warm-up |
best | Fastest single iteration — approximates peak throughput |
speedupAvg | java-reference average / device average — overall speedup |
speedupMedian | Speedup based on median values |
speedupFirstIteration | Speedup including warm-up cost — typically lower |
CV | Coefficient of variation (std dev / mean × 100%) — measures stability |
deviceName | Human-readable backend and device name |
Pay attention to
CV (coefficient of variation). Values above 15–20% indicate unstable measurements — consider increasing --iterations or excluding first-iteration timings from your analysis.JMH Integration
For micro-benchmarks following the Java Microbenchmark Harness (JMH) methodology, the suite provides a--jmh flag and per-benchmark JMH entry points.
Running All Benchmarks with JMH
Running a Single Benchmark via JMH
Each benchmark has a dedicated JMH entry point following the naming conventionJMH<BENCHMARK>:
avgt) minimises JIT and GC noise better than a manual timing loop.
Writing Custom Benchmarks
Custom benchmarks extend theBenchmarkDriver base class, which provides the iteration loop, timing infrastructure, and result reporting automatically.
Extend BenchmarkDriver
Create your benchmark class by extending
uk.ac.manchester.tornado.benchmarks.BenchmarkDriver:Performance Tips
Choose the right data size
Choose the right data size
GPU kernels have a fixed overhead for kernel launch, JIT compilation, and PCIe data transfer. For most benchmarks, meaningful speedups only appear above 256K–1M elements. Always verify that your working set fits in GPU memory.
Allow enough warm-up iterations
Allow enough warm-up iterations
The first iteration includes LLVM/NVRTC kernel compilation time and can be 10–100× slower than steady-state. Exclude
firstIteration timings from speedup analysis, or use JMH which handles warm-up automatically. The default benchmark runner uses 131 iterations (approximately 130 measured iterations).Understand JIT compilation effects
Understand JIT compilation effects
TornadoVM compiles kernels once per unique task graph configuration and caches them. Benchmarks that repeatedly change data size or device will re-trigger compilation. Enable the code cache with
-Dtornado.opencl.codecache.enable=true to persist compiled kernels across JVM restarts.Monitor CV for stability
Monitor CV for stability
A coefficient of variation (CV) above 15% in benchmark results usually means interference from the OS scheduler, GPU power management, or JVM GC. Try running with
-Xms24G -Xmx24G -server to reduce GC pressure, and disable GPU Boost if your hardware supports it.Compare against the right baseline
Compare against the right baseline
The
java-reference baseline in the benchmark suite is a straightforward sequential Java loop — not a hand-tuned BLAS or multi-threaded baseline. For a fair comparison against optimised libraries, add your own baseline to the benchmark.