Open source GPU simulator
Run CUDA on a rack of GPUs you don’t have.
PantheonSim simulates NVIDIA GPUs on an ordinary CPU: the driver, the CUDA runtime
and its libraries, nvidia-smi and NVML. Unmodified programs compile, run, and
fail exactly where they would on a card.
- No GPU, no sign-up
- CUDA 12 and 13
- 13 NVIDIA GPU profiles
- Apache-2.0
(vgpu 8xNVIDIA H100 80GB HBM3) ~$ nvidia-smi
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.126.20 Driver Version: 580.126.20 CUDA Version: 13.0 |
+-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA H100 80GB HBM3 On | 00000000:01:00.0 Off | N/A |
| 0% 32C P8 56W / 700W | 0MiB / 81559MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
| ... |
+-----------------------------------------+------------------------+----------------------+
| 7 NVIDIA H100 80GB HBM3 On | 00000000:08:00.0 Off | N/A |
| 0% 32C P8 56W / 700W | 0MiB / 81559MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
~$ nvidia-smi --query-gpu=index,name,memory.total --format=csv
index, name, memory.total [MiB]
0, NVIDIA H100 80GB HBM3, 81559 MiB
1, NVIDIA H100 80GB HBM3, 81559 MiB
2, NVIDIA H100 80GB HBM3, 81559 MiB
3, NVIDIA H100 80GB HBM3, 81559 MiB
4, NVIDIA H100 80GB HBM3, 81559 MiB
5, NVIDIA H100 80GB HBM3, 81559 MiB
6, NVIDIA H100 80GB HBM3, 81559 MiB
7, NVIDIA H100 80GB HBM3, 81559 MiB
Runs against it
- nvcc
- cuBLAS
- cuDNN
- NCCL
- cuFFT
- cuSPARSE
- NVRTC
- Numba
- Triton
- nvidia-smi
- pynvml
- nvitop
How it works
Your program doesn’t know the difference
Build with the real CUDA toolkit and run the binary unchanged. The simulator answers every call it makes, under the same library names a GPU driver installs.
Build it as you always do
The real
nvcc, your own build system. Link the CUDA runtime shared.nvcc -cudart shared app.cu -o app
Pick the machine
Any card, up to sixteen of them.
nvidia-smiand NVML agree.vgpu run --gpu nvidia/h100 ./app
See what hardware hides
Races named to the line, exact counters, and the same binary on every profile at once.
vgpu test --matrix ./app
Coverage
The whole stack a CUDA program touches
Not a mock of a few calls: the driver API, the runtime and the libraries, checked against NVIDIA’s own on a physical GPU, and the tools that read them.
Unmodified CUDA programs
Binaries built with CUDA 12 or 13 run as they are, their kernels interpreted on the CPU.
The libraries programs link
cuBLAS, cuBLASLt, cuDNN, cuFFT, cuRAND, cuSPARSE, cuSOLVER, NCCL, NVRTC, NPP and nvJPEG.
The tools people run
nvidia-smi, NVML, pynvml, gpustat and nvitop report
the machine you asked for. Numba and Triton kernels run too.
Cards measured, not guessed
Eleven GPU profiles were read off physical cards and checked against them. The rest say they are not.
Debugging
What a real GPU won’t tell you
A simulator sees every lane of every warp. These come straight from it.
Find the race
Two warps wrote the same word with no barrier. Hardware usually hides it; this names the kernel, the PTX line and the instruction.
$ VGPU_SCHEDULER=adversarial vgpu run --race ./race
[vgpu] cudaLaunchKernel: VirtualGPU error [data-race]: read-write race on shared memory at byte offset 0: warp 2 and warp 0 both reach it with no bar.sync between them, so which one wins is not something the program decided. Hardware usually hides this because warps advance together; it is a real race either way
in kernel '_Z5tallyPi', PTX line 38
instruction: st.shared.u32[_ZZ5tallyPiE5local], %r4
GPU profile: nvidia/h100
Run on every card at once
The same binary on each profile, outputs compared. A result that depends on the card shows up here, not in production.
$ vgpu test --matrix ./vectoradd
profile exit output
nvidia/a10 0 baseline
nvidia/a100 0 identical
nvidia/h100 0 identical
nvidia/rtx3060 0 identical
nvidia/a100-sxm4-40gb 0 identical
...
11 profiles: 10 identical to nvidia/a10, 0 different
Count, don’t sample
Exact instruction, memory and sector counts for every launch. They do not move between runs.
$ VGPU_COUNTERS=1 vgpu run ./vectoradd
[vgpu][counters] _Z3addPfPKfS1_i grid=4x1x1 block=256x1x1
blocks=4 warps=32
inst_executed=704 thread_inst_executed=22528 lanes_active_avg=32.00/32
divergent_branches=0 barriers=0 atomics=0 (0 B)
global ld=2048 st=1024 read=8192 B write=4096 B
shared ld=0 st=0 read=0 B write=0 B
local ld=0 st=0 read=0 B write=0 B
sectors global=384 over 96 requests (4.00 per request, 100% of ideal)
shared bank_conflicts=0 over 0 requests
mix fp16=0 fp32=1024 fp64=0 int=5120 cvt=3072
ctrl=2048 mem=7168 tensor=0 misc=4096 (tensor issues=0)
...
Continuous integration
CUDA tests on every pull request, no GPU runners
Hosted runners have no GPU, so CUDA code usually goes untested until someone has a card free. One step gives the job simulated ones.
- Works on standard runners.
ubuntu-24.04, nothing to provision. - Cached build. The simulator builds once and is restored on later runs.
- Real tools.
nvcc,nvidia-smiandvgpuare on the path.
jobs: cuda-tests: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: pantheongpu/pantheonsim@main with: gpu: nvidia/h100 count: 2 - run: | nvcc -arch=compute_90 test.cu -o test vgpu run ./test
Playground
Try it without installing anything
Pick up to eight cards and an operating system and you get a Linux machine in the browser.
- A real toolchain.
nvccfor CUDA 12.6 or 13.0, Numba, git and CMake. - An editor and a terminal. Compile a kernel, run it, point the race detector at it.
- Up to an hour per session. Ten idle minutes end it. The network reaches GitHub, GitLab, PyPI, PyTorch, NVIDIA and Hugging Face.

GPUs
Thirteen cards, from Turing to Blackwell
Every profile the simulator carries. “Measured” means its values were read off a physical card and diffed against it.
| Card | Architecture | Memory | Compute | Profile |
|---|---|---|---|---|
| NVIDIA H100 SXM5 80GB | Hopper | 80 GB | 9.0 | measured |
| NVIDIA H100 PCIe 80GB | Hopper | 80 GB | 9.0 | measured |
| NVIDIA A100 80GB | Ampere | 80 GB | 8.0 | measured |
| NVIDIA A100 SXM4 40GB | Ampere | 40 GB | 8.0 | measured |
| NVIDIA A10 | Ampere | 24 GB | 8.6 | measured |
| NVIDIA A10G | Ampere | 24 GB | 8.6 | measured |
| NVIDIA L4 | Ada Lovelace | 24 GB | 8.9 | measured |
| NVIDIA L40S | Ada Lovelace | 48 GB | 8.9 | measured |
| NVIDIA Tesla T4 | Turing | 16 GB | 7.5 | measured |
| NVIDIA RTX 3060 | Ampere | 12 GB | 8.6 | measured |
| NVIDIA GH200 480GB | Hopper/Grace | 96 GB | 9.0 | measured |
| NVIDIA H200 | Hopper | 141 GB | 9.0 | not yet measured |
| NVIDIA B200 | Blackwell | 192 GB | 10.0 | not yet measured |
Questions
Honest about what it is
Run it on every commit; keep a run on physical GPUs before a release.
Can I run CUDA code without an NVIDIA GPU?
Yes. PantheonSim implements the CUDA driver API, the runtime and the common CUDA libraries on the
CPU, so a program built with the real nvcc runs unmodified under vgpu run.
It checks what a program does, not how fast it does it.
Does it predict GPU performance?
No. There is no timing, cache or thermal model, so timings mean nothing. What it gives instead is exact: instruction, memory and sector counts that do not change between runs.
Do PyTorch and CuPy work?
Not today. PyTorch’s bundled CUDA runtime checks the driver’s identity and refuses a simulated one, and CuPy links the runtime statically. Numba runs unmodified, and Triton works with a one-line hook.
Can I run CUDA tests in CI without GPU runners?
Yes. PantheonSim is also a GitHub Action: one step gives a job simulated GPUs on a standard hosted runner, so CUDA code can be compiled and tested on every pull request. Keep a run on physical GPUs before a release. How to set it up.
Which GPUs can it simulate?
Thirteen NVIDIA profiles from Turing to Blackwell, including the T4, A10, A100, L4, L40S, H100, GH200, H200 and B200. Eleven were measured on physical cards and checked against them; the rest are marked as not yet measured.
What happens when a program uses something that is not implemented?
The call returns the documented CUDA error and the simulator prints where: the instruction, the PTX line, the kernel and the GPU profile. A gap is never silent, but the program carries on, so check return codes.
Is PantheonSim affiliated with NVIDIA?
No. It is an independent project, open source under Apache-2.0, built from documented public interfaces. It contains no NVIDIA code.
A GPU machine in a minute.
Open one in the browser, or build it on any Linux machine with CMake and a C++20 compiler. No GPU needed; the CUDA libraries build when a CUDA toolkit is installed.
$ git clone https://github.com/pantheongpu/pantheonsim $ cd pantheonsim && ./scripts/build.sh $ ./build/vgpu shell --gpu nvidia/h100 --count 8 --cuda 13.0 --driver 580.126.20