Servers & Hosting

How to tell if your VPS is oversold, and measure it yourself

Steal time, disk latency and the vCPU that is not a CPU. Four commands and ten minutes.

Every VPS host oversubscribes; the question is by how much. Steal time, run-queue depth and fsync latency expose it in minutes, and knowing the numbers turns a vague "feels slow" into something you can act on.

Oversubscription is how virtual hosting works. A host with 64 physical cores sells far more than 64 vCPUs, on the correct assumption that no customer uses their allocation continuously. That is not fraud — it is the business model, and it is why a VPS costs what it does.

The question is never whether your provider oversubscribes. It is by how much, and whether you are currently on a machine where the assumption has stopped holding.

What a vCPU actually is

A vCPU is a scheduling entity, not a piece of silicon. It is a thread that the hypervisor runs on a physical core when one is free. When every guest on the host wants CPU simultaneously, the hypervisor queues them — and your workload waits, holding a CPU that it is not being allowed to use.

Linux exposes that wait directly, and almost nobody looks at it.

Steal time: the number that settles the argument

Steal time is the percentage of time your virtual CPU was ready to run but the hypervisor gave the physical core to someone else. It appears as st in top and vmstat.

bash
# the st column, sampled every second
vmstat 1 30

# the same thing in top, on the %Cpu line
top -b -n 1 | head -3

Reading it:

  • 0–1% — normal. Nothing to see.
  • 2–5% — mild contention. Unlikely to be noticeable.
  • 5–10% — a busy host. You are losing meaningful capacity.
  • Above 10% — sustained, this is worth a support ticket or a migration.

The detail that matters: steal time is only visible while you are trying to use the CPU. An idle server shows zero steal regardless of how contended the host is. Measure it under your real load, or generate load deliberately:

bash
# occupy every vCPU for 60 seconds, then read steal
nproc
for i in $(seq 1 $(nproc)); do (timeout 60 sh -c 'while :; do :; done' &) ; done
vmstat 1 60 | awk 'NR>2 {s+=$16; n++} END {printf "mean steal: %.2f%%\n", s/n}'

Run-queue depth: contention steal time misses

Steal time does not capture everything. Check how many processes are waiting to run against how many vCPUs you have:

bash
uptime                 # 1, 5 and 15 minute load averages
nproc                  # vCPUs available
vmstat 1 10            # the r column: processes in the run queue

A load average persistently above your vCPU count means work is queuing. A run queue (r) consistently higher than nproc says the same thing more immediately. If load is high while steal is low, the contention is yours; if both are high, you are sharing a crowded host.

Disk is where oversubscription usually hurts most

CPU contention is the famous one, but storage is more often the thing that makes a server feel broken. Sequential throughput tests — the ones hosts quote — are close to useless here, because almost nothing real is sequential. What matters is latency on a synchronous write, which is what a database does on every commit.

bash
# install first: fio is in every distro's repos

# synchronous 4k writes, the pattern a database commit makes
fio --name=sync-write --ioengine=sync --fdatasync=1 \
    --rw=write --bs=4k --size=256M --runtime=30 --time_based \
    --directory=/var/tmp --output-format=normal | grep -E 'lat \(|IOPS'

Watch the 99th percentile, not the average. A disk averaging 0.3 ms with a p99 of 180 ms will feel erratic in a way the average completely hides, and that pattern is the signature of a shared device under load from someone else.

Run it at several times of day. Noisy-neighbour effects are rarely constant, and a single measurement at 3am proves nothing about 9pm.

Memory: ballooning and the overcommit you cannot see

Hypervisors reclaim memory from guests through a balloon driver. Under host pressure, memory you believe you own can be taken back.

bash
# is a balloon driver present?
lsmod | grep -i balloon
dmesg | grep -i balloon | tail -5

# is the guest swapping despite apparently free memory?
free -h
vmstat 1 10            # si and so columns: swap in, swap out

Non-zero si/so while free reports available memory is a strong hint that the hypervisor, not your workload, is the cause.

Identifying the virtualisation type

How much the above applies depends on what you bought, and the names on sales pages are not reliable.

bash
systemd-detect-virt            # kvm, xen, lxc, openvz, none …
lscpu | grep -i hypervisor
cat /proc/cpuinfo | grep 'model name' | head -1
  • KVM / Xen — full virtualisation. Your kernel is yours; steal time is meaningful and reported honestly.
  • LXC / OpenVZ — containers sharing the host kernel. Cheaper, denser, and your visibility into contention is much worse: /proc may reflect the host rather than your slice, so steal time can read zero on a heavily contended machine.
  • none — bare metal, or a hypervisor hiding itself.

If systemd-detect-virt reports a container type and the provider's page said "VPS", that is worth knowing before you benchmark anything, because the numbers mean different things.

A ten-minute assessment

  1. Identify the platform — systemd-detect-virt.
  2. Load every vCPU for a minute and record mean and peak steal.
  3. Record run-queue depth against nproc under that load.
  4. Measure fsync latency with fio, and note p99 rather than the mean.
  5. Check for swap activity while memory appears free.
  6. Repeat at a different hour. One sample is an anecdote.

Keep the output. A support ticket containing "mean steal 14% over 60 seconds, p99 fsync 210 ms, run queue 9 on 4 vCPUs" gets a different response from one saying the server feels slow — and in many cases the response is a migration to a less loaded host, which is the outcome you actually wanted.

When oversubscription is the right trade

None of this argues for dedicated hardware by default. For workloads that are bursty, idle most of the time, or horizontally scaled, oversubscription is exactly what you want to be paying for — you are buying access to more capacity than you could afford to own, on the understanding that you will not always get it.

It stops being the right trade when your workload is latency-sensitive and continuous: a database serving interactive queries, a game server, anything where the p99 is the number your users feel. Those are the cases where measuring first, and then paying for dedicated cores or bare metal, is the cheaper decision overall.

VPSsteal timevirtualisationhostingperformancebenchmarking

Arslan ud Din Shafiq

Founder and lead editor of LearnCybers. Full-stack engineer with expertise in Linux systems, cybersecurity, cloud infrastructure and web development. Writing about practical technology since 2019.

Related reading

Newsletter

Get smarter about security

Practical guides, tooling notes and the developments actually worth your attention — delivered when there is something worth saying.

No spam. Unsubscribe in one click.