java-topology/defects/llvm/unit/LlvmAssumptionCacheTransferTest.java

135 lines
4.7 KiB
Java

package unit;
import java.util.*;
/**
* Unit test for llvm-0005: AssumptionCache::transferAffectedValuesInCache O(N*M) defect.
*
* Models the pattern:
* for (auto &A : src_list) // O(N) iterations
* if (!is_contained(dst_list, A)) // O(M) linear scan — the defect
* dst_list.push_back(A);
*
* Slow path: List.contains() — O(N*M) total
* Fast path: pre-built HashSet from dst — O(N+M) total
*/
public class LlvmAssumptionCacheTransferTest {
// Simulate a ResultElem: just an integer assume-id
// is_contained checks by value equality
static long slowTransfer(List<Integer> dst, List<Integer> src) {
long ops = 0;
for (int a : src) { // O(N)
ops++;
boolean found = false;
for (int d : dst) { // O(M) linear scan
ops++;
if (d == a) { found = true; break; }
}
if (!found) dst.add(a);
}
return ops;
}
static long fastTransfer(List<Integer> dst, List<Integer> src) {
long ops = 0;
// Build set from dst once: O(M)
Set<Integer> dstSet = new HashSet<>(dst);
ops += dst.size(); // building the set
for (int a : src) { // O(N)
ops++;
if (dstSet.add(a)) { // O(1)
dst.add(a);
}
}
return ops;
}
static boolean correctnessCheck(List<Integer> dstInit, List<Integer> src) {
// slow
List<Integer> slowDst = new ArrayList<>(dstInit);
slowTransfer(slowDst, src);
// fast
List<Integer> fastDst = new ArrayList<>(dstInit);
fastTransfer(fastDst, src);
return new HashSet<>(slowDst).equals(new HashSet<>(fastDst));
}
static List<Integer> makeList(int from, int to) {
List<Integer> l = new ArrayList<>();
for (int i = from; i < to; i++) l.add(i);
return l;
}
public static void main(String[] args) {
int pass = 0, total = 0;
// Test 1: no overlap
total++;
if (correctnessCheck(makeList(0, 5), makeList(5, 10))) {
pass++; System.out.println("PASS test1: no overlap");
} else System.out.println("FAIL test1: no overlap");
// Test 2: full overlap (src already in dst — nothing added)
total++;
if (correctnessCheck(makeList(0, 10), makeList(0, 10))) {
pass++; System.out.println("PASS test2: full overlap");
} else System.out.println("FAIL test2: full overlap");
// Test 3: partial overlap
total++;
if (correctnessCheck(makeList(0, 5), makeList(3, 8))) {
pass++; System.out.println("PASS test3: partial overlap");
} else System.out.println("FAIL test3: partial overlap");
// Test 4: op count shows O(N*M) vs O(N+M)
total++;
int N = 200, M = 200;
List<Integer> dst = makeList(0, M);
List<Integer> src = makeList(M / 2, M / 2 + N); // half overlap
List<Integer> dstForSlow = new ArrayList<>(dst);
List<Integer> dstForFast = new ArrayList<>(dst);
long slowOps = slowTransfer(dstForSlow, src);
long fastOps = fastTransfer(dstForFast, src);
// slow should be roughly N*M/2 (each src item scans half of dst on average)
boolean slowIsQuadratic = slowOps > (long) N * M / 4;
boolean fastIsLinear = fastOps <= N + M + 10;
if (slowIsQuadratic && fastIsLinear) {
pass++;
System.out.printf("PASS test4: op count slow=%d O(N*M) fast=%d O(N+M) N=%d M=%d%n",
slowOps, fastOps, N, M);
} else {
System.out.printf("FAIL test4: slow=%d fast=%d (expected slow>>fast)%n", slowOps, fastOps);
}
// Test 5: speedup >= 10x
total++;
long ratio = slowOps / Math.max(fastOps, 1);
if (ratio >= 10) {
pass++;
System.out.printf("PASS test5: speedup %dx (slow=%d fast=%d)%n",
ratio, slowOps, fastOps);
} else {
System.out.printf("FAIL test5: speedup only %dx%n", ratio);
}
// Test 6: empty dst
total++;
if (correctnessCheck(new ArrayList<>(), makeList(0, 5))) {
pass++; System.out.println("PASS test6: empty dst");
} else System.out.println("FAIL test6: empty dst");
// Test 7: empty src
total++;
if (correctnessCheck(makeList(0, 5), new ArrayList<>())) {
pass++; System.out.println("PASS test7: empty src");
} else System.out.println("FAIL test7: empty src");
System.out.printf("%n%d/%d PASS%n", pass, total);
if (pass != total) System.exit(1);
}
}