java-topology/defects/kicad-0003/unit/KicadNetlistUpdaterTest.java
russell@unturf.com 3bf7ed2cec freecad+kicad: 5-MOAD scan; 3 CWE-407 defects, MOAD 0002-0005 CLEAN
freecad-0003: CrossSection::removeDuplicates O(W^2*E) wire dedup via
std::find_if over growing list; fix: hash-keyed seen-set O(W*E log E).
Severity MEDIUM-HIGH, ~200x at W=400 duplicate wires.

freecad-0004: SketchAnalysis::detectMissingEqualityConstraints O(C*M^2)
std::find_if over std::list of equal-line/radius candidates; fix:
unordered_multimap keyed on canonical (GeoId,GeoId) pair, O(C).
Severity MEDIUM-HIGH, ~5x at C=50/M=50, grows with M^2.

kicad-0003: BOARD_NETLIST_UPDATER::testConnectivity calls FindPadByNumber
(O(P) linear scan) for each of N pins per footprint; fix: build
unordered_map<padNumber,PAD*> once per footprint, O(P+N) total.
Severity HIGH, ~19x at P=256 pads, ~512x at P=512 pads.

MOAD-0002/0003/0004/0005: CLEAN for both projects (documented in SCAN-NOTES).
2026-03-31 22:09:45 -04:00

75 lines
2.5 KiB
Java

import java.util.*;
/**
* Java model of KiCad kicad-0003: BOARD_NETLIST_UPDATER::testConnectivity
* FindPadByNumber O(N*P) list scan vs O(N) hash map lookup.
*
* Models: for each component, for each of N pins, call FindPadByNumber which
* does a linear scan over P pads.
*/
public class KicadNetlistUpdaterTest {
// --- Defect: O(N * P) linear scan ----------------------------------------
static int testConnectivityDefect(List<String> pinNames, List<String> padNumbers) {
int errors = 0;
for (String pin : pinNames) {
// FindPadByNumber: O(P) linear scan
boolean found = false;
for (String pad : padNumbers) {
if (pad.equals(pin)) {
found = true;
break;
}
}
if (!found) errors++;
}
return errors;
}
// --- Fix: O(N) hash map lookup -------------------------------------------
static int testConnectivityFixed(List<String> pinNames, List<String> padNumbers) {
// Build pad map once: O(P)
Set<String> padSet = new HashSet<>(padNumbers);
int errors = 0;
for (String pin : pinNames) {
// O(1) lookup
if (!padSet.contains(pin)) errors++;
}
return errors;
}
// --- Benchmark -----------------------------------------------------------
public static void main(String[] args) {
for (int p : new int[]{64, 128, 256, 512}) {
List<String> padNumbers = new ArrayList<>();
List<String> pinNames = new ArrayList<>();
for (int i = 0; i < p; i++) {
padNumbers.add(String.valueOf(i + 1));
pinNames.add(String.valueOf(i + 1));
}
// Add a few unknown pins to trigger the error path
pinNames.add("MISSING_1");
pinNames.add("MISSING_2");
int N = pinNames.size();
long t0 = System.nanoTime();
int errD = testConnectivityDefect(pinNames, padNumbers);
long defectNs = System.nanoTime() - t0;
long t1 = System.nanoTime();
int errF = testConnectivityFixed(pinNames, padNumbers);
long fixedNs = System.nanoTime() - t1;
assert errD == errF : "Error count mismatch";
double ratio = (double) defectNs / Math.max(fixedNs, 1);
System.out.printf("P=%4d defect=%7dns fixed=%7dns ratio=%.1fx%n",
p, defectNs, fixedNs, ratio);
}
System.out.println("PASS");
}
}