#!/usr/bin/env python3 """Find the canary tid that runs the sub_821748F0 worker body and see what it does in its 155ms lifetime (host_ns 1.935s to ~2.09s). The spawn semantic-id is 3bd922fbb385c2c9. """ import json import os from collections import Counter INPUT = "/home/fabi/RE - Project Sylpheed/xenia-canary/build-cross/bin/Windows/Debug/canary-jitter-1.jsonl" OUTDIR = os.path.dirname(os.path.abspath(__file__)) TARGET_HSID = "3bd922fbb385c2c9" # First pass: locate this thread's tid by matching the spawn handle. target_tid = None with open(INPUT, "r") as f: for line in f: if '"thread.create"' in line and TARGET_HSID in line: ev = json.loads(line) if ev.get("payload", {}).get("handle_semantic_id") == TARGET_HSID: child_handle = TARGET_HSID print(f" spawn at host_ns={ev['host_ns']}, entry={ev['payload'].get('entry_pc')}") # The thread's own tid will be in events the thread itself emits. # Look for the FIRST event whose tid is NOT the parent and whose # subsequent guest_pc/handle matches this child handle. break # We need to find tid by looking at next thread.create's tid_event_idx=0 emission. # Simpler: scan events after this point for new tid that emits with this handle. # Canary's convention: each new thread emits its first events under its own tid. # Better approach: find thread.create events with handle_semantic_id=TARGET_HSID, # then find the smallest tid > 6 that emits AFTER that timestamp. T_LO = 1_900_000_000 # 1.9s T_HI = 3_000_000_000 # 3.0s events_by_tid = {} with open(INPUT, "r") as f: for line in f: if '"host_ns":' not in line: continue try: i = line.index('"host_ns":') + len('"host_ns":') j = i while j < len(line) and (line[j].isdigit() or line[j] == '-'): j += 1 host_ns = int(line[i:j]) except (ValueError, IndexError): continue if host_ns < T_LO: continue if host_ns >= T_HI: break try: ev = json.loads(line) except json.JSONDecodeError: continue tid = ev.get("tid") if tid is None: continue events_by_tid.setdefault(tid, []).append(ev) # tid=6 is parent. Look for new tids that emit between 1.935s and 2.1s. print("\n=== tids active in window [1.9..3.0s] ===") for tid, evts in sorted(events_by_tid.items()): if not evts: continue first_ns = evts[0]["host_ns"] last_ns = evts[-1]["host_ns"] print(f" tid={tid}: {len(evts)} events from {first_ns/1e9:.4f}s to {last_ns/1e9:.4f}s") # Find tid that spawns at ~1.935s and ends at ~2.09s. candidate_tid = None for tid, evts in events_by_tid.items(): if tid == 6: continue first_ns = evts[0]["host_ns"] if first_ns < 1_930_000_000 or first_ns > 1_960_000_000: continue # Check exit time. last_ns = evts[-1]["host_ns"] print(f" CANDIDATE tid={tid}: first={first_ns/1e9:.4f}s last={last_ns/1e9:.4f}s events={len(evts)}") candidate_tid = tid if candidate_tid is None: print("\nNo single candidate found.") else: print(f"\n=== Worker tid={candidate_tid} timeline (sub_821748F0 body) ===") evts = events_by_tid[candidate_tid] # All kernel.calls and thread.create. summary = Counter() for ev in evts: if ev["kind"] == "kernel.call": summary[ev["payload"].get("name", "?")] += 1 print(f"Total events: {len(evts)}") print(f"Top kernel.call names:") for n, c in summary.most_common(40): print(f" {c:5d} {n}") # Save full timeline. with open(os.path.join(OUTDIR, f"canary-worker-tid{candidate_tid}-timeline.csv"), "w") as f: f.write("host_ns,tid_event_idx,kind,name,detail\n") for ev in evts: name = ev["payload"].get("name", "") detail = json.dumps(ev["payload"])[:400].replace('"', '""') f.write(f'{ev["host_ns"]},{ev["tid_event_idx"]},{ev["kind"]},{name},"{detail}"\n') print(f"Wrote canary-worker-tid{candidate_tid}-timeline.csv")