If your problem is CPU time that wobbles (latency spikes, uneven build times, a game server that lags when nothing on your side changed), a VDS with whole physical cores pinned to you usually fixes it, and you don't need bare metal. Buy a dedicated server when you need something a VM can't give you even with pinned cores: all of the machine's RAM, all of its disk IOPS, direct access to hardware, or a licence or compliance rule tied to physical hardware. The way to tell which camp you're in is to measure first, and the commands below are enough to do that.

First, be clear about what each option actually shares

The words get used loosely, so here is the split this article uses:

  • Ordinary VPS: a KVM guest with fair-share vCPUs. Your CPU time comes from physical cores that other tenants also use. You get burst headroom, but under contention you wait.
  • VDS (virtual dedicated server): still a KVM guest, but specific physical cores are reserved for you and never handed to anyone else. Often the guest sees the host's real CPU model, so instruction sets like AVX2 are available. What is still shared on the host: L3 cache, memory bandwidth, disks and the network uplink.
  • Dedicated server: the whole machine, no hypervisor. Nothing is shared except the network beyond your port.

So a VDS removes the biggest source of jitter (waiting for a core) but not every one. A dedicated server removes all of them, at a higher price and usually with slower provisioning.

Step 1: measure whether you're losing CPU time at all

On any Linux VM, the kernel counts steal time: time your vCPU was ready to run but the hypervisor was running something else. That is the number that tells you whether a VDS will help.

Quick look, live:

top # the "st" value in the %Cpu(s) line vmstat 1 10 # the "st" column (steal), once a second for 10 seconds mpstat -P ALL 1 5 # per-core %steal (needs the sysstat package) 

Ignore the first line of vmstat output: it's the average since boot, not the first second.

For a number you can log over a day, read /proc/stat twice and diff it. The first line is cpu user nice system idle iowait irq softirq steal ..., so steal is the 9th field when cpu is field 1:

#!/usr/bin/env bash # steal.sh - percent of CPU time stolen over an interval (default 60 s) INTERVAL=${1:-60} read -r _ u1 n1 s1 i1 w1 q1 sq1 st1 _ < /proc/stat sleep "$INTERVAL" read -r _ u2 n2 s2 i2 w2 q2 sq2 st2 _ < /proc/stat total=$(( (u2+n2+s2+i2+w2+q2+sq2+st2) - (u1+n1+s1+i1+w1+q1+sq1+st1) )) steal=$(( st2 - st1 )) awk -v s="$steal" -v t="$total" -v d="$(date -Is)" 'BEGIN { printf "%s steal: %.2f%%\n", d, (t ? 100*s/t : 0) }' 

The guest and guest_nice columns that follow steal are left out on purpose: the kernel already counts guest time inside user and nice, so adding them would count it twice.

Each line carries a timestamp, so you can line it up with your app's latency graphs later. Run it from cron every few minutes during your busy hours and keep the output, for example:

*/5 * * * * /usr/local/bin/steal.sh 60 >> /var/log/steal.log 

How to read it:

  • Near zero all day: CPU contention isn't your problem. A VDS won't fix your latency; look at queries, I/O or memory instead.
  • Low on average but spiking at the times your app misbehaves: this is the classic case for pinned cores.
  • Consistently several percent or more: you're paying for vCPUs you don't fully get. Pinned cores will help.

On a VDS or a dedicated server, steal should sit at or very near zero. If it doesn't on a VDS, ask your provider why.

Step 2: check what CPU your workload can actually see

Many VPS products expose a generic virtual CPU model so guests can be live-migrated between different hosts. That's sensible, but it can hide instruction sets. (Our companion piece, VPS vs VDS: what fair-share vCPU and reserved cores actually mean, goes through these CPU checks in more detail; the short version is below.)

lscpu | grep -E 'Model name|Hypervisor vendor|Virtualization type|^CPU\(s\)|Thread|L3|NUMA' grep -o -w -E 'avx2|avx512f|sha_ni|aes' /proc/cpuinfo | sort | uniq -c grep -c -w hypervisor /proc/cpuinfo # > 0 inside a VM (unless the provider hides it), 0 on bare metal systemd-detect-virt # "kvm" on a KVM guest, "none" on bare metal 

