135 lines
4.7 KiB
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);
|
|
}
|
|
}
|