126 lines
4.8 KiB
Java
126 lines
4.8 KiB
Java
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<Integer> ancestors;
|
|
|
|
SlowAdapterOptions(int instance, List<Integer> 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<Integer> ancestors;
|
|
|
|
FastAdapterOptions(int instance, List<Integer> 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<Integer> ancestorChain = new ArrayList<>();
|
|
for (int d = 0; d < D - 1; d++) ancestorChain.add(d);
|
|
|
|
// Create A adapters, all using the deepest instance
|
|
List<SlowAdapterOptions> slowAdapters = new ArrayList<>();
|
|
List<FastAdapterOptions> 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");
|
|
}
|
|
}
|