TornadoVM’s Loop Parallel API lets you turn ordinary sequential Java methods into GPU kernels without touching any GPU-specific code. Instead of rewriting your algorithms in OpenCL or CUDA, you annotate loop-index variables withDocumentation 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.
@Parallel to declare which loops can execute concurrently across hardware threads, and you annotate accumulator parameters with @Reduce to indicate that TornadoVM should generate a parallel reduction pattern. The compiler and runtime handle all the thread-dispatch, synchronisation, and backend-specific code generation automatically. This API is the recommended starting point for developers who are new to GPU programming.
The @Parallel Annotation
@Parallel is a runtime-retained annotation that targets local variables (specifically loop-index declarations). When TornadoVM’s JIT compiler encounters a loop whose counter is marked @Parallel, it maps each iteration to a separate GPU thread, deriving the ND-Range work size from the loop’s bounds.
- 1D Parallelism
- 2D Parallelism
- 3D Parallelism
Annotate a single loop counter to dispatch a 1D grid of threads — one thread per iteration.TornadoVM launches
data.getSize() threads, each executing one iteration in parallel.The loop bounds must be deterministic at JIT-compile time — they can be method parameters or constants, but not values computed from non-constant expressions that the TornadoVM compiler cannot resolve.
Sequential vs. Annotated: Side-by-Side
The annotation approach keeps the business logic entirely in Java. You can run the exact same method on CPU (by not routing it through aTaskGraph) or on GPU by wrapping it in a task graph — there is no code duplication.
- Primitive arrays (
float[]) replaced with TornadoVM off-heap types (FloatArray). - Direct array indexing (
a[i]) replaced with typed accessors (a.get(i)). - The
@Parallelannotation on the loop counter.
The @Reduce Annotation
@Reduce targets method parameters (or local variables acting as accumulators) to signal that the annotated variable participates in a parallel reduction. TornadoVM automatically generates work-group-level reduction code for GPUs and scalar-fold code for CPUs — the correct pattern is selected at JIT-compile time based on the target device.
Supported reduction operators:
- Addition (
+) - Multiplication (
*) - Maximum (
Math.max) - Minimum (
Math.min)
int, long, float, and double element types.
Reduction Sum Example
Reduction Max Example
Complete Reduction Task Graph
Map/Reduce Pipeline
Multi-task graphs let you chain a map step and a reduce step inside a single execution plan, keeping the intermediate data on the device.Reductions with Data Dependencies
@Reduce works even when each reduction term is computed on-the-fly from other inputs, as in the π estimation below:
Limitations and Best Practices
What TornadoVM Can Parallelise
- Loops with simple integer bounds (
i < size,i < array.getSize()) - Element-wise operations with no cross-iteration data dependencies
- Reductions using
+,*,max,minon supported element types - Nested
@Parallelloops (up to 3 dimensions)
Current Limitations
- Loops with non-constant or data-dependent bounds may not parallelize
- Pointer aliasing between input and output arrays is not supported
@Parallelon non-outermost loops only when outer loops are also@Parallel- Only static methods are compiled to GPU kernels
Why only static methods?
Why only static methods?
TornadoVM’s JIT compiler analyses the bytecode of the target method to generate GPU code. Instance methods introduce implicit
this references and potential heap accesses that the compiler cannot safely eliminate. Using static methods (with all data passed as explicit parameters) ensures the compiler can produce a pure, side-effect-free GPU kernel.Can I mix @Parallel and non-@Parallel loops?
Can I mix @Parallel and non-@Parallel loops?
Yes. Non-annotated inner loops (like the
k loop in matrix multiplication) execute sequentially within each GPU thread. Only the loops marked @Parallel are distributed across the thread grid. This is the standard tiling pattern: outer parallel loops select the tile, inner sequential loops compute within it.