package unit; import java.util.*; /** * wasmtime-0002: AdapterOptions ancestors Vec O(n) scan per trampoline compilation. * * Models the re-entrancy check in trampoline.rs: * slow: ancestors stored as List (Vec), contains() scans linearly O(D) * fast: ancestors stored as HashSet, contains() is O(1) * * Benchmark: D nesting depth, A adapters. * slow: each adapter check = 2 * O(D) scans => A adapters = O(2 * A * D) ops * fast: each adapter check = 2 * O(1) => A adapters = O(2 * A) ops * Speedup = D. */ public class AncestorsLinearScanTest { /** SLOW: Vec-backed ancestor list — O(D) contains */ static class SlowAdapterOptions { final int instance; final List ancestors; SlowAdapterOptions(int instance, List ancestors) { this.instance = instance; this.ancestors = new ArrayList<>(ancestors); } /** Returns ops: linear scan through ancestors for target */ long containsAncestor(int target) { long ops = 0; for (int a : ancestors) { ops++; if (a == target) return ops; } return ops; // not found — full scan } } /** FAST: HashSet-backed ancestor set — O(1) contains */ static class FastAdapterOptions { final int instance; final Set ancestors; FastAdapterOptions(int instance, List ancestorList) { this.instance = instance; this.ancestors = new HashSet<>(ancestorList); } /** Returns ops: hash lookup (modeled as 1 op) */ long containsAncestor(int target) { ancestors.contains(target); return 1; // O(1) hash lookup } } static long bench(boolean slow, int D, int A) { // Build a component tree of depth D: instances 0..D-1 // The full ancestor chain for the deepest instance = [0, 1, ..., D-2] List ancestorChain = new ArrayList<>(); for (int d = 0; d < D - 1; d++) ancestorChain.add(d); // Create A adapters, all using the deepest instance List slowAdapters = new ArrayList<>(); List fastAdapters = new ArrayList<>(); for (int a = 0; a < A; a++) { int liftInstance = D - 1; int lowerInstance = D; // a new/different instance not in chain if (slow) { slowAdapters.add(new SlowAdapterOptions(liftInstance, ancestorChain)); slowAdapters.add(new SlowAdapterOptions(lowerInstance, ancestorChain)); } else { fastAdapters.add(new FastAdapterOptions(liftInstance, ancestorChain)); fastAdapters.add(new FastAdapterOptions(lowerInstance, ancestorChain)); } } // Simulate: for each adapter pair, perform the 2 re-entrancy checks // Each check: lower.ancestors.contains(lift.instance) + lift.ancestors.contains(lower.instance) long totalOps = 0; for (int a = 0; a < A; a++) { int liftInst = D - 1; int lowerInst = D; if (slow) { totalOps += slowAdapters.get(a * 2).containsAncestor(lowerInst); // lower.ancestors.contains(lift) totalOps += slowAdapters.get(a * 2 + 1).containsAncestor(liftInst); // lift.ancestors.contains(lower) } else { totalOps += fastAdapters.get(a * 2).containsAncestor(lowerInst); totalOps += fastAdapters.get(a * 2 + 1).containsAncestor(liftInst); } } return totalOps; } static void test(String name, int D, int A, int minSpeedup) { long sOps = bench(true, D, A); long fOps = bench(false, D, A); double speedup = (double) sOps / fOps; boolean pass = sOps >= fOps * minSpeedup; System.out.printf("%-50s slow=%,d fast=%,d speedup=%.1fx %s%n", name, sOps, fOps, speedup, pass ? "PASS" : "FAIL"); assert pass : String.format( "%s: expected speedup >=%dx, got %.1fx (slow=%d, fast=%d)", name, minSpeedup, speedup, sOps, fOps); } public static void main(String[] args) { System.out.println("wasmtime-0002: Ancestors linear scan"); System.out.println("====================================="); // D=10 nesting, 50 adapters: slow=10x over fast test("D=10 A=50 minSpeedup=5x", 10, 50, 5); // D=50 nesting, 100 adapters test("D=50 A=100 minSpeedup=25x", 50, 100, 25); // D=100 nesting (deep wasm-compose pipelines) test("D=100 A=100 minSpeedup=50x", 100, 100, 50); // D=20 nesting, 200 adapters test("D=20 A=200 minSpeedup=10x", 20, 200, 10); System.out.println("====================================="); System.out.println("ALL PASS"); } }