TornadoVM README

The project's README from github.com/beehive-lab/TornadoVM. As one markdown file: README.md.

TornadoVM logo

Write Java. Run on GPUs. Fast.

TornadoVM is a GPU programming framework for Java that works with JDK 21+ (currently JDK 21-27). It JIT-compiles Java bytecode into NVIDIA CUDA, OpenCL C, and Apple Metal (MSL) at runtime, so your existing Java code runs on NVIDIA GPUs (via CUDA), AMD, Intel, and Apple Silicon GPUs, integrated GPUs, and multi-core CPUs.

On NVIDIA hardware it goes further: beyond generating CUDA, TornadoVM now calls straight into the NVIDIA library ecosystem (cuBLAS, cuFFT, cuDNN, cuDF) and exposes Tensor Core mma.sync instructions from pure Java. No CUDA C. No JNI bindings to maintain. No native toolchain in your application. In addition, it has support for Tile Programming cuTile via its TileContext API.

Build & Test Tornado API Install with SDKMAN! Docs Slack

Latest release: TornadoVM 7.0.0 (JDK 21 - JDK 27) — native NVIDIA library integration (cuBLAS / cuFFT / cuDNN) and Tensor Core intrinsics, plus a native Apple Metal backend for Apple Silicon. Changelog · Website · Documentation


This is the whole programming model

TornadoVM gives you three Java APIs for writing GPU kernels, from the least to the most explicit about how work maps onto the hardware. All three build the same TaskGraph, run through the same TornadoExecutionPlan, and can be mixed in a single graph. Here's one computation, dense matrix multiplication, C = A × B written all three ways:

Loop Parallel API (@Parallel) KernelContext API
void matmul(Matrix2DFloat A,
     Matrix2DFloat B,
     Matrix2DFloat C, int size) {
  for (@Parallel int i=0; i<size; i++) {
    for (@Parallel int j=0; j<size; j++) {
      float sum = 0f;
      for (int k=0; k<size; k++)
        sum += A.get(i,k)*B.get(k,j);
      C.set(i, j, sum);
    }
  }
}

// TornadoVM infers the thread
// mapping from the @Parallel loops.
void matmul(KernelContext ctx,
     FloatArray A, FloatArray B,
     FloatArray C, int size) {
  int row = ctx.globalIdx;
  int col = ctx.globalIdy;
  float sum = 0f;
  for (int k=0; k<size; k++)
    sum += A.get(k*size+row)
         * B.get(col*size+k);
  C.set(col*size+row, sum);
}

// You name the thread; TornadoVM
// still owns memory + dispatch.
TileContext API (CuTile) 🆕 — CUDA backend only
void matmul(TileContext tc, HalfFloatArray A, HalfFloatArray B, FloatArray C,
            int m, int n, int k) {
  PartitionView aView = tc.partition(tc.view(A, m, k), TILE, TILE);
  PartitionView bView = tc.partition(tc.view(B, k, n), TILE, TILE);
  PartitionView cView = tc.partition(tc.view(C, m, n), TILE, TILE);

  Tile acc = tc.zeros(DType.F32, TILE, TILE);
  for (int step = 0; step < k / TILE; step++) {
    acc = tc.mma(aView.load(tc.bidX(), step), bView.load(step, tc.bidY()), acc);
  }
  cView.store(acc, tc.bidX(), tc.bidY());
}

// No thread index, no shared memory, no barrier, no instruction shape —
// the tile compiler picks them.

Pick the one that matches how much control you need: @Parallel when TornadoVM should infer the thread mapping for you, KernelContext when you want CUDA/OpenCL/SYCL-style explicit thread indexing, and TileContext when you'd rather program in tiles than threads and let the tile compiler pick the tensor-core instructions. Each is covered in depth below. Programming guide →


Loop Parallel API (@Parallel)

The simplest of the three models. You just annotate the parallel loops with @Parallel and TornadoVM infers the whole launch configuration (global bounds, local work size) for you. Because the annotation is the only GPU-specific part, the same method also runs unmodified on the plain sequential JVM path, which makes it the easiest style to write and debug first.

Full runnable example: MatrixMultiplication2D.java. Programming guide →


KernelContext API

Write the kernel in Java with the same thread-indexing model you'd use in CUDA: global/local thread IDs, local memory, and barriers, with identical semantics across CUDA, OpenCL, and SYCL. TornadoVM still JIT-compiles the bytecode to a GPU kernel at runtime and manages all host↔device data transfers for you; on NVIDIA GPUs that kernel is emitted as CUDA PTX and compiled through NVRTC to a native cubin.

KernelContext gives you the full GPU programming model while TornadoVM handles memory management and runs the identical code across all four backends. Don't need that control? Drop KernelContext and use the Loop Parallel API above instead — both styles can be combined in the same TaskGraph. Full runnable example: MatrixMultiplication2DV1.java. Programming guide →


