Here is a fact that should startle anyone who has studied CPUs: nobody outside NVIDIA knows
the full instruction set of an NVIDIA GPU. There is no public manual for the machine code;
it changes — sometimes drastically — with every hardware generation; and yet a CUDA program compiled
in 2010 still runs on a GPU designed in 2026. On the CPU side, where
The GPU world pulled off a beautiful trick: it kept the idea of the ISA-as-contract but moved the contract up one level — from the silicon to a virtual instruction set that no chip has ever executed directly. This lesson follows a kernel from source code to executing silicon, and the journey explains both how GPU vendors redesign their machines every two years without breaking anything, and why we will be free to invent our own ISA when this course builds its capstone GPU in module 12.
At build time, the compiler translates your kernel not into machine code but into a virtual ISA — NVIDIA's is called PTX — a clean, stable, assembly-like intermediate language for an idealised SIMT machine:
This is what ships inside your application, and this is the contract: PTX is documented, versioned, and forward-compatible. Then, on the user's machine, the driver JIT-compiles the PTX into the GPU's actual machine ISA — NVIDIA's is called SASS — which is undocumented, generation-specific, and free to change utterly. New register file layout? Different instruction encodings? Split an instruction into three, fuse five into one? Fine: ship a new driver, and every existing program JIT-compiles onto the new silicon. The hardware team got the one freedom CPU architects dream of: redesign the microarchitecture and the machine ISA without breaking a single binary.
Step through the pipeline. Notice where the dashed line falls: everything above it happens once, on the developer's machine; everything below happens on every user's machine, against whatever GPU happens to be installed:
Now follow one kernel launch. Your host program makes an API call — conceptually
launch(vecAdd, blocks, threadsPerBlock, args). That call does not reach into
the GPU and start threads. Instead:
Notice what is missing: there is no operating system on the GPU. No scheduler process, no interrupts driving time-slices, no syscalls. A kernel is a batch job: submitted into a queue, run to completion, results collected afterwards — 1960s mainframe operation reborn at gigahertz. Every OS-like duty (scheduling queues, memory management, compilation, multiplexing between applications) is performed by the driver on the host. The driver is the GPU's operating system.
The runtime's other half manages memory. The GPU has its own DRAM, so the classic discipline is explicit: allocate device memory, copy inputs across the interconnect, launch, copy results back. Those transfers ride a bus that is orders of magnitude narrower than the GPU's local memory bandwidth, which is why "keep data resident on the device" is the first commandment of GPU performance. Modern stacks soften the ceremony with unified memory — one pointer space, pages migrated on demand by driver and hardware — a convenience whose costs and machinery we will weigh when we design the memory system in the next module.
This lesson looks like software, but it is load-bearing for the silicon we design later. First, the launch path is hardware: our capstone GPU in module 12 needs a command processor — something that reads launch packets from memory and feeds a work distributor — or nothing ever runs. Second, and more liberating: the virtual/physical ISA split means the machine ISA is ours to invent. As long as some translation layer accepts kernels above us, we can choose our own instruction encodings, register conventions and scheduling rules, optimised purely for clean hardware — exactly the freedom NVIDIA exercises every generation, and exactly what we will do.
Every window on your screen is being drawn by the same GPU that is running your compute kernel — so who referees? The driver, again. It maintains separate command queues and separate GPU page tables per process (your kernel cannot read the game's textures), and the hardware time-slices between queues or, on datacentre parts, partitions the chip outright. The pattern rhymes with how an OS virtualises a CPU — contexts, address spaces, preemption — except the "OS" lives in a vendor binary on the host, which is also why a GPU driver bug can take down the whole display, and why driver updates fix performance: the operating system of your GPU shipped on a Tuesday.
The classic GPU-benchmarking embarrassment: time the first kernel launch, publish the number, and discover you measured the JIT compiler, not the GPU. The first time a kernel is launched, the driver may still have to compile PTX to SASS (plus allocate context state and warm caches) — easily tens of milliseconds for a kernel whose steady-state runtime is microseconds: a 1000× error waiting for a conference slide. The discipline is universal: warm up before timing — run the kernel a few times, then time many iterations and average. The same trap, for the same JIT reason, bites JVM and JavaScript benchmarking; on GPUs the compile happens in the driver where nobody thinks to look for it.