TheDocumentation 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.
TaskGraph is TornadoVM’s primary abstraction for describing GPU workloads. It acts as a directed acyclic graph (DAG) that captures which Java methods should run on an accelerator, which data needs to travel to the device before execution, and which results must be read back afterward. Crucially, creating a TaskGraph does not trigger any computation or data movement — it only records intent. Execution only happens through a TornadoExecutionPlan, giving you a clean separation between workload description and execution policy.
Core Concepts
TaskGraph
A mutable builder that records tasks and data-transfer declarations. Think of it as the “blueprint” for your GPU pipeline.
ImmutableTaskGraph
A frozen snapshot of a
TaskGraph. Immutability guarantees thread safety and prevents accidental mutation between execution calls.TornadoExecutionPlan
Wraps one or more
ImmutableTaskGraph objects and provides the fluent API to select devices, enable profiling, and trigger execution.TornadoExecutionResult
Returned by every
.execute() call. Holds profiler data and execution metadata.Step-by-Step: Building Your First Pipeline
Write a parallelisable Java method
Methods targeted for GPU acceleration are ordinary Java static methods. Annotate loop variables with
@Parallel to hint at parallelism (see Annotations).Create a TaskGraph
Construct a
TaskGraph with a unique string name. This name becomes a prefix for all task IDs inside the graph (e.g. "graph.task").Declare device-bound data with transferToDevice
Tell TornadoVM which arrays must be on the accelerator before execution begins. Choose the appropriate
DataTransferMode for your access pattern.Register tasks with .task()
Link Java methods as GPU tasks. The first argument is a unique task ID, the second is a method reference, and the remaining arguments mirror the method signature.
Declare results with transferToHost
Specify which arrays should be synchronised back to CPU memory after execution.
Snapshot → ImmutableTaskGraph
Call
.snapshot() to freeze the graph. From this point the TaskGraph can continue to be mutated without affecting the immutable copy.DataTransferMode Reference
TheDataTransferMode enum controls when TornadoVM actually moves data between host and device memory.
- EVERY_EXECUTION
- FIRST_EXECUTION
- UNDER_DEMAND
Data is copied on every call to
.execute(). Use this for inputs that change between executions or for results you want back every time.The
DataTransferMode only influences the runtime data movement — the TornadoVM JIT compiler still sees all arguments and optimises accordingly regardless of the mode selected.Complete Working Example: Vector Addition
The following self-contained example demonstrates the entire lifecycle — allocation, task declaration, snapshotting, plan creation, execution, and verification.The .task() Method
The task() call accepts a method reference (or lambda) via TornadoVM’s TornadoFunctions interfaces. The framework supports methods with zero to twenty parameters.
Method reference vs. lambda expression
Method reference vs. lambda expression
Both styles are valid. Method references (
Class::method) are preferred for named, reusable kernels. Lambdas are convenient for one-off inline kernels.Chaining Multiple Tasks
A singleTaskGraph can hold any number of tasks. TornadoVM chains their execution on the device, eliminating redundant host↔device round-trips between tasks.
The intermediate array
c above does not need a transferToHost call — it lives entirely on the device and is consumed by t1 without touching the CPU.TornadoExecutionPlan Fluent API
TornadoExecutionPlan is the runtime controller. Its methods all return this (or a decorated subtype), enabling fluent chaining.
Available execution plan modifiers
Available execution plan modifiers
| Method | Effect |
|---|---|
.withDevice(TornadoDevice) | Run all graphs on a specific device |
.withDevice(String, TornadoDevice) | Target one named task to a specific device |
.withGridScheduler(GridScheduler) | Attach explicit thread grid (Kernel API) |
.withProfiler(ProfilerMode) | Enable profiler (SILENT or CONSOLE) |
.withPreCompilation() | JIT-compile all tasks without executing |
.withWarmUpIterations(int) | Run N warm-up rounds before timing |
.withBatch(String) | Enable batch processing (e.g. "512MB") |
.withConcurrentDevices() | Run independent tasks in parallel across devices |
AutoCloseable and Resource Management
TornadoExecutionPlan implements AutoCloseable. Always wrap it in a try-with-resources block so that device memory, command queues, and compiled kernels are freed deterministically.
Obtaining Profiler Results
When profiling is enabled, everyTornadoExecutionResult carries timing and memory-transfer metrics.
Profiler data is only populated when
.withProfiler(...) has been called. Querying profiler results without enabling the profiler returns zero or undefined values.