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 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 sections, Set 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 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 uniqueSet = new HashSet<>(uniqueNames); // Build S input sections: every (matchFraction)th section matches a unique name List 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); } }