TileContext API (CuTile) 🆕

A task whose kernel takes a TileContext is compiled through NVIDIA CUDA Tile (nvcc -tilecubin --tile-only) instead of the SIMT path. You write what one tile block does; the tile compiler decides how many threads back it, which tensor-core instruction to issue, and how tiles move through shared memory. Nothing in the API names a thread, a warp or a fragment.

WorkerGrid2D worker = new WorkerGrid2D(n / TILE, n / TILE);   // TILE BLOCKS, not threads

Tile API guide → · runnable examples (matmul three ways, softmax, attention, quantized projection)


🟩 The NVIDIA ecosystem, native to Java

On NVIDIA hardware, TornadoVM is an open-source on-ramp to the whole CUDA software stack, callable from the same TaskGraph you already use. Generated kernels and native library calls share TornadoVM-managed device buffers on one CUDA stream, so a JIT-compiled kernel can feed a cuBLAS call and consume its output with no extra copies and no host synchronization.

Capability What it gives Java developers
CUDA backend Java bytecode → Graal IR → CUDA PTX → NVRTC → cubin, JIT-compiled and specialized to your data sizes and GPU at runtime.
cuBLAS / cuBLASLt library tasks SGEMV, SGEMM, strided-batched, TF32 and FP16 GemmEx on Tensor Cores, and cuBLASLt with plan caching and fused BIAS / GELU_BIAS epilogues — one library task replaces a GEMM plus a separate activation kernel.
cuFFT library tasks C2C, R2C / C2R, and Z2Z transforms (1D and 2D) with capture-safe plan caching; FFT-filter pipelines mix with JIT kernels in one graph.
cuDNN library tasks Deep-learning primitives through the cuDNN graph API, including fused scaled-dot-product (flash) attention via cudnn-frontend.
cuDF library tasks RAPIDS relational primitives — multi-key ordering, grouped SUM/MIN/MAX/MEAN/COUNT over several columns, whole-column reductions, inclusive scan, inner join and stream compaction — the cross-row operations no @Parallel loop expresses. A generated projection can feed a cuDF group-by in one graph, with the intermediate never leaving the device.
Tensor Core MMA intrinsics mma.sync exposed through KernelContext (mmaLoadA/B, mma, mmaStore) — FP16 (m16n8k16 → FP32) and INT8 (m16n8k32 → INT32), with swizzled shared-memory staging. Not a binding: real CUDA generated from Java.
CUDA Graphs executionPlan.withCUDAGraph() records kernels, library calls, and transfers into a captured graph and replays them with a single cuGraphLaunch.
CUDA Tile (TileContext) 🆕 A second compilation path: kernels written over tiles go through nvcc -tilecubin, and the tile compiler picks the threads, the tensor-core instruction, and the shared-memory staging. Details.

Mixing your own kernels with NVIDIA's tuned libraries looks like this:

TaskGraph tg = new TaskGraph("hybrid")
    .transferToDevice(DataTransferMode.EVERY_EXECUTION, matrix, vector)
    .task("preprocess", MyKernels::preprocess, matrix)              // JIT-compiled Java kernel
    .libraryTask("gemv", CuBlas::cublasSgemv,                       // native cuBLAS call
            CUBLAS_OP_T, m, n, alpha, matrix, lda, vector, incx, beta, output, incy)
    .task("postprocess", MyKernels::activate, output)              // JIT-compiled Java kernel
    .transferToHost(DataTransferMode.EVERY_EXECUTION, output);

try (TornadoExecutionPlan plan = new TornadoExecutionPlan(tg.snapshot())) {
    plan.withCUDAGraph().execute();   // captured once, replayed each iteration
}

Library bindings are discovered via Java ServiceLoader, bind the calls through java.lang.foreign (a JNI module only if the library genuinely needs compiled C/C++), and any native library joins the graph with no core runtime changes. TornadoVM is a member of the NVIDIA Inception Program and has presented this work at NVIDIA GTC. Hybrid API guide →


What people build with it

Project What it shows
🦙 GPULlama3.java LLM inference (Llama 3, Qwen 3, Mistral, Phi-3, Granite, DeepSeek distills) in pure Java — 117 tok/s on an RTX 5090, official GPU engine for LangChain4j and Quarkus
🔆 TornadoVM-Ray-Tracer Real-time ray tracing in Java, interactive frame rates on consumer GPUs
📷 kfusion-tornadovm KinectFusion 3D reconstruction — a full computer-vision pipeline on integrated and discrete GPUs
📷 Gaia Mission (ESA) High-performance algorithms for space exploration at the European Space Agency use TornadoVM

TornadoVM is used to accelerate machine learning and deep learning, computer vision, physics simulations, financial applications, computational photography, and signal processing. Building something with TornadoVM? Tell us — we feature community projects.


