This guide walks you through verifying your TornadoVM installation, running a built-in example, and then writing your own GPU-accelerated program from scratch — first using the simpleDocumentation 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 annotation style, then using the lower-level KernelContext API. By the end you will have a complete, runnable program and understand exactly how to launch it with both the tornado command and the java @tornado-argfile approach.
Step 0: Prerequisites Check
Before diving in, confirm that TornadoVM and a suitable JDK are ready on your machine.Check your JDK version
JAVA_HOME is not set, TornadoVM will not start.Check that TORNADOVM_HOME is set
setvars.sh after a source build.List available devices
If
tornado is not on your PATH, add $TORNADOVM_HOME/bin (Linux/macOS) or %TORNADOVM_HOME%\bin (Windows) to your PATH environment variable and open a new terminal.Step 1: Run the Built-In Example
TornadoVM ships with a suite of ready-to-run examples. Running one now confirms that the runtime, native libraries, and GPU driver are all wired up correctly — before you write any code.--debug for more information:
Step 2: Write Your First GPU Program — @Parallel Style
The@Parallel annotation is the fastest way to accelerate an existing Java loop. TornadoVM inspects the annotated index variable and automatically maps each loop iteration to a separate GPU thread — you never write a thread ID calculation.
The following program performs an element-wise addition of two FloatArray buffers. FloatArray is TornadoVM’s off-heap array type, allocated outside the Java heap so it can be transferred to the GPU without an extra copy step.
Create the kernel method
Write a plain
static method with @Parallel on the loop variable. This method is valid Java and can run sequentially on the JVM with no changes — TornadoVM only accelerates it when it appears inside a TaskGraph.Build a TaskGraph
A
TaskGraph declares what to run. transferToDevice moves buffers to the GPU; task registers the kernel method; transferToHost copies results back.Snapshot the graph and create an execution plan
snapshot() produces an ImmutableTaskGraph — a frozen, thread-safe view of the task graph that cannot be modified. The TornadoExecutionPlan wraps it and provides all runtime controls (device selection, profiling, batching, etc.).Complete @Parallel Program
Step 3: The KernelContext Variant
KernelContext gives you explicit control over thread IDs, local (shared) memory, and synchronisation barriers — the same programming model as CUDA’s threadIdx/blockIdx or OpenCL’s get_local_id(). Use it when you need maximum performance, want to use local memory tiling, or need to call Tensor Core intrinsics.
The same vector addition rewritten with KernelContext:
Write the kernel with explicit thread indexing
ctx.globalIdx is TornadoVM’s equivalent of blockIdx.x * blockDim.x + threadIdx.x in CUDA. The bounds check (if (i < c.getSize())) is essential because the GPU may launch more threads than there are elements.Create a WorkerGrid and GridScheduler
With
KernelContext, you must specify the thread grid explicitly. WorkerGrid1D sets the total number of global threads; setLocalWork sets the work-group (block) size.When using
KernelContext, TornadoVM will not infer a thread grid automatically. If you omit withGridScheduler(grid), execution will throw an error. Always pair a KernelContext kernel with a GridScheduler.Step 4: Running Your Program
TornadoVM requires a set of JVM flags (--module-path, --add-exports, JVMCI settings, etc.) that would be tedious to type by hand. Two approaches handle this automatically.
- tornado command
- java @tornado-argfile
The Useful
tornado launcher is a wrapper script that sets all required flags and then invokes java. It is the simplest option for running from a terminal.tornado flags:| Flag | Effect |
|---|---|
--devices | List discovered devices and exit |
--printKernel / -pk | Print the generated OpenCL/CUDA/MSL kernel source |
--enableProfiler console | Print per-task profiling data to stdout |
--debug | Enable verbose debug logging |
--jvm="<opts>" | Pass extra JVM options (e.g., -Xmx8g, device selectors) |
Step 5: What to Explore Next
More Built-In Examples
The
tornado-examples JAR ships with NBody, DFT, KMeans, matrix multiplications, reductions, and more. Explore them in $TORNADOVM_HOME/share/java/tornado/.Run on a Specific Device
Use
-D<graphName>.<taskName>.device=<driver>:<device> to target a specific GPU or CPU. Run tornado --devices first to find the right IDs.Enable the Profiler
Add
--enableProfiler console (tornado) or -Dtornado.profiler=true (argfile) to print per-kernel dispatch, data transfer, and JIT compilation times.Print the Generated Kernel
Pass
--printKernel to tornado or -Dtornado.printKernel=true to the argfile invocation to see the CUDA PTX, OpenCL C, or Metal MSL that TornadoVM generated from your Java method.