TrueTick closes on December 1, 2026. Download your worlds from your server's Backups before then. Moving to another host? BlockByte gives TrueTick customers a discount with the code truetick at blockbyte.host.
Benchmark · 2026-07-25

What a 3:1 CPU oversell costs a Minecraft server

If three servers are each promised a CPU thread and all three get the same one, what happens to the tick? We ran PAPER 1.21.4 pinned to a single logical CPU, once alone and once with three servers sharing it, under a load held identical and verified at three checkpoints. The average tick went from 41.65 ms to 137.28 ms (3.30×), and the server stopped keeping up: 20 TPS alone, 7.3 TPS shared.

Result

The numbers

300 seconds sampled every 5 s, after a 60 s warm-up. A tick has a 50 ms budget: spend more and the server runs below 20 TPS.

ArmMSPT avgp50p95TPS avgTick budget used
1 server on the pinned thread41.65 ms41.3 ms43 ms2083%
3 servers on the same thread137.28 ms136.1 ms151.2 ms7.3275%

Alone, the server spent 83% of its tick budget and still held 20 TPS: busy, but never behind. Sharing the thread three ways, each tick cost 3.30× as much. That is close to the 3× you would predict if three equally loaded servers split one thread evenly, which shows the cost of overselling landing directly on the tick.

Method

Everything needed to run it again

Machine

AMD Ryzen 7 9700X 8-Core Processor
16 logical CPUs · kernel 6.8.0-124-generic
host truetick-na-1 (prod)

Server

PAPER 1.21.4 · heap 3072 MB
seed 888777666 · cpuset 6
itzg/minecraft-server@sha256:ddc48d6eff894f88bdc19728363aab40d8557b1b115ef10657bb07c61728e0c7

Load

2000 villagers per server, radius 48
PersistenceRequired · Invulnerable
time midnight · daylight false · spawning false
randomTickSpeed 3 · maxEntityCramming 0
forceload -112, -112, 112, 112

The harness reads the load from a manifest, and that same manifest is published as raw JSON below. Mobs are summoned persistent so they don't despawn, invulnerable so they don't drown or fall, and the world is pinned to night with spawning off so nothing wanders into the measurement.

Verification

Checking that the load held for the whole run

A benchmark that doesn't check its own load can measure anything. Entity counts were read over RCON on every container at three points: after seeding, after warm-up, and after sampling. A run aborts if any container holds less than half its seeded count.

ContainerAfter seedAfter warm-upAfter sampling
bench-dedicated-1200020002000
bench-oversubscribed-1200020002000
bench-oversubscribed-2200020002000
bench-oversubscribed-3200020002000

All four containers held exactly 2000 through the whole run, so both arms were measuring the same load, and it stayed constant.

What we threw away

Three runs that didn't survive review

These produced clean-looking numbers. They were wrong, and each was caught by checking the measurement instead of the conclusion.

Empty load dressed up as a stress test

The first recipe summoned 300 zombies in a tight ring. They killed each other off (109 of 300 alive after 20 seconds), and the tick cost 1.8 ms of a 50 ms budget. We were measuring an idle server with extra steps.

A quarter of the budget, and double the CPU we meant to give

The fixed zombie recipe still only used ~12 ms of the tick budget, so three servers had nothing to contend over. Worse, pinning cpuset 6,14 handed the containers both SMT threads of one core while their quota stayed at one CPU. That made it a 1.5:1 oversell, not the 3:1 we were claiming to test.

A load that drained away while being measured

Villagers fixed the tick cost, but entity counts fell 49% (dedicated) and 39% (oversubscribed) during sampling. The printed averages described a load that no longer existed, and the two arms were no longer running the same load as each other. Disabling entity cramming didn't stop it; summoning the villagers invulnerable did.

Limits

What this does not show

  • One run, one machine. A single AMD Ryzen 7 9700X 8-Core Processor on PAPER 1.21.4. Different hardware, versions or server software will land somewhere else.
  • The 3:1 arm is ours, not anyone else's. We built the oversell to measure it. This is not a measurement of any other host, and we make no claim about what anyone else sells.
  • --cpus=1 is the bench's choice, not our pricing. Both arms use it so the only variable is how many servers share the thread. Our own servers get a quota by RAM tier, not a flat one CPU, and we don't pin cores at all. See pricing for what a plan includes.
  • Entity load is one kind of load. Mob AI and pathfinding stress the main tick thread; redstone, chunk generation and plugin work stress it differently.
Raw data

The data behind this page

Every sample from the run is in one JSON file: 60 points per container for both arms, plus the full manifest. This page reads the same file.

Download result.json →

Captured 2026-07-25T12:33:58Z · CC BY 4.0. Reuse it and cite this page.