⚡ Quick start

Prerequisites

Install via SDKMAN!

sdk install tornadovm

Pick a backend-specific build if you prefer a smaller install. Candidate versions are per-JDK (swap jdk21 below for jdk22plus to install a build for that JDK line):

Backend SDKMAN! version Targets
OpenCL (default) 7.0.0-opencl NVIDIA / AMD / Intel GPUs, multi-core CPUs, FPGAs
CUDA 7.0.0-cuda NVIDIA GPUs (CUDA) — codegen, Tensor Cores, cuBLAS/cuFFT/cuDNN/cuDF library tasks
Metal 🆕 7.0.0-metal Apple Silicon GPUs (M1–M4), natively via MSL
All backends 7.0.0-full Everything above

Binaries are also on the official website. For Docker and AWS (CPUs/GPUs) see the linked guides.

Verify your devices

tornado --devices

Run your first program

# Unix (Linux/macOS)
java @$TORNADOVM_HOME/tornado-argfile \
  -cp $TORNADOVM_HOME/share/java/tornado/tornado-examples-7.0.0.jar \
  uk.ac.manchester.tornado.examples.compute.MatrixVectorRowMajor

# Windows 10+
java @%TORNADOVM_HOME%\tornado-argfile ^
  -cp %TORNADOVM_HOME%\share\java\tornado\tornado-examples-7.0.0.jar ^
  uk.ac.manchester.tornado.examples.compute.MatrixVectorRowMajor

More examples — NBody, DFT, KMeans, matrix kernels, reductions: tornado-examples


📦 Use TornadoVM in your project

Maven Central coordinates are per-JDK — pin the -jdk21 / -jdk22plus version matching the JDK you build with:

<dependencies>
  <dependency>
    <groupId>io.github.beehive-lab</groupId>
    <artifactId>tornado-api</artifactId>
    <version>7.0.0-jdk21</version>
  </dependency>
  <dependency>
    <groupId>io.github.beehive-lab</groupId>
    <artifactId>tornado-runtime</artifactId>
    <version>7.0.0-jdk21</version>
  </dependency>
</dependencies>

❓ FAQ

What can TornadoVM do on NVIDIA GPUs specifically?

On NVIDIA hardware TornadoVM JIT-compiles your Java kernels to CUDA PTX and compiles them through NVRTC to native cubins. On top of that, it integrates the NVIDIA software ecosystem directly into the TaskGraph: cuBLAS / cuBLASLt (including TF32 and FP16 GemmEx on Tensor Cores and fused epilogues), cuFFT, cuDNN (including fused flash attention) and cuDF (RAPIDS relational primitives) are available as library tasks that share device buffers and a CUDA stream with your generated kernels. You can also target Tensor Cores directly from Java via mma.sync intrinsics (FP16 and INT8), and capture the whole pipeline into a CUDA Graph for single-launch replay. On develop there is a second compilation path as well: a kernel taking a TileContext is compiled through NVIDIA CUDA Tile, where a tile rather than a thread is the unit of work. See The NVIDIA ecosystem, native to Java.

What's the licensing situation for commercial use?

The parts your application links against — Tornado-API and all the modules you code with — are Apache 2.0. The runtime and drivers are GPLv2 with Classpath Exception, the same license as OpenJDK itself: it does not impose copyleft obligations on your application, exactly as running on OpenJDK doesn't. Full per-module breakdown below.

Does it replace my JVM?

No. TornadoVM is a plug-in to your existing OpenJDK or GraalVM installation. It complements the JVM with the ability to offload selected tasks to accelerators, handling device memory management and kernel orchestration. Everything else in your application runs on the JVM as normal.

Which hardware is supported?

Multi-core CPUs; dedicated GPUs from NVIDIA, AMD, and Intel; and integrated GPUs (Apple Silicon M1–M4, Intel HD Graphics, ARM Mali). Backends can be installed individually or together, and tasks can migrate between devices at runtime. NVIDIA GPUs can be driven either through the CUDA backend (with the library and Tensor Core features above) or through the OpenCL backend.

How fast is it?

It depends on the workload — data-parallel kernels with enough arithmetic intensity see order-of-magnitude speedups over sequential Java; see the benchmarking guide and the GPULlama3.java performance tables for end-to-end numbers on real applications (e.g. 117 tok/s for Llama-3 inference on an RTX 5090). For compute-bound linear algebra, the cuBLAS library tasks reach the tuned vendor throughput — including full FP16 Tensor Core rates — from Java.


🤝 Contributing & community


📚 Resources & publications

Videos, presentations, and articles: resources. Selected academic publications: publications.

If you use TornadoVM ≥ 0.2 in research, please cite:

