java-topology/defects/webdriverio/bench/bench-webdriverio-0002.py
russell@unturf.com b79fddfb51 browser-automation wave 2: testcafe-0001 + webdriverio-0002
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.
2026-04-22 18:31:53 -04:00

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()