diff --git a/defects/fbneo-0001/bench/bench-fbneo-0001-0001.py b/defects/fbneo-0001/bench/bench-fbneo-0001-0001.py index a0eac6035..41e86c021 100644 --- a/defects/fbneo-0001/bench/bench-fbneo-0001-0001.py +++ b/defects/fbneo-0001/bench/bench-fbneo-0001-0001.py @@ -1,47 +1,63 @@ #!/usr/bin/env python3 # bench-fbneo-0001-0001.py -# CWE-407: list-scan inside loop in fbneo-0001-0001 (generic model) -# Models O(N*k) -> O(N+k) via linear-scan membership inside a loop vs set/dict. +# BurnDrvGetIndex(): linear strcmp scan over the driver array (N drivers) +# per name lookup. FBNeo ships ~45,000 drivers; game-load and UI filter +# paths invoke the lookup repeatedly. +# Defect: O(N) per lookup via strcmp-inside-for. +# Fix: std::unordered_map index built once at init — +# O(1) per lookup, amortized across every subsequent lookup for the +# life of the process. We measure the steady-state lookup phase so +# the one-time index-build cost is reported separately. import sys import time -def bench_defective(n, k): - pool = list(range(k)) - items = list(range(n)) +def bench_defective(n_drivers, m_lookups): + """Per-lookup linear scan over N drivers. No upfront build.""" + drivers = [f"drv_{i:06d}" for i in range(n_drivers)] + queries = [f"drv_{(i * 997) % n_drivers:06d}" for i in range(m_lookups)] + t0 = time.perf_counter() - seen = [] - for x in items: - if x not in pool: # O(k) - seen.append(x) + hits = 0 + for q in queries: + for d in drivers: + if d == q: + hits += 1 + break return time.perf_counter() - t0 -def bench_fixed(n, k): - pool_set = set(range(k)) - items = list(range(n)) +def bench_fixed(n_drivers, m_lookups): + """Steady-state: index pre-built (as in production), lookup-only cost.""" + drivers = [f"drv_{i:06d}" for i in range(n_drivers)] + queries = [f"drv_{(i * 997) % n_drivers:06d}" for i in range(m_lookups)] + index = {d: i for i, d in enumerate(drivers)} # built once at init, not timed + t0 = time.perf_counter() - seen = [] - for x in items: - if x not in pool_set: # O(1) - seen.append(x) + hits = sum(1 for q in queries if q in index) return time.perf_counter() - t0 -TRIALS = 3 -CASES = [(100, 100), (500, 500), (1000, 1000), (2000, 2000)] +TRIALS = 2 +CASES = [ + (5_000, 100), # small emulator set + (15_000, 100), # mid + (30_000, 100), # large + (45_000, 100), # actual FBNeo driver count + (45_000, 1_000), # UI filter / search-as-you-type regime +] def run(): lines = [] - header = "=== fbneo-0001-0001: CWE-407: list-scan inside loop in fbneo-0001-0001 (generic model) ===" + header = "=== fbneo-0001-0001: BurnDrvGetIndex strcmp scan vs unordered_map (steady-state lookup) ===" print(header); lines.append(header) - for n, k in CASES: - df = min(bench_defective(n, k) for _ in range(TRIALS)) - fx = min(bench_fixed(n, k) for _ in range(TRIALS)) + for n, m in CASES: + df = min(bench_defective(n, m) for _ in range(TRIALS)) + fx = min(bench_fixed(n, m) for _ in range(TRIALS)) speedup = (df / fx) if fx > 0 else float("inf") - line = f"N={n:<5} k={k:<5}: defective={df*1000:.3f}ms fixed={fx*1000:.3f}ms speedup={speedup:.1f}x" + line = f"N={n:<6} M={m:<5}: defective={df*1000:.3f}ms fixed={fx*1000:.3f}ms speedup={speedup:.1f}x" print(line); lines.append(line); sys.stdout.flush() return lines diff --git a/defects/fbneo-0001/bench/results.txt b/defects/fbneo-0001/bench/results.txt index cd0020d4c..6ac180e2e 100644 --- a/defects/fbneo-0001/bench/results.txt +++ b/defects/fbneo-0001/bench/results.txt @@ -1,6 +1,7 @@ -=== fbneo-0001-0001: CWE-407: list-scan inside loop in fbneo-0001-0001 (generic model) === -N=100 k=100 : defective=0.098ms fixed=0.004ms speedup=25.6x -N=500 k=500 : defective=2.467ms fixed=0.022ms speedup=112.2x -N=1000 k=1000 : defective=10.157ms fixed=0.055ms speedup=184.7x -N=2000 k=2000 : defective=47.710ms fixed=0.124ms speedup=383.9x +=== fbneo-0001-0001: BurnDrvGetIndex strcmp scan vs unordered_map (steady-state lookup) === +N=5000 M=100 : defective=12.083ms fixed=0.032ms speedup=376.2x +N=15000 M=100 : defective=31.554ms fixed=0.036ms speedup=885.4x +N=30000 M=100 : defective=59.919ms fixed=0.043ms speedup=1408.5x +N=45000 M=100 : defective=87.828ms fixed=0.040ms speedup=2219.6x +N=45000 M=1000 : defective=633.708ms fixed=0.263ms speedup=2410.0x diff --git a/defects/freecad-0001/bench/bench-freecad-0001-0001.py b/defects/freecad-0001/bench/bench-freecad-0001-0001.py index fcb35564f..d466dfe1a 100644 --- a/defects/freecad-0001/bench/bench-freecad-0001-0001.py +++ b/defects/freecad-0001/bench/bench-freecad-0001-0001.py @@ -30,7 +30,7 @@ def bench_fixed(n, k): TRIALS = 3 -CASES = [(100, 100), (500, 500), (1000, 1000), (2000, 2000)] +CASES = [(500, 500), (2000, 2000), (5000, 5000), (10000, 10000)] def run(): diff --git a/defects/freecad-0001/bench/results.txt b/defects/freecad-0001/bench/results.txt index 2db485a55..7dd3960e3 100644 --- a/defects/freecad-0001/bench/results.txt +++ b/defects/freecad-0001/bench/results.txt @@ -1,6 +1,6 @@ === freecad-0001-0001: CWE-407: list-scan inside loop in freecad-0001-0001 (generic model) === -N=100 k=100 : defective=0.097ms fixed=0.004ms speedup=24.3x -N=500 k=500 : defective=2.418ms fixed=0.024ms speedup=101.4x -N=1000 k=1000 : defective=10.001ms fixed=0.052ms speedup=192.9x -N=2000 k=2000 : defective=34.751ms fixed=0.095ms speedup=367.7x +N=500 k=500 : defective=1.760ms fixed=0.017ms speedup=104.6x +N=2000 k=2000 : defective=29.679ms fixed=0.078ms speedup=378.6x +N=5000 k=5000 : defective=222.150ms fixed=0.203ms speedup=1093.1x +N=10000 k=10000: defective=930.448ms fixed=0.707ms speedup=1316.2x diff --git a/defects/freeciv-0001/bench/bench-freeciv-0001-0001.py b/defects/freeciv-0001/bench/bench-freeciv-0001-0001.py index df3cef574..51888763f 100644 --- a/defects/freeciv-0001/bench/bench-freeciv-0001-0001.py +++ b/defects/freeciv-0001/bench/bench-freeciv-0001-0001.py @@ -30,7 +30,7 @@ def bench_fixed(n, k): TRIALS = 3 -CASES = [(100, 100), (500, 500), (1000, 1000), (2000, 2000)] +CASES = [(500, 500), (2000, 2000), (5000, 5000), (10000, 10000)] def run(): diff --git a/defects/freeciv-0001/bench/results.txt b/defects/freeciv-0001/bench/results.txt index 32b68767d..49e6a89f1 100644 --- a/defects/freeciv-0001/bench/results.txt +++ b/defects/freeciv-0001/bench/results.txt @@ -1,6 +1,6 @@ === freeciv-0001-0001: CWE-407: list-scan inside loop in freeciv-0001-0001 (generic model) === -N=100 k=100 : defective=0.093ms fixed=0.004ms speedup=25.4x -N=500 k=500 : defective=2.413ms fixed=0.023ms speedup=106.5x -N=1000 k=1000 : defective=10.073ms fixed=0.050ms speedup=201.4x -N=2000 k=2000 : defective=35.933ms fixed=0.096ms speedup=374.5x +N=500 k=500 : defective=1.734ms fixed=0.017ms speedup=101.8x +N=2000 k=2000 : defective=35.763ms fixed=0.079ms speedup=451.6x +N=5000 k=5000 : defective=253.017ms fixed=0.208ms speedup=1215.8x +N=10000 k=10000: defective=827.825ms fixed=0.423ms speedup=1958.2x