Public: anyone can read this; the crew can change it.

forked from trevato/cs

What a room costs, measured before anything is built on it: the world stepped headless in this process, at a ceiling a test holds #346

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`scripts/room.ts` is the bench this issue asked for: it builds a real `createRoom` — ten bodies on de_forge, the shipped policy thinking, the freeze set aside — steps it with `stepRoom` at 64 Hz, and prints milliseconds of CPU per simulated world-second with bots thinking and with every seat driven by input frames instead, the policy's share of the difference, the snapshot in three encodings over…

shipped production is serving it deploy ae07c2d

opened this

scripts/room.ts is the bench this issue asked for: it builds a real createRoom — ten bodies on de_forge, the shipped policy thinking, the freeze set aside — steps it with stepRoom at 64 Hz, and prints milliseconds of CPU per simulated world-second with bots thinking and with every seat driven by input frames instead, the policy's share of the difference, the snapshot in three encodings over 128 real beats of that round, the bytes a member a second at 8/16/32 Hz for each, what each costs this process to encode, and how many rooms one core holds at a stated margin. Nothing about the game changed: no route, no socket, no dependency, and no module the server imports gained a line of code.

Measured on the forge's box (Intel Xeon Gold 6230, 80 shared cores at load ~20, bun 1.3.14), eight-second window, median of seven batches, four runs: a room-second of ten bots thinking is 5.4–8.1 ms, 10–24 ms in the round's dearest single second; the same room with all ten seats held by members and nobody thinking is 2.5–3.0 ms, of which 0.35–0.54 ms is the input frames off the wire — so the ten policies are 60–70% of a thinking room. A snapshot is 514 B packed (764 B widest), 3.8 kB as JSON, 684 B as gzipped JSON, which is 8.2 / 61.4 / 10.9 kB a second a member at 16 Hz; encoding one costs 0.006, 0.019 and 0.066 ms, so gzip buys 170 bytes a beat over the packed frame for ten times its CPU. The answer: a whole room — the step plus ten packed snapshots at 16 Hz — costs 6.4–9.0 ms of CPU a second, so one core holds 55–78 rooms, or 19–45 if every room hits its dearest second at once; ROOM_CAP at 20 is a sixth of a core, a choice about a box that also serves pages rather than a limit the simulation imposed. Excluded, deliberately: the socket — no connection is opened, so the kernel's share of those bytes is in no number here.

The finding is held as a ceiling in src/budget.test.ts, in that file's own idiom: a room-second must cost under 40 ms in this process (the test's own second — the first of a live round — reads 4.6 ms), with a proof beside it that a room-second sixteen times dearer trips it. measure there gained one optional argument so the printed line says whether the ceiling is a slice of a frame or of the second a room has. src/rooms/hub.ts and ROOM_CAP's docstring now cite the measured figures instead of the earlier estimate of "about 5 ms", and the README carries the table, the machine, and both new commands. What I chose not to do: pick an encoding — that is #304's — and fix the per-tick seat Map stepRoom rebuilds, which the bench shows but which is a change to the game.

Worth a look: the table itself (bun run scripts/room.ts), the "dearest second" column, which is the number a deployment should be sized by and is the noisiest reading on a shared box, and scripts/room.test.ts, which asserts the JSON candidate carries the same round the packed one does so the comparison is not flattering the winner.

🤖 Generated with Claude Code

Closes #302

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs