import re import sys from collections import defaultdict # ================= BACKEND FIX (IMPORTANT FOR HYPRLAND) ================= import matplotlib try: # Wayland / Hyprland recommended backend matplotlib.use("QtAgg") except Exception: # fallback for headless systems matplotlib.use("Agg") import matplotlib.pyplot as plt # ================= INPUT ================= if len(sys.argv) < 2: print("Usage: python analyze_log.py log.txt") sys.exit(1) logfile = sys.argv[1] # ================= PARSE LOG ================= pattern = re.compile(r"(START|END).*TID=(\d+).*range=\[(\d+),(\d+)\].*time=([\d.]+)") events = defaultdict(dict) with open(logfile) as f: for line in f: m = pattern.search(line) if not m: continue typ, tid, l, r, t = m.groups() key = (tid, int(l), int(r)) events[key][typ] = float(t) # ================= BUILD ROWS ================= rows = [] for (tid, l, r), v in events.items(): if "START" in v and "END" in v: start = v["START"] end = v["END"] duration = end - start rows.append( { "tid": tid, "range": f"[{l},{r}]", "start": start, "end": end, "duration": duration, } ) rows.sort(key=lambda x: x["start"]) if not rows: print("No valid events found") sys.exit(1) # ================= OFFSET ================= t0 = rows[0]["start"] for r in rows: r["offset"] = r["start"] - t0 # ================= PRINT TABLE ================= print("\n## TABLE\n") print("| TID | Range | Start | End | Duration | Offset |") print("|-----|-------|-------|-----|----------|--------|") for r in rows: print( f"| {r['tid']} | {r['range']} | " f"{r['start']:.6f} | {r['end']:.6f} | " f"{r['duration']:.6f} | {r['offset']:.6f} |" ) # ================= PLOT ================= plt.figure(figsize=(10, 6)) for i, r in enumerate(rows): plt.plot([r["offset"], r["offset"] + r["duration"]], [i, i], linewidth=4) plt.xlabel("Time (seconds from start)") plt.ylabel("Tasks") plt.title("Execution Timeline") plt.grid(True) plt.tight_layout() # ================= SAVE (IMPORTANT FOR LAB) ================= plt.savefig("timeline.png", dpi=200) print("\nSaved: timeline.png") # ================= SHOW (HYPRLAND WINDOW) ================= plt.show()