@inproceedings{Fumero:DARHH:VEE:2019,
 author    = {Fumero, Juan and Papadimitriou, Michail and Zakkak, Foivos S. and
              Xekalaki, Maria and Clarkson, James and Kotselidis, Christos},
 title     = {{Dynamic Application Reconfiguration on Heterogeneous Hardware}},
 booktitle = {Proceedings of the 15th ACM SIGPLAN/SIGOPS International
              Conference on Virtual Execution Environments},
 series    = {VEE '19},
 year      = {2019},
 doi       = {10.1145/3313808.3313819},
 publisher = {Association for Computing Machinery}
}

For Tornado 0.1 (initial release), cite Clarkson et al., ManLang '18.

Licenses per module

Link the Tornado-API (Apache 2.0) into your application.

Modules License
Tornado-API, Tornado-Assembly, Tornado-scripts, Tornado-Annotation, Tornado-Unittests, Tornado-Benchmarks, Tornado-Examples, Tornado-Matrices, Tornado-Drivers-OpenCL-Headers Apache 2.0
Tornado-Runtime, Tornado-Drivers GPLv2 with Classpath Exception

Acknowledgments

Partially funded by Intel Corporation and by EU & UKRI grants (most recent first): AERO (101092850), P2CODE (101093069), ENCRYPT (101070670), TANGO (101070052), ELEGANT (957286), E2Data (780245), ACTiCLOUD (732366); and EPSRC grants PAMELA (EP/K008730/1) and AnyScale Apps (EP/L000725/1).

Meet the team.

TornadoVM (beehive-lab/TornadoVM)

Searching Database…

这是什么?一个开源的 Java GPU 编程框架:它在运行时把 Java 字节码即时编译成 NVIDIA CUDA、OpenCL C 或 Apple Metal 代码,让 Java 程序跑在 GPU 和多核 CPU 上。支持 JDK 21-27。
那它是一门新语言,还是用来替代 JVM 的?都不是——它是现有 OpenJDK 或 GraalVM 的一个插件,也是一个普通的 Maven 依赖。所有代码仍然在 JVM 上运行,只有你标记的任务会被交给加速器处理。
在它跑起来之前,我的电脑上需要装什么?JDK 21 或更新版本并把 JAVA_HOME 指向它,GCC/G++ 13+,以及你目标平台所需的驱动环境:OpenCL 运行时、CUDA Toolkit(库任务还需要 cuBLAS/cuFFT/cuDNN),用 Metal 的话只需要 macOS。
上手之前有什么要注意的坑吗?你必须使用 JDK 21-27 并设置好 JAVA_HOME,还要 GCC 13+;新的 TileContext(CuTile)API 仅支持 CUDA 后端;另外性能提升取决于工作负载——具备真正算术强度的数据并行内核受益最大。
能用在商业产品里吗?可以——你编写代码所用的 API 和模块采用 Apache 2.0 许可证,运行时和驱动采用带 Classpath Exception 的 GPLv2(即 OpenJDK 自己的许可证),不会给你的应用带来任何 copyleft 义务。
它支持哪些硬件?NVIDIA、AMD 和 Intel 的 GPU,Apple Silicon(M1-M4)及其他集成 GPU,多核 CPU,以及通过 OpenCL 后端支持的 FPGA。各后端可以单独安装也可以一起安装,任务还能在运行时于不同设备之间迁移。
GPU 代码怎么写——我必须学 CUDA 吗?不用。有三种 Java API,甚至可以在同一个 TaskGraph 里混用:给循环加上 @Parallel 注解,TornadoVM 会自动推断线程映射;用 KernelContext 做 CUDA 风格的显式索引,支持本地内存和 barrier;或者用 TileContext,按 tile 编程,编译器会自动选择 tensor core 指令。
在 NVIDIA GPU 上,除了普通内核我还能得到什么?你即时编译的内核可以在同一个 TaskGraph 中共享设备缓冲区,并对 cuBLAS、cuFFT、cuDNN 和 cuDF 进行原生调用;Tensor Core 的 mma.sync 内置指令可以从纯 Java 代码以 FP16 和 INT8 使用;整个流水线还能捕获成一个 CUDA Graph,只需一次启动就能重放。
我的 Java 程序能快多少?取决于工作负载:算术强度足够的数据并行内核相比串行 Java 能有一个数量级的加速,cuBLAS 任务则能达到厂商调优的吞吐量。举个实际数字:GPULlama3.java 在 RTX 5090 上跑 Llama-3 推理可达 117 tok/s。
大家用它真正做出了什么东西?纯 Java 的 LLM 推理——GPULlama3.java 是 LangChain4j 和 Quarkus 的官方 GPU 引擎;此外还有一个实时光线追踪器、KinectFusion 三维重建,以及为 ESA 的 Gaia 空间任务开发的高性能算法。
Size
172.7 MB
Stars
1.5K
Age
8y
Commits · 90 Days