An OpenCL 1.2 driver with a SPIR-V interpreter and a browser based debugger for catching concurrency bugs in OpenCL kernels. This project takes heavy inspiration from Oclgrind.
Kernels run on an interpreter instead of hardware, so vodd can watch every memory access and report data races, barrier divergence and out of bounds reads.
vodd compiles OpenCL C to SPIR-V using clang, so a clang with a SPIR-V target is required.
| Tool | Minimum | Notes |
|---|---|---|
| Rust | 1.88 | edition 2024, install with rustup |
| clang | 23 | compiles OpenCL C to LLVM IR |
| llvm-spirv | 23 | carries the line information the debugger needs |
| spirv-link | v2026.3 | only needed to link multiple programs |
The toolchain can be installed using Homebrew on both macOS and Linux
brew install llvm spirv-llvm-translator spirv-tools
If you do not have Homebrew, install it first from https://brew.sh.
If the tools are not on your path, point vodd at them with VODD_CLANG,
VODD_LLVM_SPIRV and VODD_SPIRV_LINK.
cargo build --release
This produces target/release/libvodd.so, or libvodd.dylib on macOS.
Run any OpenCL program against vodd by preloading the driver
LD_PRELOAD=./target/release/libvodd.so clinfo
The program will see a single platform named vodd with a single device.
You can also link a program against the driver directly
cc my-program.c -Ltarget/release -lvodd -Wl,-rpath,$PWD/target/release
On macOS, link directly. There is no LD_PRELOAD, and DYLD_INSERT_LIBRARIES
does not divert calls away from the system OpenCL framework
cc my-program.c -DCL_TARGET_OPENCL_VERSION=120 -Itests/vendor/OpenCL-Headers -Ltarget/release -lvodd
DYLD_LIBRARY_PATH=target/release ./a.out
Checks are off by default. Turn them on with VODD_CHECK, which takes a comma
separated list.
| Value | Reports |
|---|---|
all |
everything below except uniform-writes |
none |
nothing, the default |
mem |
out of bounds, misaligned and read only accesses |
type |
accesses that disagree with the declared type |
divergence |
work items reaching different barriers |
races |
unsynchronised accesses from different work items |
uniform-writes |
writes of the same value from every work item |
VODD_CHECK=all LD_PRELOAD=./target/release/libvodd.so ./my-program
| Variable | Meaning |
|---|---|
VODD_CHECK |
which correctness checks to run, see above |
VODD_LOG |
append diagnostics to this file instead of standard error |
VODD_MAX_ERRORS |
stop reporting after this many diagnostics, default 1000 |
VODD_THREADS |
work items to run at once, default the smaller of the work group and the core count |
VODD_DEBUG |
address to serve the debugger on, for example 127.0.0.1:8080 |
VODD_CLANG |
path to clang |
VODD_LLVM_SPIRV |
path to llvm-spirv |
VODD_SPIRV_LINK |
path to spirv-link |
Set VODD_DEBUG to an address and vodd will serve a debugger there. The
program waits at the first line of the kernel until you continue it.
VODD_DEBUG=127.0.0.1:8080 LD_PRELOAD=./target/release/libvodd.so ./my-program
Open http://127.0.0.1:8080 in a browser.
Tests use a Makefile. Run make on its own to list the targets.
-
Fetch the vendored Khronos repositories
make submodules -
Run the Rust suites, the SPIR-V interpreter, the OpenCL conformance tests and the kernel checks
make test-rust -
Run the browser tests for the debugger, this installs node packages and chromium the first time
make test-browser -
Run everything
make test -
Check formatting and lints
make lint -
Format the Rust sources and the templates
make fmt
