#!/usr/bin/env python3 """Summarize measured callback deltas, not estimated CPU savings.""" import argparse import json import re from pathlib import Path def summarize(paths): groups = {} for path in paths: for line in path.read_text(errors='replace').splitlines(): if 'AID SAMPLE ' not in line or 'missing=1' in line: continue fields = dict(re.findall(r'(\w+)=([^\s\']+)', line)) key = (fields['side'], int(fields['stage']), fields['kind']) groups.setdefault(key, []).append(fields) result = [] for (side, stage, kind), samples in sorted(groups.items()): # Trim both edges: ownership and the phase-label RPC can arrive on different frames. stable = samples[2:-2] if len(stable) < 2: continue first, last = stable[0], stable[-1] row = dict(side=side, stage=stage, kind=kind, samples=len(stable), wall_ms=int(last['wall'])-int(first['wall'])) for field in ('role','owner','master','ownerProxy','remoteProxy','control','agent','controlActive','agentActive','lod'): row[field] = sorted({int(s[field]) for s in stable}) for field in ('perception','bt','utility','groupBT'): values = [int(s[field]) for s in stable] row[field] = dict(first=values[0], last=values[-1], delta=values[-1]-values[0] if min(values)>=0 else None, monotonic=all(a<=b for a,b in zip(values,values[1:]))) result.append(row) return result if __name__ == '__main__': parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('logs', nargs='+', type=Path) args = parser.parse_args() print(json.dumps(summarize(args.logs), indent=2))