NVIDIA CUDA Devices (PTX and CUDA C backends)
TornadoVM provides two backends that target NVIDIA GPUs through the NVIDIA Driver API:
The PTX backend, which generates NVIDIA PTX assembly directly.
The CUDA backend, which generates CUDA C source at runtime, compiles it with NVRTC to PTX, and executes it through the same CUDA Driver API.
Both backends share the same prerequisites (NVIDIA driver + CUDA Toolkit), described below. The CUDA C backend is documented in its own section further down this page.
Prerequisites
In order to use the PTX or the CUDA backend of TornadoVM, you will need a CUDA compatible device (NVIDIA GPUs with CUDA support).
Driver Installation
CUDA Toolkit. If you don’t have it
installed already, you can follow this
guide.C_INCLUDE_PATH and LD_LIBRARY_PATH variables to include the
CUDA headers.$ export C_INCLUDE_PATH=/usr/local/cuda/include:${C_INCLUDE_PATH}
$ export LD_LIBRARY_PATH=/usr/local/cuda/lib64:${LD_LIBRARY_PATH}
To ensure that the installation has been successful, you can run the following commands: nvidia-smi and nvcc --version.
The output of nvidia-smi should be similar to:
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.100 Driver Version: 440.100 CUDA Version: 10.2 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce GTX 1650 Off | 00000000:01:00.0 Off | N/A |
| N/A 51C P8 1W / N/A | 73MiB / 3914MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 1095 G /usr/lib/xorg/Xorg 36MiB |
| 0 1707 G /usr/lib/xorg/Xorg 36MiB |
+-----------------------------------------------------------------------------+
The output of nvcc --version should be similar to:
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2019 NVIDIA Corporation
Built on Wed_Oct_23_19:24:38_PDT_2019
Cuda compilation tools, release 10.2, V10.2.89
TornadoVM Installation
PTX backend selected and run tornado --devices.The output of the TornadoVM build containing both backends (PTX and OpenCL) should look like this:
Number of Tornado drivers: 2
Total number of devices : 1
Tornado device=0:0
CUDA-PTX -- GeForce GTX 1650
Global Memory Size: 3.8 GB
Local Memory Size: 48.0 KB
Workgroup Dimensions: 3
Max WorkGroup Configuration: [1024, 1024, 64]
Device OpenCL C version: N/A
Total number of devices : 2
Tornado device=1:0
NVIDIA CUDA -- GeForce GTX 1650
Global Memory Size: 3.8 GB
Local Memory Size: 48.0 KB
Workgroup Dimensions: 3
Max WorkGroup Configuration: [1024, 1024, 64]
Device OpenCL C version: OpenCL C 1.2
Tornado device=1:1
Intel(R) OpenCL HD Graphics -- Intel(R) Gen9 HD Graphics NEO
Global Memory Size: 24.8 GB
Local Memory Size: 64.0 KB
Workgroup Dimensions: 3
Max WorkGroup Configuration: [256, 256, 256]
Device OpenCL C version: OpenCL C 2.0
Note that the first Tornado driver will always correspond to the CUDA device detected by the PTX backend.
Addressing Possible issues
In some cases, running nvidia-smi might show the error NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver.
This can happen because the driver module is not loaded due to a
blacklist file.
You can remove this by running: sudo rm /etc/modprobe.d/blacklist-nvidia.conf
On Ubuntu, the driver can also fail to load if it is not selected in prime-select. In order to select it, you can run
prime-select nvidia or prime-select on-demand.
LIBRARY_PATH variable to the libcuda library in order to build
TornadoVM.export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/cuda/lib64/stubsAfter these changes, a reboot might be required for the driver module to be loaded.
Testing the PTX Backend of TornadoVM
We have tested the PTX backend of TornadoVM on the following configurations:
GPU
|
Arch
|
PTX ISA
Version
|
Target
|
Driver
version
|
CUDA
version
|
Status
|
|---|---|---|---|---|---|---|
RTX 3070
|
Ampere
|
8.6
|
sm_86
|
510.54
|
11.8
|
OK
|
RTX 2060
|
Turing
|
7.5
|
sm_75
|
510.54
|
11.6
|
OK
|
Quadro
GP100
|
Pascal
|
6.0
|
sm_60
|
384.111
|
9.0
|
Fun
ctional
|
GeForce
GTX
1650
|
Turing
|
6.5
|
sm_75
|
440.100
|
10.2
|
OK
|
GeForce
930MX
|
Maxwell
|
6.4
|
sm_50
|
418.56
|
10.1
|
OK
|
GeForce
930MX
|
Maxwell
|
6.5
|
sm_50
|
450.36
|
11.0
|
OK
|
DISCLAIMER:
The PTX backend might fail with the Quadro GP100, driver 384.111, with segmentation faults for some of the unit test due to driver issues.
The CUDA C Backend
What it is
The CUDA backend is a new backend that generates CUDA C source at
runtime, compiles it with NVRTC to PTX, and executes it through the
CUDA Driver API (cuModuleLoadDataEx / cuLaunchKernel).
It complements the existing PTX backend (which emits PTX assembly directly):
both share the same NVIDIA Driver-API execution path, but the CUDA backend
uses an OpenCL-C-style source-generation front end that emits textual CUDA C
(extern "C" __global__ void ..., blockIdx.x * blockDim.x + threadIdx.x
for the global thread id, __shared__ for local memory, and
__syncthreads() for barriers).
Status: Work-in-progress. Core functionality works end-to-end on real hardware; several feature buckets are still pending (see Supported and in-progress features).
Compilation and execution flow
Graal lowers the Java task to LIR and emits CUDA C text.
CUDAProgram(JNI) runs NVRTC (nvrtcCompileProgramwith--gpu-architecture=compute_<major><minor>queried from the device, plus--include-pathfor the CUDA headers), producing PTX.The PTX is loaded via
cuModuleLoadDataEx, the kernel is fetched withcuModuleGetFunction, and launched withcuLaunchKernel. Memory and streams usecuMemAlloc/cuMemcpy*Async/CUstream.
The backend is implemented in two modules:
tornado-drivers/cuda— the backend (Graal compiler integration + runtime), Java packageuk.ac.manchester.tornado.drivers.cuda.tornado-drivers/cuda-jni— the native JNI layer (CUDA Driver API + NVRTC), which buildslibtornado-cuda.so.
Prerequisites
JDK 21 (set
JAVA_HOMEaccordingly).CUDA Toolkit including NVRTC and
libcuda(see Driver Installation above).GCC and CMake to build the native JNI layer.
Verified on an NVIDIA RTX 3070 (compute capability 8.6) with CUDA 11.x.
Building the CUDA backend
Important
Build the CUDA backend on its own (not together with OpenCL). With both
the CUDA and OpenCL backends installed, the unit tests can silently run on
the OpenCL device and report false positives. A CUDA-only build exposes
exactly one backend (Tornado device 0:0), so the results are
unambiguous.
# JDK 21 is required
export JAVA_HOME=/path/to/jdk21
# Build the CUDA backend (tornado-drivers/cuda + cuda-jni) and the SDK
make BACKEND=cuda
The build maps to the Maven cuda-backend profile, which activates the
tornado-drivers/cuda and tornado-drivers/cuda-jni modules.
Selecting the CUDA device
After a CUDA-only build, tornado --devices lists a single
CUDADriver device:
$ tornado --devices
Number of Tornado drivers: 1
Driver: CUDADriver
Total number of devices : 1
Tornado device=0:0 (DEFAULT)
CUDA C 1.0 -- <your NVIDIA GPU>
Because there is a single backend, the CUDA device is 0:0. To pin the unit
tests to it, pass -Dtornado.unittests.device=0:0:
# Run a kernel and dump the generated CUDA C source
tornado-test --printKernel --jvm="-Dtornado.unittests.device=0:0" \
uk.ac.manchester.tornado.unittests.arrays.TestArrays#testVectorAdditionFloat
# Run a unit-test class on the CUDA device
tornado-test --ea -V --jvm="-Dtornado.unittests.device=0:0" <test.class>
Supported and in-progress features
Supported
Scalar
@Parallelkernels end-to-end (int/float/double/long), loops, conditionals / branching, and grids.Global-memory reductions and
KernelContextlocal-memory reductions (__shared__,__syncthreads).Math built-ins (
sin/cos/sqrt/ …,signumincluding NaN semantics,clamp,radians, relationalisequal/ …).Local and private scalar arrays, and the native CUDA scalar types.
FP16 / ``__half`` scalar add / sub / mul / div (via
cuda_fp16.h).NVRTC runtime compilation with a device-matched
--gpu-architectureand include paths.
In progress / pending
Vector types (
float2/3/4,int*,double*): width ≤ 4 with native CUDA vector types and component-wise ops. Widths 8 and 16 have no native CUDA equivalent and are marked unsupported.Object fields / instance kernels (the
thisreceiver and object parameter marshalling).Private array copies.
FP16 conversions and half-precision matrix multiply.
Atomics (a subset of CUDA
atomicAdd/atomicSub/atomicCAS).Two-stage local reductions.
CUDA Graph API support (
withCUDAGraph).
Not applicable (PTX/other-backend specific)
Swizzled local arrays (PTX-only).
DP4A quantization (PTX-only).
Prebuilt SPIR-V / OpenCL binary tests.