Two VPS hosts can sell identical vCPU counts and differ by several percent on a latency-sensitive workload before you write a line of application code, because of how often the guest kernel wakes a sleeping core. The timer tick, the CONFIG_HZ value baked into the kernel, and whether the build uses NO_HZ_IDLE or NO_HZ_FULL decide how much work an idle vCPU does and how precisely it can sleep. On a hypervisor, those micro-wakeups also translate into VM exits that steal real cycles from the host.
What the tick actually is
A classic kernel programs a local APIC timer to fire CONFIG_HZ times per second. Each interrupt runs scheduler accounting, RCU callbacks, and timekeeping, then returns to idle. At CONFIG_HZ=250 that is 250 interrupts per second per core even with nothing to do; at 1000 it is a thousand. On a 16-vCPU guest that is 16,000 wakeups per second of pure overhead.
Idle cores in a VM are worse than idle cores on bare metal because each tick can trigger a VM exit and a return, which costs on the order of microseconds. Read the counter directly: grep -E 'LOC|RES|CAL' /proc/interrupts before and after a 30 second idle window gives a wakeups-per-second figure you can compare between hosts.
NO_HZ_IDLE versus NO_HZ_FULL
NO_HZ_IDLE stops the periodic tick when a CPU has nothing to run, keeping time through the clocksource on wake. Every general-purpose distribution kernel uses it; it removes most idle overhead automatically. NO_HZ_FULL goes further and removes the tick even while a single task runs, at the cost of per-CPU nohz_full= configuration and reduced accounting precision.
NO_HZ_FULL is for dedicated real-time or DPDK-style pinning, not for shared web hosting. What matters for a VPS is whether the provider’s kernel exposes a sane clocksource and whether /sys/devices/system/clocksource/clocksource0/available_clocksource includes a stable option such as kvm-clock or tsc. A guest falling back to hpet or acpi_pm pays far more per timer read than the tick overhead you are trying to remove.
Measuring idle overhead per host
Boot a clean instance with no services beyond sshd, wait two minutes for boot-time work to settle, then sample for 60 seconds: sar -u 1 60, vmstat 1 60 and the interrupt counters. Record %system, %idle, interrupts per second and context switches per second. A guest with proper tickless behaviour shows nearly zero system time and only a handful of interrupts per second.
Two samples are not enough — collect the same window three times and compare medians. Run the check on a second instance of the same plan to see host-to-host variance, and repeat after 24 hours of uptime, because some providers inject guest agents and monitoring probes that wake cores far more often than a tick ever would.
Thresholds worth acting on
On a quiet 1-vCPU instance, expect under 200 interrupts per second, under 100 context switches per second, and %system under 0.5. Sustained figures several times higher suggest a guest agent polling in a loop, a monitoring daemon with a tight interval, or a host that has disabled tickless idle in its kernel configuration.
For a latency workload, run a small task pinned to an idle core with taskset -c 3 cyclictest -p 50 -i 1000 -n -l 10000. Wakeup latency p99 above 100 µs on an otherwise idle VPS points to tick or VM-exit interference; on bare metal the same test typically stays under 30 µs. That gap is the tax you are paying for virtualisation.
Building the kernel argument for comparison
You cannot change the host’s CONFIG_HZ, but you can compare guests fairly by noting zcat /proc/config.gz | grep -E 'CONFIG_HZ|CONFIG_NO_HZ|CONFIG_HIGH_RES_TIMERS' where the provider ships /proc/config.gz. Many do not, in which case use uname -a plus the distribution default and state your assumption clearly in the report.
Always verify high-resolution timers are active: cat /sys/devices/system/clocksource/clocksource0/current_clocksource and grep hres_active /proc/timer_list. Without hrtimers, tickless idle is effectively off and your measurements describe the distributor’s build, not the provider’s hardware. Correct for that before drawing conclusions about hosts.
Isolating tick cost from neighbour noise
Idle overhead and CPU steal look similar in coarse tools. Separate them with mpstat -P ALL 1 30: uniform system time across cores with no steal is tick overhead, while spikes concentrated on some cores with a rising %steal is the hypervisor. Interrupt counters help too — tick interrupts arrive at a fixed cadence, host interference does not.
For a decisive test, compare perf stat -e cycles,instructions,context-switches -a sleep 30 on an idle instance against a busy one. Cycles per second on the idle guest give you a direct overhead figure in hardware terms, which is the number that matters when you are paying for a vCPU that is supposed to be sleeping.
What to do with the finding
If a provider’s idle overhead is high, you have three options: accept it, pin latency-critical work to a core and reduce the impact of wakeups with isolcpus, or move. For most workloads the practical fix is to remove guest-side pollers, set monitoring intervals above 30 seconds, and use event-driven tooling instead of per-second sampling scripts that themselves generate thousands of wakeups.
Record the idle overhead next to the price in your provider spreadsheet, because a host that costs ten percent less but burns a percent of every core on tick overhead and another on steal is not cheaper. Our VPS comparison table notes kernel and clock-source details per tier, and the plan breakdown explains which configurations are worth benchmarking for low-latency work. Rerun the same measurements after any provider migration.

Leave a Reply
You must be logged in to post a comment.