java-topology/defects/lean4/bench/bench-lean4-0006.py
russell@unturf.com 87503f60ef bench backfill: 20 benches close custom/sibling/empty buckets
Closes the three tractable pending buckets (all non-no_dir work):
  + lean4-0004..0007: 4 correctness/race benches (ir_interp DCL, jobreg
    IO.Ref race, g_opts thread-local leakage, process envvar hash).
    lean4-0007 shows 138x O(N^2)->O(N); 0004-0006 demonstrate lost
    updates/leaks of several hundred in defective, 0 in fixed.
  + 0ad-0001..0004: 3 CWE-407 list.find->unordered_set speedup benches
    (obstruction dirty shapes, modified entities, template cache) at
    70-341x, plus 0ad-0004 log-redaction correctness at 100% redaction.
  + activemq-0001..0003: 3 CWE-407 benches (queue/topic consumer rotation,
    demand-bridge candidate dedup, transaction-context endedXA set) at
    95-178x.
  + linux-0001..0008: 8 Python complexity-class models for the kernel
    patches. Coexist with the existing build-and-bench.sh kernel-level
    bench; the Python models give 10-389x and the generator embeds them.
  + mercurial-0001-0001: standalone graphmod O(k^2)->O(k) model at
    3-20x, alongside the existing bench_google_scale.py (which imports
    the real mercurial graphmod).

Progress: 13 -> 33 full coverage. Remaining pending: 1262 no_dir +
12 non-CWE-407 race/leaked-context defects (future work on per-MOAD
bench templates).
2026-04-23 11:48:03 -04:00

113 lines
3.4 KiB
Python

#!/usr/bin/env python3
# bench-lean4-0006.py
# LEAN_THREAD_PTR(g_opts) not reset at task boundaries: pooled thread inherits
# previous task's trace options. Fixed path: reset g_opts to nullptr on task
# finalize. Correctness metric: observed leakage count (task B sees task A's
# options).
import sys
import threading
import queue
import time
def make_pool(n_threads, task_queue, context_fn):
"""Minimal thread-pool. context_fn receives (tid, task) and runs under
whatever thread-local setup context_fn itself establishes."""
def loop(tid):
while True:
task = task_queue.get()
if task is None:
task_queue.task_done()
break
context_fn(tid, task)
task_queue.task_done()
threads = [threading.Thread(target=loop, args=(i,)) for i in range(n_threads)]
for t in threads:
t.start()
return threads
def bench_defective(n_threads, n_tasks):
"""g_opts modelled as a thread-local dict; defective path does NOT clear
g_opts between tasks, so a reused thread keeps the prior task's options.
Count leakages: task T_new observes g_opts_from T_prev."""
g_opts = threading.local()
leakages = [0]
leak_lock = threading.Lock()
tq = queue.Queue()
def run_task(tid, task):
prior = getattr(g_opts, 'payload', None)
if prior is not None and prior != task['tid']:
with leak_lock:
leakages[0] += 1
g_opts.payload = task['tid']
# simulate work
_ = sum(range(50))
# defective: no reset
threads = make_pool(n_threads, tq, run_task)
t0 = time.perf_counter()
for i in range(n_tasks):
tq.put({'tid': f't{i}'})
for _ in threads:
tq.put(None)
for t in threads:
t.join()
elapsed = time.perf_counter() - t0
return elapsed, leakages[0]
def bench_fixed(n_threads, n_tasks):
"""Fixed: task finalizer resets g_opts to None before returning."""
g_opts = threading.local()
leakages = [0]
leak_lock = threading.Lock()
tq = queue.Queue()
def run_task(tid, task):
prior = getattr(g_opts, 'payload', None)
if prior is not None and prior != task['tid']:
with leak_lock:
leakages[0] += 1
g_opts.payload = task['tid']
_ = sum(range(50))
g_opts.payload = None # task finalizer: reset
threads = make_pool(n_threads, tq, run_task)
t0 = time.perf_counter()
for i in range(n_tasks):
tq.put({'tid': f't{i}'})
for _ in threads:
tq.put(None)
for t in threads:
t.join()
elapsed = time.perf_counter() - t0
return elapsed, leakages[0]
TRIALS = 3
def run():
lines = []
header = "=== lean4-0006: kernel/trace g_opts thread-local leakage (correctness) ==="
print(header); lines.append(header)
for n_threads, n_tasks in [(2, 200), (4, 400), (8, 800)]:
def_leaks = []
fix_leaks = []
for _ in range(TRIALS):
_, dl = bench_defective(n_threads, n_tasks)
_, fl = bench_fixed(n_threads, n_tasks)
def_leaks.append(dl); fix_leaks.append(fl)
line = (f"threads={n_threads:<2} tasks={n_tasks:<4}: "
f"defective_leakages(max)={max(def_leaks):>5} "
f"fixed_leakages(max)={max(fix_leaks):>5}")
print(line); lines.append(line); sys.stdout.flush()
return lines
if __name__ == "__main__":
run()