undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
313
tests/bench/LoadSimBenchmark.java
Normal file
313
tests/bench/LoadSimBenchmark.java
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
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<String, List<String>> buildDiamondTags(int depth, String prefix) {
|
||||
Map<String, List<String>> 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<Map<String, List<String>>> buildModpackTags(int depth, int reps) {
|
||||
List<Map<String, List<String>>> 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<String,String> m, String from, String to) {
|
||||
Collection<String> d = m.get(to);
|
||||
if (d.contains(from)) return true;
|
||||
return d.stream().anyMatch(dep -> isCyclicVanilla(m, from, dep));
|
||||
}
|
||||
static void addDepVanilla(Multimap<String,String> m, String from, String to) {
|
||||
if (!isCyclicVanilla(m, from, to)) m.put(from, to);
|
||||
}
|
||||
static int resolveVanilla(List<Map<String,List<String>>> tagSpaces) {
|
||||
int total = 0;
|
||||
for (Map<String,List<String>> tags : tagSpaces) {
|
||||
HashMultimap<String,String> m = HashMultimap.create();
|
||||
for (Map.Entry<String,List<String>> 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<String,String> m, String from, String to, Set<String> seen) {
|
||||
if (!seen.add(to)) return false;
|
||||
Collection<String> d = m.get(to);
|
||||
if (d.contains(from)) return true;
|
||||
return d.stream().anyMatch(dep -> isCyclicPatched(m, from, dep, seen));
|
||||
}
|
||||
static void addDepPatched(Multimap<String,String> m, String from, String to) {
|
||||
if (!isCyclicPatched(m, from, to, new HashSet<>())) m.put(from, to);
|
||||
}
|
||||
static int resolvePatched(List<Map<String,List<String>>> tagSpaces) {
|
||||
int total = 0;
|
||||
for (Map<String,List<String>> tags : tagSpaces) {
|
||||
HashMultimap<String,String> m = HashMultimap.create();
|
||||
for (Map.Entry<String,List<String>> 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<Integer> wiresToProcess = new ArrayDeque<>();
|
||||
ArrayDeque<Integer> 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<Integer> wiresToProcess = new ArrayDeque<>();
|
||||
ArrayDeque<Integer> wiresToTurnOff = new ArrayDeque<>();
|
||||
Set<Integer> 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<Map<String,List<String>>> 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<Future<?>> 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<Map<String,List<String>>> 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("=================================================================");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue