mirror of
https://github.com/vladtrc/iw4L
synced 2026-10-26 10:19:50 -04:00
51 lines
2.2 KiB
Python
51 lines
2.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Subtract engine mark timestamps; shell/log delivery time is never measured."""
|
|
import argparse
|
|
import json
|
|
import re
|
|
from pathlib import Path
|
|
|
|
MARK = re.compile(r"benchmark-mark: pid=(\d+) seq=(\d+) ns=(\d+) label=([A-Za-z0-9_.-]+)(?:\s|$)")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("log", type=Path)
|
|
parser.add_argument("labels", nargs="*", default=["in_menu", "in_hanoi", "in_underpass"])
|
|
parser.add_argument("--json", action="store_true", help="emit machine-readable intervals")
|
|
args = parser.parse_args()
|
|
try:
|
|
marks = [tuple(match.groups()) for match in MARK.finditer(args.log.read_text())]
|
|
if not marks:
|
|
raise ValueError("no engine markers found")
|
|
if len({row[0] for row in marks}) != 1:
|
|
raise ValueError("multiple processes in log; provide one run")
|
|
# stdout and the runtime log may both contain the same event.
|
|
unique = list(dict.fromkeys(marks))
|
|
if any(int(b[1]) <= int(a[1]) or int(b[2]) < int(a[2]) for a, b in zip(unique, unique[1:])):
|
|
raise ValueError("markers are not in monotonic sequence order")
|
|
selected = []
|
|
for label in args.labels:
|
|
matches = [row for row in unique if row[3] == label]
|
|
if len(matches) != 1:
|
|
raise ValueError(f"{label}: expected one marker, found {len(matches)}")
|
|
selected.append(matches[0])
|
|
if len(selected) < 2:
|
|
raise ValueError("at least two labels are required")
|
|
intervals = []
|
|
for start, end in zip(selected, selected[1:]):
|
|
if int(end[1]) <= int(start[1]):
|
|
raise ValueError(f"{end[3]} does not follow {start[3]}")
|
|
intervals.append({"from": start[3], "to": end[3], "elapsed_ns": int(end[2]) - int(start[2])})
|
|
except (OSError, ValueError) as error:
|
|
parser.exit(1, f"bench-marks: {error}\n")
|
|
if args.json:
|
|
print(json.dumps({"pid": int(marks[0][0]), "intervals": intervals}, indent=2))
|
|
else:
|
|
for interval in intervals:
|
|
print(f"{interval['from']} -> {interval['to']}: {interval['elapsed_ns'] / 1e9:.6f} s")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|