cmake-0005: cmQtAutoGen MergeOptions std::find over baseOpts in newOpts loop, O(N*M), 31.5x at N=M=50 cmake-0006: cmVisualStudio10TargetGenerator FinishWritingSource writtenSettings O(S^2), 15.3x at S=30 cmake-0007: cmGeneratorExpressionNode TargetRuntimeDllDirsNode dllDirs O(D^2), 10.3x at D=100 MPD: all 5 MOADs CLEAN; updated CLEAN.md with MOAD-0002 through MOAD-0005 analysis. Unit tests: 3/3 PASS.
130 lines
4.7 KiB
Java
130 lines
4.7 KiB
Java
import java.util.*;
|
|
|
|
/**
|
|
* Unit test for cmake-0007: TargetRuntimeDllDirsNode O(D^2) -> O(D) dedup.
|
|
*
|
|
* Models $<TARGET_RUNTIME_DLL_DIRS:tgt> evaluator: collect unique DLL directories
|
|
* from a list of DLL paths, preserving insertion order.
|
|
*
|
|
* Defect: std::find over growing dllDirs vector = O(D) per entry = O(D^2) total.
|
|
* Fix: parallel unordered_set for membership + vector for order = O(1) per entry.
|
|
*/
|
|
public class DllDirsAlgorithm {
|
|
|
|
static String getFilenamePath(String path) {
|
|
int slash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
|
|
return slash >= 0 ? path.substring(0, slash) : ".";
|
|
}
|
|
|
|
// --- Defective: O(D^2) ---
|
|
static List<String> collectDllDirsDefective(List<String> dlls) {
|
|
List<String> dllDirs = new ArrayList<>();
|
|
for (String dll : dlls) {
|
|
String dir = getFilenamePath(dll);
|
|
if (!dllDirs.contains(dir)) { // O(D) linear scan -- the defect
|
|
dllDirs.add(dir);
|
|
}
|
|
}
|
|
return dllDirs;
|
|
}
|
|
|
|
// --- Fixed: O(D) ---
|
|
static List<String> collectDllDirsFixed(List<String> dlls) {
|
|
List<String> dllDirs = new ArrayList<>();
|
|
Set<String> dllDirsSet = new HashSet<>();
|
|
for (String dll : dlls) {
|
|
String dir = getFilenamePath(dll);
|
|
if (dllDirsSet.add(dir)) { // O(1) hash insert+check
|
|
dllDirs.add(dir);
|
|
}
|
|
}
|
|
return dllDirs;
|
|
}
|
|
|
|
static List<String> makeDlls(int numDirs, int dllsPerDir) {
|
|
List<String> dlls = new ArrayList<>();
|
|
for (int d = 0; d < numDirs; d++) {
|
|
for (int i = 0; i < dllsPerDir; i++) {
|
|
dlls.add("C:/Qt/" + d + "/lib" + i + ".dll");
|
|
}
|
|
}
|
|
return dlls;
|
|
}
|
|
|
|
static void testCorrectness() {
|
|
List<String> dlls = Arrays.asList(
|
|
"C:/Qt/bin/Qt6Core.dll",
|
|
"C:/Qt/bin/Qt6Gui.dll",
|
|
"C:/Boost/lib/boost_system.dll",
|
|
"C:/Qt/bin/Qt6Widgets.dll",
|
|
"C:/Boost/lib/boost_thread.dll"
|
|
);
|
|
|
|
List<String> defect = collectDllDirsDefective(dlls);
|
|
List<String> fixed = collectDllDirsFixed(dlls);
|
|
|
|
if (!defect.equals(fixed)) {
|
|
throw new AssertionError("Results differ: " + defect + " vs " + fixed);
|
|
}
|
|
if (defect.size() != 2) {
|
|
throw new AssertionError("Expected 2 unique dirs, got " + defect.size() + ": " + defect);
|
|
}
|
|
// Order must be preserved (insertion order)
|
|
if (!defect.get(0).equals("C:/Qt/bin") || !defect.get(1).equals("C:/Boost/lib")) {
|
|
throw new AssertionError("Wrong order: " + defect);
|
|
}
|
|
System.out.println("PASS testCorrectness (2 unique dirs, insertion order preserved)");
|
|
}
|
|
|
|
static void testAllUnique() {
|
|
List<String> dlls = Arrays.asList(
|
|
"C:/dir1/a.dll", "C:/dir2/b.dll", "C:/dir3/c.dll"
|
|
);
|
|
List<String> result = collectDllDirsFixed(dlls);
|
|
if (result.size() != 3) throw new AssertionError("Expected 3: " + result);
|
|
System.out.println("PASS testAllUnique");
|
|
}
|
|
|
|
static void testAllSameDir() {
|
|
List<String> dlls = Arrays.asList(
|
|
"C:/Qt/bin/A.dll", "C:/Qt/bin/B.dll", "C:/Qt/bin/C.dll"
|
|
);
|
|
List<String> result = collectDllDirsFixed(dlls);
|
|
if (result.size() != 1) throw new AssertionError("Expected 1: " + result);
|
|
if (!result.get(0).equals("C:/Qt/bin")) throw new AssertionError("Wrong dir: " + result);
|
|
System.out.println("PASS testAllSameDir");
|
|
}
|
|
|
|
static void testBenchmark() {
|
|
int NUM_DIRS = 20;
|
|
int DLLS_PER_DIR = 5; // 100 DLLs total, 20 unique dirs
|
|
List<String> dlls = makeDlls(NUM_DIRS, DLLS_PER_DIR);
|
|
int D = dlls.size();
|
|
|
|
// Count defective ops (linear scans in contains)
|
|
long defectiveOps = 0;
|
|
List<String> seen = new ArrayList<>();
|
|
for (String dll : dlls) {
|
|
String dir = getFilenamePath(dll);
|
|
for (String s : seen) { defectiveOps++; if (s.equals(dir)) break; }
|
|
if (!seen.contains(dir)) seen.add(dir);
|
|
}
|
|
|
|
long fixedOps = D; // one hash lookup per dll
|
|
double ratio = (double) defectiveOps / fixedOps;
|
|
System.out.printf("BENCH dllDirs D=%d dirs=%d: defective=%d ops, fixed=%d ops, ratio=%.1fx%n",
|
|
D, NUM_DIRS, defectiveOps, fixedOps, ratio);
|
|
if (ratio < 2.0) {
|
|
throw new AssertionError("Expected ratio >= 2x, got " + ratio);
|
|
}
|
|
System.out.println("PASS testBenchmark (ratio >= 2x confirmed)");
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
testCorrectness();
|
|
testAllUnique();
|
|
testAllSameDir();
|
|
testBenchmark();
|
|
System.out.println("ALL PASS cmake-0007 DllDirs");
|
|
}
|
|
}
|