The KVM VM Exit and the VMREAD Cost: Why Nested Virtualization Doubles Your Hypercall Latency

2026-09-05

When a guest VM does something the hypervisor must handle — an I/O port write, a CPUID, an EPT violation, an interrupt injection — the CPU performs a VM exit: it saves guest state into the VMCS (Virtual Machine Control Structure), loads host state, and jumps to the host's exit handler. This is the fundamental tax of hardware virtualization, and it's more expensive than almost any other CPU operation you'll encounter.

A VM exit on modern Intel silicon (Sapphire Rapids, Emerald Rapids) costs roughly 1,000–1,500 cycles just for the transition itself — before your handler runs a single instruction. That's ~400ns at 3.5 GHz. Compare that to a syscall (~50ns via SYSCALL) or a page fault (~200ns). The exit is expensive because the CPU must serialize the pipeline, flush speculative state, swap CR3 (with KPTI, twice), reload segment bases, and update the VPID-tagged TLB entries.

The nasty part is VMREAD/VMWRITE. The VMCS isn't a normal memory structure — it's a CPU-managed opaque blob, and reading a field (like the exit reason, the guest RIP, or the exit qualification) requires the VMREAD instruction, which costs ~40–60 cycles per field. A typical exit handler reads 5–10 VMCS fields, adding another 300–500 cycles before it even dispatches to the specific handler.

Concrete example: Consider a virtio-net guest doing packet I/O. Each packet notification writes to a "kick" MMIO register, causing an EPT violation exit. Measured on bare-metal KVM: ~1.8µs per exit round-trip. Now run that guest inside another KVM guest (nested virtualization). Every L2 exit traps to L1's hypervisor, which itself runs virtualized, so L1's VMREAD instructions each cause an L1→L0 exit. Result: nested exits cost 15–30µs — a 10–15x slowdown. This is why cloud providers charge more for nested virt and why AWS bare-metal instances exist.

The mitigation: Intel added VMCS shadowing, which lets L1 read/write a subset of VMCS fields without exiting to L0. AMD has an equivalent with its Virtual VMCB. Modern KVM also uses enlightened VMCS (a Hyper-V-style shadow copy in guest memory) to batch VMREADs.

Rule of thumb: Budget ~500ns per VM exit on bare-metal, ~5–10µs per nested exit. If your workload does more than ~200,000 exits/sec/vCPU, you're spending 10%+ of CPU on the exit tax alone — time to look at SR-IOV, vhost-user, or PCIe passthrough to eliminate the exits entirely.

You can measure this directly: perf kvm stat live shows exit counts and average handler duration per exit reason. Look for high counts of EPT_VIOLATION, IO_INSTRUCTION, or EXTERNAL_INTERRUPT — those are your optimization targets.

Key Takeaway: Every VM exit costs ~500ns of pure transition overhead plus ~50 cycles per VMCS field read, and nesting multiplies this cost because each L1 VMREAD itself triggers an L0 exit.

All newsletters