The virtual clock would run training matches faster than real time by letting the server advance game time as fast as its CPU allows. How much faster depends on one number: how long the server takes for one tick, one pass of its main loop that moves every player, spell and timer forward. This experiment measured it.
The question#
Before the measurement, the estimate rested on an assumption: that a tick costs under a millisecond while one arena match runs. That gave a speed-up of about 3 to 40 times real time. The experiment tested the assumption.
How it was measured#
- The server: a separate copy of the project's game server, built from the same code as the live one and given copies of its databases. The live server was not touched.
- No waiting between ticks. The server normally sleeps between ticks to keep to real time; for the measurement it was set to never sleep, so each tick is pure work.
- A timer in the project's own server module measured the time between the starts of consecutive ticks, in microseconds, and logged a histogram every second.
- The load: the smallest match the tests use, one against one (a Paladin and a Mage, both level 80). Four phases of 10 seconds each: both players waiting outside, the arena's preparation with its gates closed, the fight with the Mage casting a spell at the Paladin about once a second, and waiting again after the match.
- Two runs on the project's one machine (16 CPU cores), which was also hosting the live server at the time, with no tests running on it.
Result#
| Phase | Ticks per second | Average tick | Ticks of 250 µs or more |
|---|---|---|---|
| Waiting outside the arena | about 26,600–27,000 | about 37 µs | 0.04–0.05% |
| Arena, gates closed | about 26,300–27,000 | 37–38 µs | 0.04–0.06% |
| Arena, fighting | about 27,000 | 37 µs | 0.008% |
| Waiting after the match | about 27,200–27,300 | about 37 µs | under 0.01% |
A µs is a millionth of a second. The rare slow ticks (the longest was 111 ms, once) came in the first phases, when players log in and the arena is created, not during the fight. One match with two players added nothing measurable to the average tick.
Confidence: measured, for this setup. Both runs agreed closely.
What it means#
The prediction held by a wide margin: a tick costs about 37 µs on average, far below the 1 ms assumed, and 99.9% of ticks take under 250 µs. If each tick advances the game by 3 to 4 ms, the server alone could run a match about 12 to 100 times faster than real time, most likely about 35 to 90 times. The limit will be the agents' own thinking time and the coordination between them and the server, not the server.
What it doesn't settle#
- Bigger matches. The project's teams play two against two, with pets; this measured one against one with light combat.
- Several arenas at once on the same machine.
- A match with agents playing. This measured the server's work per tick; the first match on the lockstep clock, below, had no agent deciding anything.
- A quiet machine. The live server shared the CPU.
A first match on the lockstep clock#
The lockstep clock has since been built, behind a switch that is off on the server humans play on. On a test copy of the server, with a 4 ms step, a scripted two-against-two practice match with one bot ran with the switch off and then on, one run each:
| Game time from invite to gates | Wall time | Speed | |
|---|---|---|---|
| Switch off | about 60.8 s | about 60.8 s | real time |
| Switch on | about 64.1 s | about 1.2 s | about 52 times |
The later phases ran at about 60 times; the whole test, with logins and commands at real speed, took 3 seconds instead of 63. The timing marks trail each event by several seconds of game time at this speed, so the figures are rough. An earlier run with players idle in the hub and no arena ran 58 to 65 times real time. Confidence: measured once, with no agent playing: it fits the 35 to 90 times estimated above, but the agents' own time isn't in it yet.
A side finding#
Asking the server for its own timing statistics while it ran without sleeping crashed it in about a quarter of runs: its statistics code misreads its records when ticks take less than a millisecond, and then reads memory it shouldn't. This is a bug in AzerothCore, the open-source server the project builds on, and it only appears in this no-sleep mode, not on the live server. The measurement above doesn't use those statistics.