Free · MIT licensed · Paper, Spigot, Purpur

How long does your server wait for a CPU?

When the machine under your server is busy, its main thread queues for a core and every tick starts late. Nothing in the console shows that queue. TickWait reads it from the kernel once a second and tells you how long the wait was and what caused it: your plan's CPU limit, your server's own threads, or other work on the same cores.

What it shows

Three numbers your console doesn't have

Every tick, split

On Paper and its forks, each tick is timed and split into CPU work, waiting for a CPU, and the rest — garbage-collection pauses, disk, locks, and on a virtual machine the moments its host took the core away.

Every second, split

Each second the main thread is working, waiting for a core, or neither — idle or blocked. Waiting between ticks doesn't lengthen a tick — it starts the next one late, which is what TPS feels.

Who made it wait

Waiting while the server was throttled is its plan's CPU limit. The rest is shared between the server's own threads and other work on the same cores — other servers, the host — by how much CPU each used.

Calibration · 2026-10-11

What the numbers look like

Test setups on our DEV box — an OVH VPS with 4 vCPUs (Intel Core Processor, Haswell), Ubuntu 24.04, kernel 6.8.0-134-generic, cgroup v2. They show how each cause reads — they are not a ranking of anyone's hosting.

One busy loop in a container pinned to one CPU — the kernel counters TickWait reads

SetupOn a CPUWaiting for oneof which throttled
Alone on its core5,003 ms4 ms0 ms
Sharing the core with another container2,502 ms2,503 ms0 ms
Alone, limited to a quarter of a core1,249 ms3,749 ms3,748 ms

Each row is one 5,000 ms window.

Paper 1.21.11 with 256 villagers on one CPU, running TickWait — its last 60 seconds in each setup

SetupWaitedof wanted timePlan's limitOwn threadsOther workTickTPS
Alone on its core14.2 ms / s4%0%88%12%18.5 ms (work 17.4 ms, waiting 0.7 ms)20.0
Same, with another container busy on that core452 ms / s57%0%12%88%42.0 ms (work 17.6 ms, waiting 23.9 ms)18.6
Same, no neighbour, limited to half a core60.8 ms / s15%67%27%5%19.4 ms (work 15.9 ms, waiting 2.9 ms)20.0
Install

Leave it running through your busy hours

  1. Put the TickWait jar in your server's plugins folder and restart.
  2. After a minute, /tickwait status shows the last 60 seconds.
  3. Keep it running through the hours your players are on. It keeps up to 7 days of per-minute numbers in plugins/TickWait, across restarts.
  4. /tickwait report sums everything. /tickwait share turns it into a link you can post.

Needs the server to run on Linux, under Paper, Spigot, Purpur or another Paper fork. The per-tick split needs a Paper build with tick events (current Paper and its forks); elsewhere — Spigot, old Paper — you get the per-second split. Folia isn't supported yet — it has no single main thread to watch.

Run on, 2026-10-11: Paper 1.21.11 on Java 25 — per-second and per-tick split · Purpur 1.21.11 on Java 25 — per-second and per-tick split · Spigot 1.21.11 on Java 25 — per-second split · Paper 1.8.8 (PaperSpigot build 445) on Java 8 — per-second split.

/tickwait statusThe last 60 seconds and the last hour.
/tickwait reportEverything measured so far — up to 7 days — with the busiest hour.
/tickwait exportSaves exactly what share would upload to plugins/TickWait, sends nothing.
/tickwait shareUploads the report and prints a public link. Asks first.
/tickwait shared · unshare <id>Lists your links; deletes one.
/tickwait host <text> · plan <text>Optional labels shown on a shared report.
/tickwait reset confirmDeletes the measured data and starts over.

All commands need the tickwait.admin permission (operators by default).

Method

What it reads, and how it splits the waiting

/proc/self/task/<main thread>/schedstatHow long the main thread ran on a CPU, and how long it was ready to run but waiting for one. Read once a second, and at the start and end of every tick on Paper.
cgroup cpu.statHow long the server's cgroup was throttled because it had used its CPU allowance for the period.
cgroup cpu.max (v2) · cpu.cfs_quota_us (v1)The CPU limit itself, when the host sets one.
/proc/self/statCPU time of the whole server process — so, of its threads other than the main one.
/proc/statBusy time of the CPUs the server may run on (its affinity list), and the machine's steal time.
Bukkit APITicks and the number of players online, for TPS and the with-players numbers.

Waiting in a second when the cgroup was throttled counts toward the plan's CPU limit, up to how long it was throttled — an upper bound, since the kernel doesn't say which thread each throttled moment held back. What's left is shared between the server's other threads and other work on the cores it may use, in proportion to the CPU time each used in that second. That's a proportion, not a verdict: when both were busy, both get a share.

Time that is neither running nor waiting lands in the per-second "idle or blocked" part and the per-tick "other" part: garbage-collection pauses, disk, locks, interrupts — and, on a virtual machine, moments the hypervisor took the core away (steal), which the guest kernel counts as neither.

What it costs

On Paper, 2 reads of a small kernel file per tick, about 3.1 µs each on our DEV box, plus a sampler thread that used 0.9 ms of CPU a second there.

What it can't tell you

  • Inside a virtual machine, steal is reported for the whole machine, not for the cores your server runs on.
  • Some hosts show a server its own version of /proc/stat (LXCFS). Other work on its cores can't be measured there, so waiting the CPU limit doesn't explain is left unattributed.
  • It reads the CPU limit of the server's own cgroup. A limit set higher up — on the container or VM around it, as some LXC and Proxmox setups do — isn't seen, so that waiting is shared out between the other causes.
  • When a counter is missing, TickWait shows "—" rather than 0.
  • Waiting isn't the only cause of lag. A long tick with little waiting is the server's own work — a profiler such as spark shows where it goes — or, on a virtual machine, steal: check the VM steal figure.
Sharing

What /tickwait share sends

Sent

Per-hour sums of the counters above, player counts included, an hour-of-day profile, the CPU model, CPU count and limit, cgroup version, OS, kernel, Java and server versions, and the host and plan labels if you set them.

Not sent

The server's address, player names, the world, chat. The IP address an upload or a delete comes from is counted, in memory, toward hourly limits — an upload's is also compared with our servers' addresses — and isn't saved with the report.

Who can see it

Anyone with the link. Report pages ask search engines not to index them. /tickwait unshare <id> deletes one; /tickwait export shows the exact upload first.

Our own servers

Measured on TrueTick

TrueTick runs Minecraft servers, so TickWait measures us too. Listed here: reports we measured on our own nodes. Customers' servers run on those nodes as well, so coming from one isn't enough to be listed — we add ours by hand.

None listed yet. Our reports will appear here once we've measured our nodes.

TickWait is made by TrueTick, a Minecraft host. It measures every host the same way, ours included. Its code is MIT-licensed and public, so you can check that. TickWait was written with Claude, Anthropic's AI, and tested on TrueTick's servers.