If Model name shows something like "QEMU Virtual CPU" or "Common KVM processor" and avx2 is missing, software that picks faster code paths at runtime (compression, hashing, some database and media libraries) falls back to slower ones. On a VDS that passes through the host CPU model you'll see the real processor name and its flags. On a dedicated server, lscpu won't print a Hypervisor vendor line at all, and the hypervisor flag is absent from /proc/cpuinfo. The reverse doesn't hold, though: a provider can hide the hypervisor flag from guests, so a missing flag alone doesn't prove you're on bare metal.

The NUMA lines show how many memory nodes the machine has. Large and multi-socket servers often have more than one, and a VM's vCPUs can span nodes. On a multi-node dedicated server, bind a database to one node with numactl --cpunodebind=0 --membind=0 or tune it for NUMA.

One gotcha for CI: if you build with -march=native (or Rust's -C target-cpu=native), the binary targets whatever CPU the runner reports. Build on a host-model VDS and deploy to a generic-model VPS, and you can get Illegal instruction at startup. Pin an explicit target no higher than the oldest machine you deploy to: -march=x86-64-v3 needs AVX2, x86-64-v2 needs SSE4.2 and POPCNT, and plain x86-64 runs anywhere. Note that a generic "QEMU Virtual CPU" is often only baseline x86-64, so even a v2 build can fail there. Check what a host supports with /lib64/ld-linux-x86-64.so.2 --help | grep supported (glibc 2.33 or later, so Ubuntu 24.04, Debian 12 and AlmaLinux 9 all work).

Databases

What a database usually needs, in order: enough RAM for the working set, fast and predictable disk I/O, then steady CPU.

A VDS is enough when the working set fits comfortably in the VM's RAM, your p95/p99 query latency spikes line up with steal spikes, and disk I/O isn't saturated. Check that last one with:

iostat -x -y 1 10 # watch r_await / w_await and aqu-sz on your data disk; -y skips the since-boot report 

iostat is in the sysstat package too (apt install sysstat / dnf install sysstat).

The numbers that matter are the waits (r_await, w_await, in milliseconds) and the queue depth (aqu-sz; older sysstat versions call it avgqu-sz): if both climb at your peak hour while the load is the same, the disk is the bottleneck. Don't read much into %util on NVMe or SSD. Those devices serve many requests in parallel, so they can show close to 100% while still having plenty of headroom; the iostat man page says as much. %util is only a useful saturation hint on spinning disks and other single-queue devices.

For PostgreSQL, a short repeatable load test makes before/after comparisons honest:

createdb testdb pgbench -i -s 50 testdb pgbench -c 16 -j 4 -T 300 -P 10 testdb # -P prints TPS and latency every 10 s 

Watch the spread in the per-interval lines, not just the final TPS. Steady numbers on pinned cores versus jumpy ones on shared vCPUs: that is exactly the difference you're paying for.

Go dedicated when you need more RAM than any VM plan offers, when await and queue depth keep rising at peak (you need all the drives' IOPS to yourself, not a share of a host's storage), when you want your own RAID and filesystem choices on the raw disks, or when your database licence or an auditor cares about physical hardware.

To see how much random I/O you actually get, run a short fio test at peak and again off-peak, then delete the test file:

fio --name=randrw --filename=/var/tmp/fio.test --size=2G --rw=randrw --bs=4k \ --iodepth=32 --direct=1 --runtime=60 --time_based --group_reporting rm /var/tmp/fio.test 

On a shared host, IOPS that vary widely between the two runs point to dedicated.

Game servers

Many game servers are bound by one main thread. Minecraft is the usual example: the world simulation runs on a largely single-threaded tick loop at 20 ticks per second, so each tick has a 50 ms budget. If that thread waits for a core even briefly, players feel it as lag regardless of how many cores the plan lists.

Measure in the game as well as on the OS. On Paper, /mspt shows milliseconds per tick, and the spark profiler shows where tick time goes. If MSPT spikes past 50 at the same moments steal.sh shows steal, pinned cores are the fix. If MSPT is high with zero steal, it's your plugins, view distance or entity counts, and more hardware only delays the problem.

A dedicated server earns its cost for games when you run many instances on one box and want to split cores yourself, or need more RAM and disk than a VM plan gives. For a single community server, a VDS is usually the right step up from a VPS. Put it close to your players, too: pinned cores don't help if every packet crosses the country.

CI runners

For CI, the symptom of shared CPU is variance: the same commit takes 6 minutes on one run and 11 on the next. Measure it before deciding anything.

# run the same build five times and compare wall-clock times (in bash) TIMEFORMAT='%R s' # bash's built-in time: wall-clock seconds, nothing to install for i in 1 2 3 4 5; do make clean >/dev/null time make -j"$(nproc)" >/dev/null done 

hyperfine --warmup 1 --runs 5 --prepare 'make clean' 'make -j$(nproc)' does the same with proper statistics if you have it installed.

A wide spread plus measurable steal points to a VDS. A tight spread that's simply too slow means you need more cores (more pinned cores, or a bigger machine), not "dedicated" as such. Go to bare metal for CI when you need nested virtualization or KVM inside jobs (Android emulators, Firecracker, VM-based tests), direct GPU access, or a scratch disk you can hammer without sharing it.

Decision table

Signal Points to
Steal near zero, still slow Neither yet. Profile the app, queries or I/O first
Steal spikes line up with latency or MSPT spikes VDS
Build-time spread is wide, average is fine VDS
Missing AVX2 or similar flags on a generic vCPU VDS with host CPU model
Working set bigger than the largest VM plan Dedicated
Disk r_await/w_await and queue depth (aqu-sz) rising at peak Dedicated
Need KVM inside the guest, raw disks, IPMI or your own RAID Dedicated
Licence or audit tied to physical hardware Dedicated
Cache- or memory-bandwidth-sensitive work that still varies on a VDS Dedicated

A short checklist before you buy

  1. Log steal time for a few busy days with steal.sh.
  2. Record p95/p99 latency, MSPT or build durations over the same period.
  3. Check lscpu and /proc/cpuinfo flags against what your software uses.
  4. Check iostat -x on your data disk at peak (await and aqu-sz, not just %util).
  5. Work out your real RAM working set.
  6. If only items 1 to 3 show a problem, try a VDS. If 4 or 5 do, look at dedicated.
  7. Re-run the same measurements after the move, so you know whether it worked.

Where we fit

We sell all three options from servers in Mumbai (BOM-1) and Delhi NCR (DEL-1), so here is how they map onto the table above, with prices as listed at the time of writing.

Our VDS plans with pinned physical cores reserve whole cores for one customer and expose the host CPU model; cache, memory bandwidth, disk and network are still shared on the host, and the page says so. VDS 4 (4 cores, 16 GB RAM) is ₹3,576/mo and VDS 8 (8 cores, 32 GB RAM) is ₹6,908/mo, ordered by enquiry for now. Our dedicated servers are single-tenant bare metal with IPMI on every box and an unmetered port. The entry model (8 cores / 16 threads, 32 GB RAM, 2 x 960 GB NVMe) is ₹14,499/mo before tax, and the 64-core model with 128 GB RAM is the one to look at when your working set outgrows a 32 GB VM. If you're choosing between cities, our page on a dedicated server in Mumbai or Delhi NCR compares the two by latency.

Our own advice matches this article: if you haven't measured yet, start on a KVM VPS in Mumbai or Delhi NCR, run steal.sh for a few days, and move to a VDS when steal or uneven run times show up. VPS and VDS are billed by the hour with the bill capped at the monthly price, renew at the price you signed up at, and have no setup fees. Payment is by UPI or bank transfer. One caveat before you test: the 7-day money-back guarantee covers only our Web & cPanel, WordPress and reseller hosting, not VPS, VDS or dedicated servers, and deleting a server doesn't produce a refund or credit, so size it with the measurements above first. All current plans are on the pricing page.

Disclosure: written by the team at Bigdomainhost, an Indian hosting provider. We sell the servers linked above.