// Fixed local release-server budgets. This is a reproducible Shacraft-only workload, // not a comparison with Minecraft and not a production player-capacity claim. import assert from "node:assert/strict"; import path from "node:path"; import {readFile} from "node:fs/promises"; import { harness, Client, delay, options, root } from "./server-harness.mjs"; const opts = options(); opts.binary ??= path.join(root, "target/release/shacraft-server"); const budgets = { ten_client_rss_bytes: 256 * 1024 * 1024, p95_tick_ms: 50 }; const duration = Number(opts["sample-ms"] || 15000); assert.ok( duration >= 3000 && duration <= 120000, "--sample-ms must be 3000..120000", ); const h = await harness(opts), clients = [], samples = [], phases = []; let reportWritten = false; const percentile = (values, p) => [...values].sort((a, b) => a - b)[ Math.min(values.length - 1, Math.floor((values.length - 1) * p)) ]; function summary(name, list) { const rss = list.map((s) => s.rss_bytes).filter(Number.isFinite), ticks = list.map((s) => s.tick_ms).filter(Number.isFinite); assert.ok( rss.length && ticks.length, "Measured RSS and tick durations are required", ); const last = list.at(-1); return { phase: name, samples: list.length, rss_bytes: { p50: percentile(rss, 0.5), p95: percentile(rss, 0.95), max: Math.max(...rss), }, tick_ms: { p50: percentile(ticks, 0.5), p95: percentile(ticks, 0.95), max: Math.max(...ticks), }, process_high_water_bytes: last.process_high_water_bytes, players: last.players, active_worlds: last.active_worlds, world_count: last.world_count, storage: last.storage, slow_clients_disconnected: last.slow_clients_disconnected, queued_client_bytes: last.queued_client_bytes, }; } async function sample(name, milliseconds = duration) { const list = [], end = Date.now() + milliseconds; while (Date.now() < end) { const m = await h.get("/api/metrics"); const processStatus = await readFile(`/proc/${h.pid}/status`, "utf8"); const highWater = Number(processStatus.match(/^VmHWM:\s+(\d+)/m)?.[1]) * 1024; assert.ok(Number.isFinite(highWater), "Linux process high-water RSS required"); m.process_high_water_bytes = highWater; const s = { phase: name, time: Date.now(), ...m }; samples.push(s); list.push(s); await delay(100); } const result = summary(name, list); phases.push(result); return result; } let mover; async function moving(count, distinct) { const manifest = await h.get("/api/manifest"); for (let i = 0; i < count; i++) { const c = new Client(h.url); clients.push(c); await c.join( manifest, `test_bench_${String(distinct ? i : 0).padStart(3, "0")}`, `Bench${i}`, ); } const started = Date.now(); mover = setInterval(() => { const t = (Date.now() - started) / 1000; for (let i = 0; i < clients.length; i++) clients[i].input({ yaw: (t * 0.75 + (i * Math.PI) / 5) % (Math.PI * 2), pitch: -0.1, forward: 1, strafe: 0, jump: Math.floor(t) % 5 === 0, }); }, 50); await delay(2000); } async function disconnect() { clearInterval(mover); await Promise.all(clients.splice(0).map((c) => c.close())); for (let n = 0; n < 50; n++) { const m = await h.get("/api/metrics"); if (m.players === 0) return; await delay(100); } throw Error("Players did not disconnect within 5 seconds"); } try { let created = 0; for (const count of [1, 10, 100]) { while (created < count) { await h.control("world.create", { world: `test_bench_${String(created).padStart(3, "0")}`, template: "lobby", }); created++; } await delay(1000); const phase = await sample(`idle_${count}_template_forks`, 3000); assert.equal(phase.players, 0); assert.equal(phase.active_worlds, 0); } await moving(10, false); await sample("10_moving_clients_shared_world"); await disconnect(); await moving(10, true); await sample("10_moving_clients_separate_worlds"); await disconnect(); await delay(1500); const idle = await sample("after_disconnect_idle", 3000); assert.equal(idle.players, 0); assert.equal(idle.active_worlds, 0); const active = phases.filter((p) => p.phase.includes("moving_clients")); const budgetResults = { rss_passed: active.every( (p) => p.rss_bytes.max <= budgets.ten_client_rss_bytes && p.process_high_water_bytes <= budgets.ten_client_rss_bytes, ), tick_passed: active.every((p) => p.tick_ms.p95 <= budgets.p95_tick_ms), }; const cacheSamples = samples.map((s) => { const storage = s.storage; return { entries: storage.cache_entries ?? storage.cache?.entries, capacity: storage.cache_capacity_sections ?? storage.cache_capacity ?? storage.cache_sections ?? storage.cache?.capacity, }; }); const recognizedCache = cacheSamples.filter( (s) => Number.isFinite(s.entries) && Number.isFinite(s.capacity), ); const cacheBounded = recognizedCache.length === cacheSamples.length && recognizedCache.every((s) => s.entries <= s.capacity); const passed = budgetResults.rss_passed && budgetResults.tick_passed && cacheBounded; await h.report({ passed, profile: h.binary.includes("/release/") ? "release" : "custom binary; verify optimization separately", binary: h.binary, budgets, budget_results: budgetResults, cache_bounded: cacheBounded, workload: { fork_counts: [1, 10, 100], players: 10, input_hz: 20, sampling_interval_ms: 100, active_sample_ms: duration, template: "lobby", scope: "local seeded map; storage and authoritative movement; not full vanilla mechanics", }, limitations: [ "No comparison with Minecraft or a modded server", "Tick metrics measure server step work, not end-to-end latency", "Process RSS excludes browser clients and operating-system disk cache", "Cache entries remain bounded after disconnect; zero active worlds does not imply zero retained cache", ], phases, samples, }); reportWritten = true; assert.ok( passed, "Predetermined benchmark budget or bounded-cache check failed; inspect report", ); } catch (error) { if (!reportWritten) await h.report({ passed: false, budgets, error: error.stack, server_logs: h.logs(), phases, samples, }); throw error; } finally { await disconnect().catch(() => {}); await h.stop(); }