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
8 × H100, on a CPU
(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
Real output from a simulated machine. There is no GPU in it.

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.

  1. 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
  2. Pick the machine

    Any card, up to sixteen of them. nvidia-smi and NVML agree.

    vgpu run --gpu nvidia/h100 ./app
  3. 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-smi and vgpu are on the path.
Set it up
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. nvcc for 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.
Open the playground
The PantheonSim playground: a CUDA editor beside a terminal that has just compiled and run a kernel on a simulated H100

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.

CardArchitectureMemoryComputeProfile
NVIDIA H100 SXM5 80GBHopper80 GB9.0measured
NVIDIA H100 PCIe 80GBHopper80 GB9.0measured
NVIDIA A100 80GBAmpere80 GB8.0measured
NVIDIA A100 SXM4 40GBAmpere40 GB8.0measured
NVIDIA A10Ampere24 GB8.6measured
NVIDIA A10GAmpere24 GB8.6measured
NVIDIA L4Ada Lovelace24 GB8.9measured
NVIDIA L40SAda Lovelace48 GB8.9measured
NVIDIA Tesla T4Turing16 GB7.5measured
NVIDIA RTX 3060Ampere12 GB8.6measured
NVIDIA GH200 480GBHopper/Grace96 GB9.0measured
NVIDIA H200Hopper141 GB9.0not yet measured
NVIDIA B200Blackwell192 GB10.0not 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