testcafe-0001: Selector filterNodes (string-filter branch) and expandSelectorResults both dedup via Array.indexOf on growing result arrays. filterNodes: O(N*M) per selector filter. expandSelectorResults: O(N^2 * K^2) worst case when derivatives unique. Fix: Set<Node> keyed by object identity. Bench: 398x at N=2000 filter, 1966x at N=K=150 expand. webdriverio-0002: MSPO aggregator dedups per-test entries via Array.find on growing bucket array. O(N^2) per test bucket, same pattern repeats in unknown-suite merger. Fix: companion Map<bucketKey, Set<selector>> for O(1) dedup. Bench: 493x at N=2000. UNDF IDs: 1290 (testcafe), 1291 (webdriverio-0002). All 17 tests pass.
67 lines
2.1 KiB
Python
67 lines
2.1 KiB
Python
#!/usr/bin/env python3
|
|
# bench-webdriverio-0002.py
|
|
# MSPO aggregator: .find(d => d.selector === data.selector) on growing bucket
|
|
# array per entry (O(N^2)) vs Set<string> of observed selectors (O(N)).
|
|
|
|
import sys
|
|
import time
|
|
|
|
|
|
def bench_defective(n, unique_frac=1.0):
|
|
"""Array.find on growing bucket per entry."""
|
|
# Generate N entries; unique_frac of them have unique selectors
|
|
unique_count = int(n * unique_frac)
|
|
entries = [{"selector": f"sel-{i}", "timestamp": i} for i in range(unique_count)]
|
|
# Fill remaining with dup of last
|
|
entries += [{"selector": entries[-1]["selector"], "timestamp": i} for i in range(unique_count, n)]
|
|
|
|
t0 = time.perf_counter()
|
|
bucket = []
|
|
for data in entries:
|
|
existing = None
|
|
for d in bucket:
|
|
if d["selector"] == data["selector"]:
|
|
existing = d
|
|
break
|
|
if existing is None:
|
|
bucket.append(data)
|
|
return time.perf_counter() - t0
|
|
|
|
|
|
def bench_fixed(n, unique_frac=1.0):
|
|
"""Set<string> of observed selectors."""
|
|
unique_count = int(n * unique_frac)
|
|
entries = [{"selector": f"sel-{i}", "timestamp": i} for i in range(unique_count)]
|
|
entries += [{"selector": entries[-1]["selector"], "timestamp": i} for i in range(unique_count, n)]
|
|
|
|
t0 = time.perf_counter()
|
|
bucket = []
|
|
seen = set()
|
|
for data in entries:
|
|
if data["selector"] not in seen:
|
|
seen.add(data["selector"])
|
|
bucket.append(data)
|
|
return time.perf_counter() - t0
|
|
|
|
|
|
TRIALS = 3
|
|
SIZES = [50, 200, 500, 1000, 2000]
|
|
|
|
|
|
def run():
|
|
lines = []
|
|
header = "=== webdriverio-0002: MSPO aggregator Array.find vs Set<string> ==="
|
|
print(header); lines.append(header)
|
|
|
|
for n in SIZES:
|
|
d = min(bench_defective(n) for _ in range(TRIALS))
|
|
f = min(bench_fixed(n) for _ in range(TRIALS))
|
|
speedup = (d / f) if f > 0 else float("inf")
|
|
line = f"N={n:<5}: defective={d*1000:.3f}ms fixed={f*1000:.3f}ms speedup={speedup:.1f}x"
|
|
print(line); lines.append(line); sys.stdout.flush()
|
|
|
|
return lines
|
|
|
|
|
|
if __name__ == "__main__":
|
|
run()
|