File size: 4,515 Bytes
795f737
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
"""Reproducible observation/execution microbenchmark; not policy task success."""
import argparse
import json
import platform
import statistics
import threading
from pathlib import Path
from time import perf_counter, process_time
import psutil
from playwright.sync_api import sync_playwright
from .actions import Action, Kind, Decision
from .authority import Authority
from .browser import Browser
from .runtime import Runtime


def quantiles(values):
    ordered = sorted(values)
    return dict(median=statistics.median(values), p95=ordered[min(len(ordered)-1, int(.95*len(ordered)))])


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--output', default='reports/runtime-baseline.json')
    parser.add_argument('--repeats', type=int, default=20)
    parser.add_argument('--path-mode', choices=['traversal', 'naive'], default='traversal')
    args = parser.parse_args()
    process = psutil.Process()
    stop = threading.Event()
    peaks = {'python_rss_bytes': 0, 'process_tree_rss_bytes': 0}
    def sample():
        while not stop.is_set():
            own = process.memory_info().rss
            total = own
            for child in process.children(recursive=True):
                try:
                    total += child.memory_info().rss
                except psutil.Error:
                    pass
            peaks['python_rss_bytes'] = max(peaks['python_rss_bytes'], own)
            peaks['process_tree_rss_bytes'] = max(peaks['process_tree_rss_bytes'], total)
            stop.wait(.01)
    monitor = threading.Thread(target=sample, daemon=True)
    monitor.start()
    rows = []
    try:
        with sync_playwright() as pw:
            with pw.chromium.launch(headless=True) as chromium:
                context = chromium.new_context(viewport={'width':1280, 'height':900})
                browser = Browser(context, path_mode=args.path_mode)
                authority = Authority()
                for size in (40, 200, 2000):
                    browser.page.set_content('<main>' + ''.join(
                        f'<button onclick="this.dataset.activated=1">Record {i}</button>' for i in range(size)) + '</main>')
                    browser.observe()  # Warm up one observation.
                    observations, cpu_times, actions, sizes = [], [], [], []
                    for trial in range(args.repeats):
                        authority.replace(f'Benchmark fixture {trial}')
                        runtime = Runtime(browser, authority, lambda *_: True)
                        start, cpu = perf_counter(), process_time()
                        state = browser.observe()
                        observations.append((perf_counter()-start)*1000)
                        cpu_times.append((process_time()-cpu)*1000)
                        sizes.append(len(json.dumps(state.compact(), ensure_ascii=False).encode()))
                        decision = Decision(authority.ticket(state), Action(Kind.CLICK, ('e0',)))
                        outcome = runtime.execute(decision)
                        if outcome.status != 'ok':
                            raise RuntimeError(outcome.code)
                        actions.append(outcome.wall_ms)
                    rows.append(dict(elements=size, repeats=args.repeats,
                        observation_wall_ms=quantiles(observations),
                        observation_python_cpu_ms=quantiles(cpu_times),
                        validated_click_wall_ms=quantiles(actions),
                        compact_json_bytes=statistics.median(sizes)))
                context.close()
    finally:
        stop.set()
        monitor.join()
    report = dict(benchmark='runtime_microbenchmark_v1', path_mode=args.path_mode, platform=platform.platform(),
                  cpu=platform.processor(), logical_cpus=psutil.cpu_count(),
                  physical_cpus=psutil.cpu_count(logical=False),
                  total_ram_bytes=psutil.virtual_memory().total,
                  memory='10ms sampled peak RSS; sum includes shared pages, not unique memory',
                  cpu_time='Python process only; excludes browser subprocess CPU',
                  policy='test fixture actions, no learned policy', target_vps_validated=False,
                  sampled_peaks=peaks, results=rows)
    path = Path(args.output)
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps(report, indent=2), encoding='utf-8')
    print(json.dumps(report, indent=2))


if __name__ == '__main__':
    main()