java-topology/tests/bench/BenchMax.java
russell@unturf.com 0a580b313d 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.
2026-03-26 17:11:57 -04:00

268 lines
11 KiB
Java

package bench;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import java.util.*;
import java.util.function.Consumer;
/**
* BenchMax — extreme-scale benchmarks for the gumyum white paper.
*
* Three defects, pushed to their limits:
*
* 1. javac Tarjan (starWithBackEdges) — V up to 5000
* BEFORE: stack.contains(n) O(V²)
* AFTER: n.active flag O(V+E)
*
* 2. minecraft-0001 DependencySorter (diamond depth) — D up to 18
* BEFORE: isCyclic no visited set O(E^D)
* AFTER: visited set O(E) per call
*
* 3. create-0001 TrackGraph BFS (ArrayList.remove(0)) — V up to 5000
* BEFORE: ArrayList.remove(0) O(V²) BFS
* AFTER: ArrayDeque.poll() O(V+E)
*/
public class BenchMax {
// ── 1. Tarjan — javac-style ───────────────────────────────────────────────
static class TNode {
final int id;
final List<TNode> neighbors = new ArrayList<>();
boolean active = false; // fix flag
TNode(int id) { this.id = id; }
}
static List<TNode> starWithBackEdges(int v) {
List<TNode> nodes = new ArrayList<>();
for (int i = 0; i < v; i++) nodes.add(new TNode(i));
TNode hub = nodes.get(0);
for (int i = 1; i < v; i++) {
hub.neighbors.add(nodes.get(i));
nodes.get(i).neighbors.add(hub); // back edge
}
return nodes;
}
static void tarjanDefective(List<TNode> graph) {
List<TNode> stack = new ArrayList<>();
for (TNode n : graph) {
if (!stack.contains(n)) tarjanDfsDefective(n, stack);
}
}
static void tarjanDfsDefective(TNode n, List<TNode> stack) {
stack.add(n);
for (TNode w : n.neighbors) {
if (stack.contains(w)) continue; // O(n) — defect
tarjanDfsDefective(w, stack);
}
stack.remove(stack.size() - 1);
}
static void tarjanFixed(List<TNode> graph) {
Deque<TNode> stack = new ArrayDeque<>();
for (TNode n : graph) {
if (!n.active) tarjanDfsFixed(n, stack);
}
}
static void tarjanDfsFixed(TNode n, Deque<TNode> stack) {
n.active = true;
stack.push(n);
for (TNode w : n.neighbors) {
if (w.active) continue; // O(1) — fixed
tarjanDfsFixed(w, stack);
}
stack.pop();
n.active = false;
}
// ── 2. DependencySorter — minecraft-0001 ─────────────────────────────────
static Map<String, List<String>> buildDiamond(int depth) {
Map<String, List<String>> deps = new LinkedHashMap<>();
deps.put("base", List.of());
String prevL = "base", prevR = "base";
for (int d = 1; d <= depth; d++) {
String L = "L" + d, R = "R" + d;
deps.put(L, List.of(prevL, prevR));
deps.put(R, List.of(prevL, prevR));
prevL = L; prevR = R;
}
deps.put("root", List.of(prevL, prevR));
return deps;
}
static boolean isCyclicBefore(Multimap<String,String> d, String from, String to) {
Collection<String> deps = d.get(to);
if (deps.contains(from)) return true;
return deps.stream().anyMatch(dep -> isCyclicBefore(d, from, dep));
}
static boolean isCyclicAfter(Multimap<String,String> d, String from, String to, Set<String> vis) {
if (!vis.add(to)) return false;
Collection<String> deps = d.get(to);
if (deps.contains(from)) return true;
return deps.stream().anyMatch(dep -> isCyclicAfter(d, from, dep, vis));
}
static void runDSBefore(Map<String, List<String>> tags) {
HashMultimap<String,String> d = HashMultimap.create();
for (var e : tags.entrySet())
for (String dep : e.getValue())
if (!isCyclicBefore(d, e.getKey(), dep)) d.put(e.getKey(), dep);
}
static void runDSAfter(Map<String, List<String>> tags) {
HashMultimap<String,String> d = HashMultimap.create();
for (var e : tags.entrySet())
for (String dep : e.getValue())
if (!isCyclicAfter(d, e.getKey(), dep, new HashSet<>())) d.put(e.getKey(), dep);
}
// ── 3. TrackGraph BFS — create-0001 ──────────────────────────────────────
// Build a simple chain graph: 0→1→2→...→(v-1) with back edges every 10 nodes
static Map<Integer, List<Integer>> buildRailGraph(int v) {
Map<Integer, List<Integer>> adj = new HashMap<>();
for (int i = 0; i < v; i++) {
adj.put(i, new ArrayList<>());
if (i > 0) { adj.get(i).add(i-1); adj.get(i-1).add(i); }
if (i > 10) { adj.get(i).add(i-10); adj.get(i-10).add(i); }
}
return adj;
}
// BEFORE: ArrayList as BFS frontier — remove(0) is O(n)
static int bfsBefore(Map<Integer, List<Integer>> adj, int start) {
List<Integer> frontier = new ArrayList<>();
Set<Integer> visited = new HashSet<>();
frontier.add(start);
visited.add(start);
int count = 0;
while (!frontier.isEmpty()) {
int cur = frontier.remove(0); // O(n) — defect
count++;
for (int nb : adj.getOrDefault(cur, List.of())) {
if (visited.add(nb)) frontier.add(nb);
}
}
return count;
}
// AFTER: ArrayDeque as BFS frontier — poll() is O(1)
static int bfsAfter(Map<Integer, List<Integer>> adj, int start) {
Deque<Integer> frontier = new ArrayDeque<>();
Set<Integer> visited = new HashSet<>();
frontier.add(start);
visited.add(start);
int count = 0;
while (!frontier.isEmpty()) {
int cur = frontier.poll(); // O(1) — fixed
count++;
for (int nb : adj.getOrDefault(cur, List.of())) {
if (visited.add(nb)) frontier.add(nb);
}
}
return count;
}
// ── Main ─────────────────────────────────────────────────────────────────
static final int WARMUP = 200;
static final int TRIALS = 1000;
public static void main(String[] args) {
System.out.println("╔══════════════════════════════════════════════════════════════╗");
System.out.println("║ BenchMax — gumyum minecraft enterprise ║");
System.out.println("╚══════════════════════════════════════════════════════════════╝");
System.out.println();
// ── Javac Tarjan ─────────────────────────────────────────────────────
System.out.println("── 1. javac Tarjan starWithBackEdges(V) ──────────────────────");
System.out.printf("%-6s %-14s %-14s %-8s%n", "V", "BEFORE ns/op", "AFTER ns/op", "Speedup");
System.out.println("-".repeat(48));
int[] tvSizes = {200, 400, 800, 1600, 3200};
for (int v : tvSizes) {
List<TNode> g = starWithBackEdges(v);
for (int i = 0; i < WARMUP; i++) { tarjanFixed(g); }
// skip large V for before (stack depth)
long beforeNs = -1;
if (v <= 800) {
for (int i = 0; i < WARMUP; i++) tarjanDefective(g);
long t0 = System.nanoTime();
for (int i = 0; i < TRIALS; i++) tarjanDefective(starWithBackEdges(v));
beforeNs = (System.nanoTime() - t0) / TRIALS;
}
long t0 = System.nanoTime();
for (int i = 0; i < TRIALS; i++) tarjanFixed(starWithBackEdges(v));
long afterNs = (System.nanoTime() - t0) / TRIALS;
if (beforeNs >= 0) {
System.out.printf("%-6d %-14d %-14d %.1fx%n", v, beforeNs, afterNs, (double)beforeNs/afterNs);
} else {
System.out.printf("%-6d %-14s %-14d (before too slow)%n", v, "SKIPPED", afterNs);
}
}
// ── Minecraft DependencySorter ────────────────────────────────────────
System.out.println();
System.out.println("── 2. minecraft-0001 DependencySorter diamond depth D ───────");
System.out.printf("%-6s %-8s %-14s %-14s %-8s%n", "Depth", "Tags", "BEFORE ns", "AFTER ns", "Speedup");
System.out.println("-".repeat(60));
int[] depths = {4, 6, 8, 10, 12, 14, 16, 18};
for (int d : depths) {
Map<String, List<String>> tags = buildDiamond(d);
for (int i = 0; i < WARMUP; i++) runDSAfter(tags);
long beforeNs = -1;
if (d <= 14) {
for (int i = 0; i < WARMUP; i++) runDSBefore(tags);
long t0 = System.nanoTime();
for (int i = 0; i < TRIALS; i++) runDSBefore(tags);
beforeNs = (System.nanoTime() - t0) / TRIALS;
}
long t0 = System.nanoTime();
for (int i = 0; i < TRIALS; i++) runDSAfter(tags);
long afterNs = (System.nanoTime() - t0) / TRIALS;
if (beforeNs >= 0) {
System.out.printf("%-6d %-8d %-14d %-14d %.1fx%n",
d, tags.size(), beforeNs, afterNs, (double)beforeNs/afterNs);
} else {
System.out.printf("%-6d %-8d %-14s %-14d (OVERFLOW)%n",
d, tags.size(), "OVERFLOW", afterNs);
}
}
// ── Create TrackGraph BFS ─────────────────────────────────────────────
System.out.println();
System.out.println("── 3. create-0001 TrackGraph BFS V nodes ────────────────────");
System.out.printf("%-6s %-14s %-14s %-8s%n", "V", "BEFORE ns/op", "AFTER ns/op", "Speedup");
System.out.println("-".repeat(48));
int[] bfsSizes = {100, 500, 1000, 2000, 5000};
for (int v : bfsSizes) {
Map<Integer, List<Integer>> adj = buildRailGraph(v);
for (int i = 0; i < WARMUP; i++) { bfsBefore(adj, 0); bfsAfter(adj, 0); }
long t0 = System.nanoTime();
for (int i = 0; i < TRIALS; i++) bfsBefore(adj, 0);
long beforeNs = (System.nanoTime() - t0) / TRIALS;
t0 = System.nanoTime();
for (int i = 0; i < TRIALS; i++) bfsAfter(adj, 0);
long afterNs = (System.nanoTime() - t0) / TRIALS;
System.out.printf("%-6d %-14d %-14d %.1fx%n", v, beforeNs, afterNs, (double)beforeNs/afterNs);
}
System.out.println();
System.out.println("Platform: " + System.getProperty("java.vm.name") +
" " + System.getProperty("java.version"));
}
}