java-topology/defects/jsc/unit/JSCBytecodeBasicBlockTest.java

147 lines
5.1 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package unit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
/**
* JSC-0001: BytecodeBasicBlock::computeImpl() O(B²×T) edge linking.
*
* Models the inner loop in BytecodeBasicBlock.cpp lines 181-193:
* - SlowLinker: for each branch block, scan all B blocks and call
* Vector::contains(jumpTargets) for each — O(B × T) per branch
* - FastLinker: load jump targets into HashSet first — O(B + T) per branch
*
* Compile: javac -d . *.java (from defects/jsc/unit/)
* Run: java -ea unit.JSCBytecodeBasicBlockTest
*/
public class JSCBytecodeBasicBlockTest {
// ---- slow path: Vector<Offset> linear contains --------------------------
static class SlowLinker {
static long opCount;
/**
* @param blockCount total basic blocks (B)
* @param jumpTargets list of target offsets (size T)
* @return number of (block, target) linkage operations found
*/
static int link(int blockCount, List<Integer> jumpTargets) {
int linked = 0;
// Simulate: for (auto& otherBlock : basicBlocks)
for (int blockId = 0; blockId < blockCount; blockId++) {
// Simulate: bytecodeOffsetsJumpedTo.contains(otherBlock.leaderOffset())
for (Integer target : jumpTargets) {
opCount++;
if (target == blockId) {
linked++;
break;
}
}
}
return linked;
}
}
// ---- fast path: HashSet<Offset> O(1) lookup -----------------------------
static class FastLinker {
static long opCount;
static int link(int blockCount, List<Integer> jumpTargets) {
// Build HashSet once: O(T)
HashSet<Integer> targetSet = new HashSet<>(jumpTargets);
opCount += jumpTargets.size(); // insertions
int linked = 0;
// Simulate: for (auto& otherBlock : basicBlocks)
for (int blockId = 0; blockId < blockCount; blockId++) {
opCount++; // one hash lookup
if (targetSet.contains(blockId)) {
linked++;
}
}
return linked;
}
}
// ---- helpers ------------------------------------------------------------
static List<Integer> makeTargets(int blockCount, int T) {
// T evenly-spaced target block offsets
List<Integer> targets = new ArrayList<>(T);
int step = Math.max(1, blockCount / T);
for (int i = 0; i < T && i * step < blockCount; i++)
targets.add(i * step);
return targets;
}
// ---- tests --------------------------------------------------------------
static int passed = 0;
static int total = 0;
static void check(String name, boolean cond) {
total++;
if (cond) {
passed++;
} else {
System.out.println("FAIL: " + name);
}
}
public static void main(String[] args) {
// correctness: both find same number of links
{
int B = 20, T = 4;
List<Integer> targets = makeTargets(B, T);
SlowLinker.opCount = 0;
FastLinker.opCount = 0;
int slowLinks = SlowLinker.link(B, targets);
int fastLinks = FastLinker.link(B, targets);
check("slow and fast agree on link count", slowLinks == fastLinks);
check("linked count == T", slowLinks == T);
}
// op-count scaling
int[] blockCounts = {50, 100, 200, 500};
int[] switchSizes = {10, 50, 200, 500};
System.out.println();
System.out.printf("%-8s %-8s %14s %14s %10s%n",
"B", "T", "slow_ops", "fast_ops", "ratio");
for (int B : blockCounts) {
for (int T : switchSizes) {
if (T > B) continue;
List<Integer> targets = makeTargets(B, T);
SlowLinker.opCount = 0;
FastLinker.opCount = 0;
int slowLinks = SlowLinker.link(B, targets);
int fastLinks = FastLinker.link(B, targets);
check("results agree B=" + B + " T=" + T, slowLinks == fastLinks);
long slow = SlowLinker.opCount;
long fast = FastLinker.opCount;
double ratio = (double) slow / fast;
System.out.printf("%-8d %-8d %14d %14d %10.1f%n",
B, T, slow, fast, ratio);
// slow ops ~ O(B × T), fast ops ~ O(B + T)
// ratio should grow with min(B,T)
int minBT = Math.min(B, T);
check("slow > fast for B=" + B + " T=" + T, slow > fast);
// for large T, ratio should be at least T/4
if (T >= 50) {
check("ratio >= T/4 for T=" + T, ratio >= (double) T / 4);
}
}
}
System.out.println();
System.out.printf("%d/%d PASS%n", passed, total);
if (passed != total) System.exit(1);
}
}