java-topology/defects/binutils/unit/BinutilsUniqueSectionAlgorithm.java

129 lines
4.4 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.*;
/**
* Unit test for binutils-0001: ldlang.c unique_section_p O(S×U) linked-list scan.
*
* Models the defect: for each input section, walk the full unique_section_list
* linked list to check membership. Fix: use a HashSet for O(1) lookup.
*/
public class BinutilsUniqueSectionAlgorithm {
// --- SLOW: linked-list membership (models ldlang.c unique_section_p) ---
static class UniqueNode {
String name;
UniqueNode next;
UniqueNode(String n, UniqueNode nxt) { this.name = n; this.next = nxt; }
}
static class SlowResult {
long ops;
int matches;
SlowResult(long ops, int matches) { this.ops = ops; this.matches = matches; }
}
/** O(S*U): for each section scan the full unique_section_list. */
static SlowResult slowUniqueSectionP(List<String> sections, UniqueNode listHead) {
long ops = 0;
int matches = 0;
for (String sec : sections) {
for (UniqueNode n = listHead; n != null; n = n.next) {
ops++;
if (n.name.equals(sec)) {
matches++;
break;
}
}
}
return new SlowResult(ops, matches);
}
// --- FAST: hash set membership ---
static class FastResult {
long ops;
int matches;
FastResult(long ops, int matches) { this.ops = ops; this.matches = matches; }
}
/** O(S): for each section do a hash lookup. */
static FastResult fastUniqueSectionP(List<String> sections, Set<String> uniqueSet) {
long ops = 0;
int matches = 0;
for (String sec : sections) {
ops++;
if (uniqueSet.contains(sec)) {
matches++;
}
}
return new FastResult(ops, matches);
}
// --- Test cases ---
static boolean runTest(String label, int S, int U, int matchFraction) {
// Build unique section list: U entries (patterns like ".text.func_NNN")
List<String> uniqueNames = new ArrayList<>();
for (int i = 0; i < U; i++) {
uniqueNames.add(".text.func_" + i);
}
// Build unique_section_list (linked list, head at end for worst-case scan)
UniqueNode listHead = null;
for (String name : uniqueNames) {
listHead = new UniqueNode(name, listHead);
}
// Build hash set version
Set<String> uniqueSet = new HashSet<>(uniqueNames);
// Build S input sections: every (matchFraction)th section matches a unique name
List<String> sections = new ArrayList<>();
for (int i = 0; i < S; i++) {
if (i % matchFraction == 0) {
// match a unique name (worst case: last in list → full scan)
sections.add(".text.func_" + (i % U));
} else {
// no match → full scan of entire list
sections.add(".rodata.var_" + i);
}
}
SlowResult slow = slowUniqueSectionP(sections, listHead);
FastResult fast = fastUniqueSectionP(sections, uniqueSet);
// Verify correctness
if (slow.matches != fast.matches) {
System.out.printf(" FAIL %s: match count mismatch slow=%d fast=%d%n",
label, slow.matches, fast.matches);
return false;
}
double ratio = (double) slow.ops / fast.ops;
boolean pass = ratio >= 5.0;
System.out.printf(" %s %s: S=%d U=%d | SLOW=%d ops FAST=%d ops ratio=%.1fx%n",
pass ? "PASS" : "FAIL", label, S, U, slow.ops, fast.ops, ratio);
return pass;
}
public static void main(String[] args) {
int pass = 0, total = 0;
// Test 1: S=1000, U=100, every 5th section matches (worst-case non-matching: full list scan)
total++; if (runTest("S=1000,U=100,match=1/5", 1000, 100, 5)) pass++;
// Test 2: S=5000, U=500, mostly non-matching (full list scan per section)
total++; if (runTest("S=5000,U=500,nomatch", 5000, 500, 999)) pass++;
// Test 3: S=2000, U=200, all matching (scan until found, avg U/2 each)
total++; if (runTest("S=2000,U=200,all-match", 2000, 200, 1)) pass++;
// Test 4: S=10000, U=1000 (representative embedded RTOS link)
total++; if (runTest("S=10000,U=1000,embed", 10000, 1000, 7)) pass++;
System.out.printf("%n%d/%d PASS%n", pass, total);
if (pass < total) System.exit(1);
}
}