xref: /aosp_15_r20/external/pytorch/benchmarks/dynamo/parse_logs.py (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1*da0073e9SAndroid Build Coastguard Workerimport csv
2*da0073e9SAndroid Build Coastguard Workerimport os
3*da0073e9SAndroid Build Coastguard Workerimport re
4*da0073e9SAndroid Build Coastguard Workerimport sys
5*da0073e9SAndroid Build Coastguard Worker
6*da0073e9SAndroid Build Coastguard Worker
7*da0073e9SAndroid Build Coastguard Worker# This script takes the logs produced by the benchmark scripts (e.g.,
8*da0073e9SAndroid Build Coastguard Worker# torchbench.py) and parses it into a CSV file that summarizes what
9*da0073e9SAndroid Build Coastguard Worker# is failing and why.  It is kept separate from the benchmark script
10*da0073e9SAndroid Build Coastguard Worker# emitting a more structured output as it is often more convenient
11*da0073e9SAndroid Build Coastguard Worker# to iterate quickly on log files offline instead of having to make
12*da0073e9SAndroid Build Coastguard Worker# a change to the benchmark script and then do a full sweep to see
13*da0073e9SAndroid Build Coastguard Worker# the updates.
14*da0073e9SAndroid Build Coastguard Worker#
15*da0073e9SAndroid Build Coastguard Worker# This script is not very well written, feel free to rewrite it as necessary
16*da0073e9SAndroid Build Coastguard Worker
17*da0073e9SAndroid Build Coastguard Workerassert len(sys.argv) == 2
18*da0073e9SAndroid Build Coastguard Worker
19*da0073e9SAndroid Build Coastguard Workerfull_log = open(sys.argv[1]).read()
20*da0073e9SAndroid Build Coastguard Worker
21*da0073e9SAndroid Build Coastguard Worker# If the log contains a gist URL, extract it so we can include it in the CSV
22*da0073e9SAndroid Build Coastguard Workergist_url = ""
23*da0073e9SAndroid Build Coastguard Workerm = re.search(r"https://gist.github.com/[a-f0-9]+", full_log)
24*da0073e9SAndroid Build Coastguard Workerif m is not None:
25*da0073e9SAndroid Build Coastguard Worker    gist_url = m.group(0)
26*da0073e9SAndroid Build Coastguard Worker
27*da0073e9SAndroid Build Coastguard Worker# Split the log into an entry per benchmark
28*da0073e9SAndroid Build Coastguard Workerentries = re.split(
29*da0073e9SAndroid Build Coastguard Worker    r"(?:cuda (?:train|eval) +([^ ]+)|WARNING:root:([^ ]+) failed to load)", full_log
30*da0073e9SAndroid Build Coastguard Worker)[1:]
31*da0073e9SAndroid Build Coastguard Worker# Entries schema example:
32*da0073e9SAndroid Build Coastguard Worker# `['hf_Bert', None, '
33*da0073e9SAndroid Build Coastguard Worker#  PASS\nTIMING: entire_frame_compile:1.80925 backend_compile:6e-05\nDynamo produced 1 graph(s) covering 367 ops\n']`
34*da0073e9SAndroid Build Coastguard Worker
35*da0073e9SAndroid Build Coastguard Worker
36*da0073e9SAndroid Build Coastguard Workerdef chunker(seq, size):
37*da0073e9SAndroid Build Coastguard Worker    return (seq[pos : pos + size] for pos in range(0, len(seq), size))
38*da0073e9SAndroid Build Coastguard Worker
39*da0073e9SAndroid Build Coastguard Worker
40*da0073e9SAndroid Build Coastguard Workerc = 0
41*da0073e9SAndroid Build Coastguard Workeri = 0
42*da0073e9SAndroid Build Coastguard Worker
43*da0073e9SAndroid Build Coastguard Workerout = csv.DictWriter(
44*da0073e9SAndroid Build Coastguard Worker    sys.stdout,
45*da0073e9SAndroid Build Coastguard Worker    [
46*da0073e9SAndroid Build Coastguard Worker        "bench",
47*da0073e9SAndroid Build Coastguard Worker        "name",
48*da0073e9SAndroid Build Coastguard Worker        "result",
49*da0073e9SAndroid Build Coastguard Worker        "component",
50*da0073e9SAndroid Build Coastguard Worker        "context",
51*da0073e9SAndroid Build Coastguard Worker        "explain",
52*da0073e9SAndroid Build Coastguard Worker        "frame_time",
53*da0073e9SAndroid Build Coastguard Worker        "backend_time",
54*da0073e9SAndroid Build Coastguard Worker        "graph_count",
55*da0073e9SAndroid Build Coastguard Worker        "op_count",
56*da0073e9SAndroid Build Coastguard Worker        "graph_breaks",
57*da0073e9SAndroid Build Coastguard Worker        "unique_graph_breaks",
58*da0073e9SAndroid Build Coastguard Worker    ],
59*da0073e9SAndroid Build Coastguard Worker    dialect="excel",
60*da0073e9SAndroid Build Coastguard Worker)
61*da0073e9SAndroid Build Coastguard Workerout.writeheader()
62*da0073e9SAndroid Build Coastguard Workerout.writerow({"explain": gist_url})
63*da0073e9SAndroid Build Coastguard Worker
64*da0073e9SAndroid Build Coastguard Worker
65*da0073e9SAndroid Build Coastguard Worker# Sometimes backtraces will be in third party code, which results
66*da0073e9SAndroid Build Coastguard Worker# in very long file names.  Delete the absolute path in this case.
67*da0073e9SAndroid Build Coastguard Workerdef normalize_file(f):
68*da0073e9SAndroid Build Coastguard Worker    if "site-packages/" in f:
69*da0073e9SAndroid Build Coastguard Worker        return f.split("site-packages/", 2)[1]
70*da0073e9SAndroid Build Coastguard Worker    else:
71*da0073e9SAndroid Build Coastguard Worker        return os.path.relpath(f)
72*da0073e9SAndroid Build Coastguard Worker
73*da0073e9SAndroid Build Coastguard Worker
74*da0073e9SAndroid Build Coastguard Worker# Assume we run torchbench, huggingface, timm_models in that order
75*da0073e9SAndroid Build Coastguard Worker# (as output doesn't say which suite the benchmark is part of)
76*da0073e9SAndroid Build Coastguard Worker# TODO: make this more robust
77*da0073e9SAndroid Build Coastguard Worker
78*da0073e9SAndroid Build Coastguard Workerbench = "torchbench"
79*da0073e9SAndroid Build Coastguard Worker
80*da0073e9SAndroid Build Coastguard Worker# 3 = 1 + number of matches in the entries split regex
81*da0073e9SAndroid Build Coastguard Workerfor name, name2, log in chunker(entries, 3):
82*da0073e9SAndroid Build Coastguard Worker    if name is None:
83*da0073e9SAndroid Build Coastguard Worker        name = name2
84*da0073e9SAndroid Build Coastguard Worker    if name.startswith("Albert"):
85*da0073e9SAndroid Build Coastguard Worker        bench = "huggingface"
86*da0073e9SAndroid Build Coastguard Worker    elif name.startswith("adv_inc"):
87*da0073e9SAndroid Build Coastguard Worker        bench = "timm_models"
88*da0073e9SAndroid Build Coastguard Worker
89*da0073e9SAndroid Build Coastguard Worker    # Payload that will go into the csv
90*da0073e9SAndroid Build Coastguard Worker    r = "UNKNOWN"
91*da0073e9SAndroid Build Coastguard Worker    explain = ""
92*da0073e9SAndroid Build Coastguard Worker    component = ""
93*da0073e9SAndroid Build Coastguard Worker    context = ""
94*da0073e9SAndroid Build Coastguard Worker
95*da0073e9SAndroid Build Coastguard Worker    if "PASS" in log:
96*da0073e9SAndroid Build Coastguard Worker        r = "PASS"
97*da0073e9SAndroid Build Coastguard Worker    if "TIMEOUT" in log:
98*da0073e9SAndroid Build Coastguard Worker        r = "FAIL TIMEOUT"
99*da0073e9SAndroid Build Coastguard Worker    if "Accuracy failed" in log:
100*da0073e9SAndroid Build Coastguard Worker        r = "FAIL ACCURACY"
101*da0073e9SAndroid Build Coastguard Worker
102*da0073e9SAndroid Build Coastguard Worker    # Attempt to extract out useful information from the traceback
103*da0073e9SAndroid Build Coastguard Worker
104*da0073e9SAndroid Build Coastguard Worker    log = log.split(
105*da0073e9SAndroid Build Coastguard Worker        "The above exception was the direct cause of the following exception"
106*da0073e9SAndroid Build Coastguard Worker    )[0]
107*da0073e9SAndroid Build Coastguard Worker    split = log.split("Traceback (most recent call last)", maxsplit=1)
108*da0073e9SAndroid Build Coastguard Worker    if len(split) == 2:
109*da0073e9SAndroid Build Coastguard Worker        log = split[1]
110*da0073e9SAndroid Build Coastguard Worker    log = log.split("Original traceback:")[0]
111*da0073e9SAndroid Build Coastguard Worker    m = re.search(
112*da0073e9SAndroid Build Coastguard Worker        r'File "([^"]+)", line ([0-9]+), in .+\n +(.+)\n([A-Za-z]+(?:Error|Exception|NotImplementedError): ?.*)',
113*da0073e9SAndroid Build Coastguard Worker        log,
114*da0073e9SAndroid Build Coastguard Worker    )
115*da0073e9SAndroid Build Coastguard Worker
116*da0073e9SAndroid Build Coastguard Worker    if m is not None:
117*da0073e9SAndroid Build Coastguard Worker        r = "FAIL"
118*da0073e9SAndroid Build Coastguard Worker        component = f"{normalize_file(m.group(1))}:{m.group(2)}"
119*da0073e9SAndroid Build Coastguard Worker        context = m.group(3)
120*da0073e9SAndroid Build Coastguard Worker        explain = f"{m.group(4)}"
121*da0073e9SAndroid Build Coastguard Worker    else:
122*da0073e9SAndroid Build Coastguard Worker        m = re.search(
123*da0073e9SAndroid Build Coastguard Worker            r'File "([^"]+)", line ([0-9]+), in .+\n +(.+)\nAssertionError', log
124*da0073e9SAndroid Build Coastguard Worker        )
125*da0073e9SAndroid Build Coastguard Worker        if m is not None:
126*da0073e9SAndroid Build Coastguard Worker            r = "FAIL"
127*da0073e9SAndroid Build Coastguard Worker            component = f"{normalize_file(m.group(1))}:{m.group(2)}"
128*da0073e9SAndroid Build Coastguard Worker            context = m.group(3)
129*da0073e9SAndroid Build Coastguard Worker            explain = "AssertionError"
130*da0073e9SAndroid Build Coastguard Worker
131*da0073e9SAndroid Build Coastguard Worker    # Sometimes, the benchmark will say FAIL without any useful info
132*da0073e9SAndroid Build Coastguard Worker    # See https://github.com/pytorch/torchdynamo/issues/1910
133*da0073e9SAndroid Build Coastguard Worker    if "FAIL" in log:
134*da0073e9SAndroid Build Coastguard Worker        r = "FAIL"
135*da0073e9SAndroid Build Coastguard Worker
136*da0073e9SAndroid Build Coastguard Worker    if r == "UNKNOWN":
137*da0073e9SAndroid Build Coastguard Worker        c += 1
138*da0073e9SAndroid Build Coastguard Worker
139*da0073e9SAndroid Build Coastguard Worker    backend_time = None
140*da0073e9SAndroid Build Coastguard Worker    frame_time = None
141*da0073e9SAndroid Build Coastguard Worker    if "TIMING:" in log:
142*da0073e9SAndroid Build Coastguard Worker        result = re.search("TIMING:(.*)\n", log).group(1)
143*da0073e9SAndroid Build Coastguard Worker        split_str = result.split("backend_compile:")
144*da0073e9SAndroid Build Coastguard Worker        if len(split_str) == 2:
145*da0073e9SAndroid Build Coastguard Worker            backend_time = float(split_str[1])
146*da0073e9SAndroid Build Coastguard Worker            frame_time = float(split_str[0].split("entire_frame_compile:")[1])
147*da0073e9SAndroid Build Coastguard Worker
148*da0073e9SAndroid Build Coastguard Worker    if "STATS:" in log:
149*da0073e9SAndroid Build Coastguard Worker        result = re.search("STATS:(.*)\n", log).group(1)
150*da0073e9SAndroid Build Coastguard Worker        # call_* op count: 970 | FakeTensor.__torch_dispatch__:35285 | ProxyTorchDispatchMode.__torch_dispatch__:13339
151*da0073e9SAndroid Build Coastguard Worker        split_all = result.split("|")
152*da0073e9SAndroid Build Coastguard Worker        # TODO: rewrite this to work with arbitrarily many stats
153*da0073e9SAndroid Build Coastguard Worker
154*da0073e9SAndroid Build Coastguard Worker    graph_count = None
155*da0073e9SAndroid Build Coastguard Worker    op_count = None
156*da0073e9SAndroid Build Coastguard Worker    graph_breaks = None
157*da0073e9SAndroid Build Coastguard Worker    unique_graph_breaks = None
158*da0073e9SAndroid Build Coastguard Worker    if m := re.search(
159*da0073e9SAndroid Build Coastguard Worker        r"Dynamo produced (\d+) graphs covering (\d+) ops with (\d+) graph breaks \((\d+) unique\)",
160*da0073e9SAndroid Build Coastguard Worker        log,
161*da0073e9SAndroid Build Coastguard Worker    ):
162*da0073e9SAndroid Build Coastguard Worker        graph_count = m.group(1)
163*da0073e9SAndroid Build Coastguard Worker        op_count = m.group(2)
164*da0073e9SAndroid Build Coastguard Worker        graph_breaks = m.group(3)
165*da0073e9SAndroid Build Coastguard Worker        unique_graph_breaks = m.group(4)
166*da0073e9SAndroid Build Coastguard Worker
167*da0073e9SAndroid Build Coastguard Worker    # If the context string is too long, don't put it in the CSV.
168*da0073e9SAndroid Build Coastguard Worker    # This is a hack to try to make it more likely that Google Sheets will
169*da0073e9SAndroid Build Coastguard Worker    # offer to split columns
170*da0073e9SAndroid Build Coastguard Worker    if len(context) > 78:
171*da0073e9SAndroid Build Coastguard Worker        context = ""
172*da0073e9SAndroid Build Coastguard Worker
173*da0073e9SAndroid Build Coastguard Worker    # Temporary file names are meaningless, report it's generated code in this
174*da0073e9SAndroid Build Coastguard Worker    # case
175*da0073e9SAndroid Build Coastguard Worker    if "/tmp/" in component:
176*da0073e9SAndroid Build Coastguard Worker        component = "generated code"
177*da0073e9SAndroid Build Coastguard Worker        context = ""
178*da0073e9SAndroid Build Coastguard Worker
179*da0073e9SAndroid Build Coastguard Worker    out.writerow(
180*da0073e9SAndroid Build Coastguard Worker        {
181*da0073e9SAndroid Build Coastguard Worker            "bench": bench,
182*da0073e9SAndroid Build Coastguard Worker            "name": name,
183*da0073e9SAndroid Build Coastguard Worker            "result": r,
184*da0073e9SAndroid Build Coastguard Worker            "component": component,
185*da0073e9SAndroid Build Coastguard Worker            "context": context,
186*da0073e9SAndroid Build Coastguard Worker            "explain": explain,
187*da0073e9SAndroid Build Coastguard Worker            "frame_time": frame_time,
188*da0073e9SAndroid Build Coastguard Worker            "backend_time": backend_time,
189*da0073e9SAndroid Build Coastguard Worker            "graph_count": graph_count,
190*da0073e9SAndroid Build Coastguard Worker            "op_count": op_count,
191*da0073e9SAndroid Build Coastguard Worker            "graph_breaks": graph_breaks,
192*da0073e9SAndroid Build Coastguard Worker            "unique_graph_breaks": unique_graph_breaks,
193*da0073e9SAndroid Build Coastguard Worker        }
194*da0073e9SAndroid Build Coastguard Worker    )
195*da0073e9SAndroid Build Coastguard Worker    i += 1
196*da0073e9SAndroid Build Coastguard Worker
197*da0073e9SAndroid Build Coastguard Workerif c:
198*da0073e9SAndroid Build Coastguard Worker    print(f"failed to classify {c} entries", file=sys.stderr)
199