package bench; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; /** * LoadSimBenchmark — simulates concurrent player connections and game-loop ticks * against both VANILLA (unpatched) and PATCHED server algorithms. * * Three simulation axes: * * 1. World load / /reload * N threads each trigger a full tag-graph resolution at modpack depth D. * Models: players queued outside door while server does /reload. * Metric: wall-clock time until all N joins complete. * * 2. TPS under concurrent player load * Game loop runs at 20 TPS target (50 ms budget per tick). * Each tick evaluates redstone contraptions for all connected players. * VANILLA: O(W) wire membership test per evaluation (Deque.contains). * PATCHED: O(1) wire membership test (HashSet companion). * Metric: achieved TPS and tick overrun rate at increasing player counts. * * 3. Join throughput and latency * Measures p50 / p95 / p99 join latency and sustained joins/sec. * * Modpack profile (Create + AE2 + Mekanism + Thermal): * - Tag depth: 12 (diamond inheritance chains across mods) * - Total cross-mod tags: ~800 entries resolved at load time * - Wires per player: uncalibrated — treat §2/§3 as exploratory * * NOTE: §1 (world load) is algorithm-isolation micro-benchmark, not real server wall-clock. * Real server /reload: vanilla 19,255 ms → patched 3,087 ms (6.2×, bench-server.sh). * * §2/§3 (redstone TPS) is EXPLORATORY. minecraft-0003 (ExperimentalRedstoneWireEvaluator) * is confirmed but WIRES_PER_PLAYER is not sourced from real measurements. * Do not cite TPS numbers from §2/§3 as confirmed defect impact. */ public class LoadSimBenchmark { // ── Modpack profile ─────────────────────────────────────────────────────── static final int TAG_DEPTH = 12; static final int TAG_GRAPH_REPS = 20; // 20 independent tag namespaces per modpack // WIRES_PER_PLAYER: exploratory — not sourced from real server measurement. // minecraft-0003 defect is confirmed but this constant determines all TPS numbers. static final int WIRES_PER_PLAYER = 400; static final int TICK_BUDGET_MS = 50; // 20 TPS = 50 ms/tick static final int TICKS_TO_SIMULATE = 200; static final int WARMUP_TICKS = 40; static final int[] PLAYER_COUNTS = {10, 20, 40, 60, 80, 100}; // ── Diamond tag graph ───────────────────────────────────────────────────── static Map> buildDiamondTags(int depth, String prefix) { Map> deps = new LinkedHashMap<>(); deps.put(prefix + "_base", List.of()); String prevLeft = prefix + "_base", prevRight = prefix + "_base"; for (int d = 1; d <= depth; d++) { String left = prefix + "_L" + d; String right = prefix + "_R" + d; deps.put(left, List.of(prevLeft, prevRight)); deps.put(right, List.of(prevLeft, prevRight)); prevLeft = left; prevRight = right; } deps.put(prefix + "_root", List.of(prevLeft, prevRight)); return deps; } /** All tag namespaces merged — simulates a full modpack tag registry. */ static List>> buildModpackTags(int depth, int reps) { List>> all = new ArrayList<>(); for (int i = 0; i < reps; i++) all.add(buildDiamondTags(depth, "ns" + i)); return all; } // ── VANILLA: isCyclic without visited set (O(2^D)) ──────────────────────── static boolean isCyclicVanilla(Multimap m, String from, String to) { Collection d = m.get(to); if (d.contains(from)) return true; return d.stream().anyMatch(dep -> isCyclicVanilla(m, from, dep)); } static void addDepVanilla(Multimap m, String from, String to) { if (!isCyclicVanilla(m, from, to)) m.put(from, to); } static int resolveVanilla(List>> tagSpaces) { int total = 0; for (Map> tags : tagSpaces) { HashMultimap m = HashMultimap.create(); for (Map.Entry> e : tags.entrySet()) for (String dep : e.getValue()) addDepVanilla(m, e.getKey(), dep); total += m.size(); } return total; } // ── PATCHED: isCyclic with visited set (O(V+E)) ─────────────────────────── static boolean isCyclicPatched(Multimap m, String from, String to, Set seen) { if (!seen.add(to)) return false; Collection d = m.get(to); if (d.contains(from)) return true; return d.stream().anyMatch(dep -> isCyclicPatched(m, from, dep, seen)); } static void addDepPatched(Multimap m, String from, String to) { if (!isCyclicPatched(m, from, to, new HashSet<>())) m.put(from, to); } static int resolvePatched(List>> tagSpaces) { int total = 0; for (Map> tags : tagSpaces) { HashMultimap m = HashMultimap.create(); for (Map.Entry> e : tags.entrySet()) for (String dep : e.getValue()) addDepPatched(m, e.getKey(), dep); total += m.size(); } return total; } // ── VANILLA: redstone wire eval — Deque membership O(W) ────────────────── static long tickRedstoneVanilla(int players, int wiresPerPlayer) { long ops = 0; for (int p = 0; p < players; p++) { ArrayDeque wiresToProcess = new ArrayDeque<>(); ArrayDeque wiresToTurnOff = new ArrayDeque<>(); // seed wires for (int w = 0; w < wiresPerPlayer; w++) wiresToProcess.add(w); while (!wiresToProcess.isEmpty()) { int wire = wiresToProcess.poll(); if (!wiresToTurnOff.contains(wire)) { // O(W) — the defect wiresToTurnOff.add(wire); ops++; // propagate to ~3 neighbours if (wire > 0 && !wiresToTurnOff.contains(wire - 1)) wiresToProcess.add(wire - 1); if (wire + 1 < wiresPerPlayer && !wiresToTurnOff.contains(wire + 1)) wiresToProcess.add(wire + 1); } } } return ops; } // ── PATCHED: redstone wire eval — HashSet companion O(1) ───────────────── static long tickRedstonePatched(int players, int wiresPerPlayer) { long ops = 0; for (int p = 0; p < players; p++) { ArrayDeque wiresToProcess = new ArrayDeque<>(); ArrayDeque wiresToTurnOff = new ArrayDeque<>(); Set wiresToTurnOffSet = new HashSet<>(); for (int w = 0; w < wiresPerPlayer; w++) wiresToProcess.add(w); while (!wiresToProcess.isEmpty()) { int wire = wiresToProcess.poll(); if (wiresToTurnOffSet.add(wire)) { // O(1) — the fix wiresToTurnOff.add(wire); ops++; if (wire > 0 && !wiresToTurnOffSet.contains(wire - 1)) wiresToProcess.add(wire - 1); if (wire + 1 < wiresPerPlayer && !wiresToTurnOffSet.contains(wire + 1)) wiresToProcess.add(wire + 1); } } } return ops; } // ── Percentile helper ───────────────────────────────────────────────────── static long pct(long[] sorted, double p) { int i = (int) Math.ceil(p / 100.0 * sorted.length) - 1; return sorted[Math.max(0, Math.min(sorted.length - 1, i))]; } // ── Simulation 1: World load — concurrent joins ─────────────────────────── static void simWorldLoad(int players) throws Exception { List>> modpack = buildModpackTags(TAG_DEPTH, TAG_GRAPH_REPS); ExecutorService pool = Executors.newFixedThreadPool(players); long[] latVanilla = new long[players]; long[] latPatched = new long[players]; CountDownLatch startGate = new CountDownLatch(1); // --- VANILLA --- List> futures = new ArrayList<>(); for (int i = 0; i < players; i++) { final int idx = i; futures.add(pool.submit(() -> { try { startGate.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } long t0 = System.nanoTime(); resolveVanilla(modpack); latVanilla[idx] = System.nanoTime() - t0; })); } long wallStart = System.nanoTime(); startGate.countDown(); for (Future f : futures) f.get(); long vanillaWall = System.nanoTime() - wallStart; // --- PATCHED --- CountDownLatch gate2 = new CountDownLatch(1); futures.clear(); for (int i = 0; i < players; i++) { final int idx = i; futures.add(pool.submit(() -> { try { gate2.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } long t0 = System.nanoTime(); resolvePatched(modpack); latPatched[idx] = System.nanoTime() - t0; })); } long wallStart2 = System.nanoTime(); gate2.countDown(); for (Future f : futures) f.get(); long patchedWall = System.nanoTime() - wallStart2; pool.shutdown(); Arrays.sort(latVanilla); Arrays.sort(latPatched); long vp50 = pct(latVanilla, 50), vp95 = pct(latVanilla, 95), vp99 = pct(latVanilla, 99); long pp50 = pct(latPatched, 50), pp95 = pct(latPatched, 95), pp99 = pct(latPatched, 99); System.out.printf(" %4d players | wall: %6.1f s → %5.3f s (%5.1f×) | p50 %5.0f ms → %4.0f ms | p99 %5.0f ms → %4.0f ms%n", players, vanillaWall / 1e9, patchedWall / 1e9, (double) vanillaWall / patchedWall, vp50 / 1e6, pp50 / 1e6, vp99 / 1e6, pp99 / 1e6); } // ── Simulation 2: TPS stability under load ──────────────────────────────── static void simTPS(int players, boolean patched) { int overruns = 0; long totalTickMs = 0; long worstTickMs = 0; for (int tick = -WARMUP_TICKS; tick < TICKS_TO_SIMULATE; tick++) { long t0 = System.nanoTime(); if (patched) tickRedstonePatched(players, WIRES_PER_PLAYER); else tickRedstoneVanilla(players, WIRES_PER_PLAYER); long tickMs = (System.nanoTime() - t0) / 1_000_000; if (tick >= 0) { totalTickMs += tickMs; if (tickMs > TICK_BUDGET_MS) overruns++; if (tickMs > worstTickMs) worstTickMs = tickMs; } } double avgTickMs = (double) totalTickMs / TICKS_TO_SIMULATE; double achievedTPS = 1000.0 / Math.max(avgTickMs, 1); double overrunPct = 100.0 * overruns / TICKS_TO_SIMULATE; System.out.printf(" %4d players | avg tick %5.1f ms | worst %4d ms | overruns %4.0f%% | TPS ~%.1f%n", players, avgTickMs, worstTickMs, overrunPct, Math.min(20.0, achievedTPS)); } // ── Main ────────────────────────────────────────────────────────────────── public static void main(String[] args) throws Exception { System.out.println("================================================================="); System.out.println(" LoadSimBenchmark — Minecraft Server Load Simulation"); System.out.println("================================================================="); System.out.printf(" Modpack profile: depth-%d diamond tag graph × %d namespaces%n", TAG_DEPTH, TAG_GRAPH_REPS); System.out.printf(" Redstone profile: %d active wires per player base%n", WIRES_PER_PLAYER); System.out.printf(" TPS target: 20 TPS (%d ms/tick budget)%n", TICK_BUDGET_MS); System.out.println(); // ── Section 1: World load ────────────────────────────────────────────── System.out.println("─────────────────────────────────────────────────────────────────"); System.out.println(" §1 World Load / /reload (all players blocked until complete)"); System.out.println("─────────────────────────────────────────────────────────────────"); System.out.printf(" %-12s %-44s %-24s %-20s%n", "Players", "Wall time (VANILLA → PATCHED)", "p50 join latency", "p99 join latency"); System.out.println(" " + "-".repeat(100)); // warmup List>> modpack = buildModpackTags(TAG_DEPTH, TAG_GRAPH_REPS); for (int i = 0; i < 3; i++) { resolveVanilla(modpack); resolvePatched(modpack); } for (int n : PLAYER_COUNTS) simWorldLoad(n); System.out.println(); // ── Section 2: TPS — VANILLA ────────────────────────────────────────── System.out.println("─────────────────────────────────────────────────────────────────"); System.out.println(" §2 Game Loop TPS — VANILLA [EXPLORATORY — wire count uncalibrated]"); System.out.println("─────────────────────────────────────────────────────────────────"); System.out.printf(" %-12s %-22s %-18s %-16s %-12s%n", "Players", "Avg tick ms", "Worst tick ms", "Overrun %", "Achieved TPS"); System.out.println(" " + "-".repeat(80)); for (int n : PLAYER_COUNTS) simTPS(n, false); System.out.println(); // ── Section 3: TPS — PATCHED ────────────────────────────────────────── System.out.println("─────────────────────────────────────────────────────────────────"); System.out.println(" §3 Game Loop TPS — PATCHED [EXPLORATORY — wire count uncalibrated]"); System.out.println("─────────────────────────────────────────────────────────────────"); System.out.printf(" %-12s %-22s %-18s %-16s %-12s%n", "Players", "Avg tick ms", "Worst tick ms", "Overrun %", "Achieved TPS"); System.out.println(" " + "-".repeat(80)); for (int n : PLAYER_COUNTS) simTPS(n, true); System.out.println(); System.out.println("─────────────────────────────────────────────────────────────────"); System.out.println(" §4 Summary"); System.out.println("─────────────────────────────────────────────────────────────────"); System.out.printf(" §1 World load [algorithm isolation]:%n"); System.out.printf(" DependencySorter.isCyclic depth-%d, O(2^D) → O(V+E)%n", TAG_DEPTH); System.out.printf(" Real server baseline: vanilla 19,255 ms → patched 3,087 ms (6.2×)%n"); System.out.printf(" §2/§3 Redstone TPS [exploratory — wire count uncalibrated]:%n"); System.out.printf(" ExperimentalRedstoneWireEvaluator, O(W) → O(1), %d wires/player assumed%n", WIRES_PER_PLAYER); System.out.printf(" minecraft-0003 defect confirmed; TPS numbers require real measurement%n"); System.out.println(" ─────────────────────────────────────────────────────────────"); System.out.println(" Confirmed: DependencySorter fix eliminates exponential world load."); System.out.println(" Exploratory: redstone fix may improve TPS at high wire density."); System.out.println(" Do not cite §2/§3 TPS numbers without a real server calibration."); System.out.println("================================================================="); } }