xref: /aosp_15_r20/external/pytorch/benchmarks/dynamo/runner.py (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1*da0073e9SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*da0073e9SAndroid Build Coastguard Worker
3*da0073e9SAndroid Build Coastguard Worker"""
4*da0073e9SAndroid Build Coastguard WorkerA wrapper over the benchmark infrastructure to generate commonly used commands,
5*da0073e9SAndroid Build Coastguard Workerparse results and generate csv/graphs.
6*da0073e9SAndroid Build Coastguard Worker
7*da0073e9SAndroid Build Coastguard WorkerThe script works on manually written TABLE (see below). We can add more commands
8*da0073e9SAndroid Build Coastguard Workerin the future.
9*da0073e9SAndroid Build Coastguard Worker
10*da0073e9SAndroid Build Coastguard WorkerOne example usage is
11*da0073e9SAndroid Build Coastguard Worker-> python benchmarks/runner.py --suites=torchbench --inference
12*da0073e9SAndroid Build Coastguard WorkerThis command will generate the commands for the default compilers (see DEFAULTS
13*da0073e9SAndroid Build Coastguard Workerbelow) for inference, run them and visualize the logs.
14*da0073e9SAndroid Build Coastguard Worker
15*da0073e9SAndroid Build Coastguard WorkerIf you want to just print the commands, you could use the following command
16*da0073e9SAndroid Build Coastguard Worker-> python benchmarks/runner.py --print-run-commands --suites=torchbench --inference
17*da0073e9SAndroid Build Coastguard Worker
18*da0073e9SAndroid Build Coastguard WorkerSimilarly, if you want to just visualize the already finished logs
19*da0073e9SAndroid Build Coastguard Worker-> python benchmarks/runner.py --visualize-logs --suites=torchbench --inference
20*da0073e9SAndroid Build Coastguard Worker
21*da0073e9SAndroid Build Coastguard WorkerIf you want to test float16
22*da0073e9SAndroid Build Coastguard Worker-> python benchmarks/runner.py --suites=torchbench --inference --dtypes=float16
23*da0073e9SAndroid Build Coastguard Worker
24*da0073e9SAndroid Build Coastguard Worker"""
25*da0073e9SAndroid Build Coastguard Worker
26*da0073e9SAndroid Build Coastguard Workerimport argparse
27*da0073e9SAndroid Build Coastguard Workerimport dataclasses
28*da0073e9SAndroid Build Coastguard Workerimport functools
29*da0073e9SAndroid Build Coastguard Workerimport glob
30*da0073e9SAndroid Build Coastguard Workerimport importlib
31*da0073e9SAndroid Build Coastguard Workerimport io
32*da0073e9SAndroid Build Coastguard Workerimport itertools
33*da0073e9SAndroid Build Coastguard Workerimport logging
34*da0073e9SAndroid Build Coastguard Workerimport os
35*da0073e9SAndroid Build Coastguard Workerimport re
36*da0073e9SAndroid Build Coastguard Workerimport shutil
37*da0073e9SAndroid Build Coastguard Workerimport subprocess
38*da0073e9SAndroid Build Coastguard Workerimport sys
39*da0073e9SAndroid Build Coastguard Workerimport tempfile
40*da0073e9SAndroid Build Coastguard Workerfrom collections import defaultdict
41*da0073e9SAndroid Build Coastguard Workerfrom datetime import datetime, timedelta, timezone
42*da0073e9SAndroid Build Coastguard Workerfrom os.path import abspath, exists
43*da0073e9SAndroid Build Coastguard Workerfrom random import randint
44*da0073e9SAndroid Build Coastguard Worker
45*da0073e9SAndroid Build Coastguard Workerimport matplotlib.pyplot as plt
46*da0073e9SAndroid Build Coastguard Workerimport numpy as np
47*da0073e9SAndroid Build Coastguard Workerimport pandas as pd
48*da0073e9SAndroid Build Coastguard Workerfrom matplotlib import rcParams
49*da0073e9SAndroid Build Coastguard Workerfrom scipy.stats import gmean
50*da0073e9SAndroid Build Coastguard Workerfrom tabulate import tabulate
51*da0073e9SAndroid Build Coastguard Worker
52*da0073e9SAndroid Build Coastguard Workerimport torch
53*da0073e9SAndroid Build Coastguard Workerimport torch._dynamo
54*da0073e9SAndroid Build Coastguard Worker
55*da0073e9SAndroid Build Coastguard Worker
56*da0073e9SAndroid Build Coastguard WorkerrcParams.update({"figure.autolayout": True})
57*da0073e9SAndroid Build Coastguard Workerplt.rc("axes", axisbelow=True)
58*da0073e9SAndroid Build Coastguard Worker
59*da0073e9SAndroid Build Coastguard WorkerDEFAULT_OUTPUT_DIR = "benchmark_logs"
60*da0073e9SAndroid Build Coastguard Worker
61*da0073e9SAndroid Build Coastguard Worker
62*da0073e9SAndroid Build Coastguard Workerlog = logging.getLogger(__name__)
63*da0073e9SAndroid Build Coastguard Worker
64*da0073e9SAndroid Build Coastguard WorkerTABLE = {
65*da0073e9SAndroid Build Coastguard Worker    "training": {
66*da0073e9SAndroid Build Coastguard Worker        "ts_nnc": "--training --speedup-ts ",
67*da0073e9SAndroid Build Coastguard Worker        "ts_nvfuser": "--training --nvfuser --speedup-dynamo-ts ",
68*da0073e9SAndroid Build Coastguard Worker        "eager": "--training --backend=eager ",
69*da0073e9SAndroid Build Coastguard Worker        "aot_eager": "--training --backend=aot_eager ",
70*da0073e9SAndroid Build Coastguard Worker        "cudagraphs": "--training --backend=cudagraphs ",
71*da0073e9SAndroid Build Coastguard Worker        "aot_nvfuser": "--training --nvfuser --backend=aot_ts_nvfuser ",
72*da0073e9SAndroid Build Coastguard Worker        "nvprims_nvfuser": "--training --backend=nvprims_nvfuser ",
73*da0073e9SAndroid Build Coastguard Worker        "inductor": "--training --inductor ",
74*da0073e9SAndroid Build Coastguard Worker        "inductor_no_cudagraphs": "--training --inductor --disable-cudagraphs ",
75*da0073e9SAndroid Build Coastguard Worker        "inductor_max_autotune": "--training --inductor --inductor-compile-mode max-autotune ",
76*da0073e9SAndroid Build Coastguard Worker        "inductor_max_autotune_no_cudagraphs": (
77*da0073e9SAndroid Build Coastguard Worker            "--training --inductor --inductor-compile-mode max-autotune-no-cudagraphs --disable-cudagraphs "
78*da0073e9SAndroid Build Coastguard Worker        ),
79*da0073e9SAndroid Build Coastguard Worker    },
80*da0073e9SAndroid Build Coastguard Worker    "inference": {
81*da0073e9SAndroid Build Coastguard Worker        "aot_eager": "--inference --backend=aot_eager ",
82*da0073e9SAndroid Build Coastguard Worker        "eager": "--inference --backend=eager ",
83*da0073e9SAndroid Build Coastguard Worker        "ts_nnc": "--inference --speedup-ts ",
84*da0073e9SAndroid Build Coastguard Worker        "ts_nvfuser": "--inference -n100 --speedup-ts --nvfuser ",
85*da0073e9SAndroid Build Coastguard Worker        "trt": "--inference -n100 --speedup-trt ",
86*da0073e9SAndroid Build Coastguard Worker        "ts_nvfuser_cudagraphs": "--inference --backend=cudagraphs_ts ",
87*da0073e9SAndroid Build Coastguard Worker        "inductor": "--inference -n50 --inductor ",
88*da0073e9SAndroid Build Coastguard Worker        "inductor_no_cudagraphs": "--inference -n50 --inductor --disable-cudagraphs ",
89*da0073e9SAndroid Build Coastguard Worker        "inductor_max_autotune": "--inference -n50 --inductor --inductor-compile-mode max-autotune ",
90*da0073e9SAndroid Build Coastguard Worker        "inductor_max_autotune_no_cudagraphs": (
91*da0073e9SAndroid Build Coastguard Worker            "--inference -n50 --inductor --inductor-compile-mode max-autotune-no-cudagraphs --disable-cudagraphs "
92*da0073e9SAndroid Build Coastguard Worker        ),
93*da0073e9SAndroid Build Coastguard Worker        "torchscript-onnx": "--inference -n5 --torchscript-onnx",
94*da0073e9SAndroid Build Coastguard Worker        "dynamo-onnx": "--inference -n5 --dynamo-onnx",
95*da0073e9SAndroid Build Coastguard Worker    },
96*da0073e9SAndroid Build Coastguard Worker}
97*da0073e9SAndroid Build Coastguard Worker
98*da0073e9SAndroid Build Coastguard WorkerINFERENCE_COMPILERS = tuple(TABLE["inference"].keys())
99*da0073e9SAndroid Build Coastguard WorkerTRAINING_COMPILERS = tuple(TABLE["training"].keys())
100*da0073e9SAndroid Build Coastguard Worker
101*da0073e9SAndroid Build Coastguard WorkerDEFAULTS = {
102*da0073e9SAndroid Build Coastguard Worker    "training": [
103*da0073e9SAndroid Build Coastguard Worker        "eager",
104*da0073e9SAndroid Build Coastguard Worker        "aot_eager",
105*da0073e9SAndroid Build Coastguard Worker        "inductor",
106*da0073e9SAndroid Build Coastguard Worker        "inductor_no_cudagraphs",
107*da0073e9SAndroid Build Coastguard Worker    ],
108*da0073e9SAndroid Build Coastguard Worker    "inference": [
109*da0073e9SAndroid Build Coastguard Worker        "eager",
110*da0073e9SAndroid Build Coastguard Worker        "aot_eager",
111*da0073e9SAndroid Build Coastguard Worker        "inductor",
112*da0073e9SAndroid Build Coastguard Worker        "inductor_no_cudagraphs",
113*da0073e9SAndroid Build Coastguard Worker    ],
114*da0073e9SAndroid Build Coastguard Worker    "flag_compilers": {
115*da0073e9SAndroid Build Coastguard Worker        "training": ["inductor", "inductor_no_cudagraphs"],
116*da0073e9SAndroid Build Coastguard Worker        "inference": ["inductor", "inductor_no_cudagraphs"],
117*da0073e9SAndroid Build Coastguard Worker    },
118*da0073e9SAndroid Build Coastguard Worker    "dtypes": [
119*da0073e9SAndroid Build Coastguard Worker        "float32",
120*da0073e9SAndroid Build Coastguard Worker    ],
121*da0073e9SAndroid Build Coastguard Worker    "suites": ["torchbench", "huggingface", "timm_models"],
122*da0073e9SAndroid Build Coastguard Worker    "devices": [
123*da0073e9SAndroid Build Coastguard Worker        "cuda",
124*da0073e9SAndroid Build Coastguard Worker    ],
125*da0073e9SAndroid Build Coastguard Worker    "quick": {
126*da0073e9SAndroid Build Coastguard Worker        "torchbench": '-k "resnet..$"',
127*da0073e9SAndroid Build Coastguard Worker        "huggingface": "-k Albert",
128*da0073e9SAndroid Build Coastguard Worker        "timm_models": ' -k "^resnet" -k "^inception"',
129*da0073e9SAndroid Build Coastguard Worker    },
130*da0073e9SAndroid Build Coastguard Worker}
131*da0073e9SAndroid Build Coastguard Worker
132*da0073e9SAndroid Build Coastguard Worker
133*da0073e9SAndroid Build Coastguard WorkerDASHBOARD_DEFAULTS = {
134*da0073e9SAndroid Build Coastguard Worker    "dashboard_image_uploader": "/fsx/users/anijain/bin/imgur.sh",
135*da0073e9SAndroid Build Coastguard Worker    "dashboard_archive_path": "/data/home/anijain/cluster/cron_logs",
136*da0073e9SAndroid Build Coastguard Worker    "dashboard_gh_cli_path": "/data/home/anijain/miniconda/bin/gh",
137*da0073e9SAndroid Build Coastguard Worker}
138*da0073e9SAndroid Build Coastguard Worker
139*da0073e9SAndroid Build Coastguard Worker
140*da0073e9SAndroid Build Coastguard Workerdef flag_speedup(x):
141*da0073e9SAndroid Build Coastguard Worker    return x < 0.95
142*da0073e9SAndroid Build Coastguard Worker
143*da0073e9SAndroid Build Coastguard Worker
144*da0073e9SAndroid Build Coastguard Workerdef flag_compilation_latency(x):
145*da0073e9SAndroid Build Coastguard Worker    return x > 120
146*da0073e9SAndroid Build Coastguard Worker
147*da0073e9SAndroid Build Coastguard Worker
148*da0073e9SAndroid Build Coastguard Workerdef flag_compression_ratio(x):
149*da0073e9SAndroid Build Coastguard Worker    return x < 0.9
150*da0073e9SAndroid Build Coastguard Worker
151*da0073e9SAndroid Build Coastguard Worker
152*da0073e9SAndroid Build Coastguard Workerdef flag_accuracy(x):
153*da0073e9SAndroid Build Coastguard Worker    return "pass" not in x
154*da0073e9SAndroid Build Coastguard Worker
155*da0073e9SAndroid Build Coastguard Worker
156*da0073e9SAndroid Build Coastguard WorkerFLAG_FNS = {
157*da0073e9SAndroid Build Coastguard Worker    "speedup": flag_speedup,
158*da0073e9SAndroid Build Coastguard Worker    "compilation_latency": flag_compilation_latency,
159*da0073e9SAndroid Build Coastguard Worker    "compression_ratio": flag_compression_ratio,
160*da0073e9SAndroid Build Coastguard Worker    "accuracy": flag_accuracy,
161*da0073e9SAndroid Build Coastguard Worker}
162*da0073e9SAndroid Build Coastguard Worker
163*da0073e9SAndroid Build Coastguard Worker
164*da0073e9SAndroid Build Coastguard Workerdef percentage(part, whole, decimals=2):
165*da0073e9SAndroid Build Coastguard Worker    if whole == 0:
166*da0073e9SAndroid Build Coastguard Worker        return 0
167*da0073e9SAndroid Build Coastguard Worker    return round(100 * float(part) / float(whole), decimals)
168*da0073e9SAndroid Build Coastguard Worker
169*da0073e9SAndroid Build Coastguard Worker
170*da0073e9SAndroid Build Coastguard Workerdef parse_args():
171*da0073e9SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser()
172*da0073e9SAndroid Build Coastguard Worker    parser.add_argument("--devices", action="append", help="cpu or cuda")
173*da0073e9SAndroid Build Coastguard Worker    parser.add_argument("--dtypes", action="append", help="float16/float32/amp")
174*da0073e9SAndroid Build Coastguard Worker    parser.add_argument("--suites", action="append", help="huggingface/torchbench/timm")
175*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
176*da0073e9SAndroid Build Coastguard Worker        "--compilers",
177*da0073e9SAndroid Build Coastguard Worker        action="append",
178*da0073e9SAndroid Build Coastguard Worker        help=f"For --inference, options are {INFERENCE_COMPILERS}. For --training, options are {TRAINING_COMPILERS}",
179*da0073e9SAndroid Build Coastguard Worker    )
180*da0073e9SAndroid Build Coastguard Worker
181*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
182*da0073e9SAndroid Build Coastguard Worker        "--flag-compilers",
183*da0073e9SAndroid Build Coastguard Worker        action="append",
184*da0073e9SAndroid Build Coastguard Worker        help="List of compilers to flag issues. Same format as --compilers.",
185*da0073e9SAndroid Build Coastguard Worker    )
186*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
187*da0073e9SAndroid Build Coastguard Worker        "--quick", action="store_true", help="Just runs one model. Helps in debugging"
188*da0073e9SAndroid Build Coastguard Worker    )
189*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
190*da0073e9SAndroid Build Coastguard Worker        "--output-dir",
191*da0073e9SAndroid Build Coastguard Worker        help="Choose the output directory to save the logs",
192*da0073e9SAndroid Build Coastguard Worker        default=DEFAULT_OUTPUT_DIR,
193*da0073e9SAndroid Build Coastguard Worker    )
194*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
195*da0073e9SAndroid Build Coastguard Worker        "--keep-output-dir",
196*da0073e9SAndroid Build Coastguard Worker        action="store_true",
197*da0073e9SAndroid Build Coastguard Worker        help="Do not cleanup the output directory before running",
198*da0073e9SAndroid Build Coastguard Worker    )
199*da0073e9SAndroid Build Coastguard Worker
200*da0073e9SAndroid Build Coastguard Worker    # Choose either generation of commands, pretty parsing or e2e runs
201*da0073e9SAndroid Build Coastguard Worker    group = parser.add_mutually_exclusive_group(required=False)
202*da0073e9SAndroid Build Coastguard Worker    group.add_argument(
203*da0073e9SAndroid Build Coastguard Worker        "--print-run-commands",
204*da0073e9SAndroid Build Coastguard Worker        "--print_run_commands",
205*da0073e9SAndroid Build Coastguard Worker        action="store_true",
206*da0073e9SAndroid Build Coastguard Worker        help="Generate commands and saves them to run.sh",
207*da0073e9SAndroid Build Coastguard Worker    )
208*da0073e9SAndroid Build Coastguard Worker    group.add_argument(
209*da0073e9SAndroid Build Coastguard Worker        "--visualize-logs",
210*da0073e9SAndroid Build Coastguard Worker        "--visualize_logs",
211*da0073e9SAndroid Build Coastguard Worker        action="store_true",
212*da0073e9SAndroid Build Coastguard Worker        help="Pretty print the log files and draw graphs",
213*da0073e9SAndroid Build Coastguard Worker    )
214*da0073e9SAndroid Build Coastguard Worker    group.add_argument(
215*da0073e9SAndroid Build Coastguard Worker        "--run",
216*da0073e9SAndroid Build Coastguard Worker        action="store_true",
217*da0073e9SAndroid Build Coastguard Worker        default=True,
218*da0073e9SAndroid Build Coastguard Worker        help="Generate commands, run and parses the files",
219*da0073e9SAndroid Build Coastguard Worker    )
220*da0073e9SAndroid Build Coastguard Worker
221*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
222*da0073e9SAndroid Build Coastguard Worker        "--log-operator-inputs",
223*da0073e9SAndroid Build Coastguard Worker        action="store_true",
224*da0073e9SAndroid Build Coastguard Worker        default=False,
225*da0073e9SAndroid Build Coastguard Worker        help="Log operator inputs",
226*da0073e9SAndroid Build Coastguard Worker    )
227*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
228*da0073e9SAndroid Build Coastguard Worker        "--include-slowdowns",
229*da0073e9SAndroid Build Coastguard Worker        "--include_slowdowns",
230*da0073e9SAndroid Build Coastguard Worker        action="store_true",
231*da0073e9SAndroid Build Coastguard Worker        default=False,
232*da0073e9SAndroid Build Coastguard Worker        help="Include slowdowns in geomean performance speedup report. By default, slowdowns are ignored. "
233*da0073e9SAndroid Build Coastguard Worker        "This is because one can always use eager if compile is not speeding things up",
234*da0073e9SAndroid Build Coastguard Worker    )
235*da0073e9SAndroid Build Coastguard Worker
236*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
237*da0073e9SAndroid Build Coastguard Worker        "--extra-args", default="", help="Append commandline with these args"
238*da0073e9SAndroid Build Coastguard Worker    )
239*da0073e9SAndroid Build Coastguard Worker
240*da0073e9SAndroid Build Coastguard Worker    # Choose either inference or training
241*da0073e9SAndroid Build Coastguard Worker    group_mode = parser.add_mutually_exclusive_group(required=True)
242*da0073e9SAndroid Build Coastguard Worker    group_mode.add_argument(
243*da0073e9SAndroid Build Coastguard Worker        "--inference", action="store_true", help="Only run inference related tasks"
244*da0073e9SAndroid Build Coastguard Worker    )
245*da0073e9SAndroid Build Coastguard Worker    group_mode.add_argument(
246*da0073e9SAndroid Build Coastguard Worker        "--training", action="store_true", help="Only run training related tasks"
247*da0073e9SAndroid Build Coastguard Worker    )
248*da0073e9SAndroid Build Coastguard Worker
249*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
250*da0073e9SAndroid Build Coastguard Worker        "--base-sha",
251*da0073e9SAndroid Build Coastguard Worker        help="commit id for the tested pytorch",
252*da0073e9SAndroid Build Coastguard Worker    )
253*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
254*da0073e9SAndroid Build Coastguard Worker        "--total-partitions",
255*da0073e9SAndroid Build Coastguard Worker        type=int,
256*da0073e9SAndroid Build Coastguard Worker        help="Total number of partitions, to be passed to the actual benchmark script",
257*da0073e9SAndroid Build Coastguard Worker    )
258*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
259*da0073e9SAndroid Build Coastguard Worker        "--partition-id",
260*da0073e9SAndroid Build Coastguard Worker        type=int,
261*da0073e9SAndroid Build Coastguard Worker        help="ID of partition, to be passed to the actual benchmark script",
262*da0073e9SAndroid Build Coastguard Worker    )
263*da0073e9SAndroid Build Coastguard Worker
264*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
265*da0073e9SAndroid Build Coastguard Worker        "--update-dashboard",
266*da0073e9SAndroid Build Coastguard Worker        action="store_true",
267*da0073e9SAndroid Build Coastguard Worker        default=False,
268*da0073e9SAndroid Build Coastguard Worker        help="Updates to dashboard",
269*da0073e9SAndroid Build Coastguard Worker    )
270*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
271*da0073e9SAndroid Build Coastguard Worker        "--no-graphs",
272*da0073e9SAndroid Build Coastguard Worker        action="store_true",
273*da0073e9SAndroid Build Coastguard Worker        default=False,
274*da0073e9SAndroid Build Coastguard Worker        help="Do not genenerate and upload metric graphs",
275*da0073e9SAndroid Build Coastguard Worker    )
276*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
277*da0073e9SAndroid Build Coastguard Worker        "--no-update-archive",
278*da0073e9SAndroid Build Coastguard Worker        action="store_true",
279*da0073e9SAndroid Build Coastguard Worker        default=False,
280*da0073e9SAndroid Build Coastguard Worker        help="Do not update lookup.csv or the log archive",
281*da0073e9SAndroid Build Coastguard Worker    )
282*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
283*da0073e9SAndroid Build Coastguard Worker        "--no-gh-comment",
284*da0073e9SAndroid Build Coastguard Worker        action="store_true",
285*da0073e9SAndroid Build Coastguard Worker        default=False,
286*da0073e9SAndroid Build Coastguard Worker        help="Do not write a comment to github",
287*da0073e9SAndroid Build Coastguard Worker    )
288*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
289*da0073e9SAndroid Build Coastguard Worker        "--no-detect-regressions",
290*da0073e9SAndroid Build Coastguard Worker        action="store_true",
291*da0073e9SAndroid Build Coastguard Worker        default=False,
292*da0073e9SAndroid Build Coastguard Worker        help="Do not compare to previous runs for regressions or metric graphs.",
293*da0073e9SAndroid Build Coastguard Worker    )
294*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
295*da0073e9SAndroid Build Coastguard Worker        "--update-dashboard-test",
296*da0073e9SAndroid Build Coastguard Worker        action="store_true",
297*da0073e9SAndroid Build Coastguard Worker        default=False,
298*da0073e9SAndroid Build Coastguard Worker        help="does all of --no-graphs, --no-update-archive, and --no-gh-comment",
299*da0073e9SAndroid Build Coastguard Worker    )
300*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
301*da0073e9SAndroid Build Coastguard Worker        "--dashboard-image-uploader",
302*da0073e9SAndroid Build Coastguard Worker        default=DASHBOARD_DEFAULTS["dashboard_image_uploader"],
303*da0073e9SAndroid Build Coastguard Worker        help="Image uploader command",
304*da0073e9SAndroid Build Coastguard Worker    )
305*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
306*da0073e9SAndroid Build Coastguard Worker        "--dashboard-archive-path",
307*da0073e9SAndroid Build Coastguard Worker        default=DASHBOARD_DEFAULTS["dashboard_archive_path"],
308*da0073e9SAndroid Build Coastguard Worker        help="Archived directory path",
309*da0073e9SAndroid Build Coastguard Worker    )
310*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
311*da0073e9SAndroid Build Coastguard Worker        "--archive-name",
312*da0073e9SAndroid Build Coastguard Worker        help="Directory name under dashboard-archive-path to copy output-dir to. "
313*da0073e9SAndroid Build Coastguard Worker        "If not provided, a generated name is used.",
314*da0073e9SAndroid Build Coastguard Worker    )
315*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
316*da0073e9SAndroid Build Coastguard Worker        "--dashboard-gh-cli-path",
317*da0073e9SAndroid Build Coastguard Worker        default=DASHBOARD_DEFAULTS["dashboard_gh_cli_path"],
318*da0073e9SAndroid Build Coastguard Worker        help="Github CLI path",
319*da0073e9SAndroid Build Coastguard Worker    )
320*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
321*da0073e9SAndroid Build Coastguard Worker        "--batch-size",
322*da0073e9SAndroid Build Coastguard Worker        "--batch_size",
323*da0073e9SAndroid Build Coastguard Worker        type=int,
324*da0073e9SAndroid Build Coastguard Worker        default=None,
325*da0073e9SAndroid Build Coastguard Worker        help="batch size for benchmarking",
326*da0073e9SAndroid Build Coastguard Worker    )
327*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
328*da0073e9SAndroid Build Coastguard Worker        "--threads",
329*da0073e9SAndroid Build Coastguard Worker        "-t",
330*da0073e9SAndroid Build Coastguard Worker        type=int,
331*da0073e9SAndroid Build Coastguard Worker        default=None,
332*da0073e9SAndroid Build Coastguard Worker        help="number of threads to use for eager and inductor.",
333*da0073e9SAndroid Build Coastguard Worker    )
334*da0073e9SAndroid Build Coastguard Worker    launcher_group = parser.add_argument_group("CPU Launcher Parameters")
335*da0073e9SAndroid Build Coastguard Worker    launcher_group.add_argument(
336*da0073e9SAndroid Build Coastguard Worker        "--enable-cpu-launcher",
337*da0073e9SAndroid Build Coastguard Worker        "--enable_cpu_launcher",
338*da0073e9SAndroid Build Coastguard Worker        action="store_true",
339*da0073e9SAndroid Build Coastguard Worker        default=False,
340*da0073e9SAndroid Build Coastguard Worker        help="Use torch.backends.xeon.run_cpu to get the peak performance on Intel(R) Xeon(R) Scalable Processors.",
341*da0073e9SAndroid Build Coastguard Worker    )
342*da0073e9SAndroid Build Coastguard Worker    launcher_group.add_argument(
343*da0073e9SAndroid Build Coastguard Worker        "--cpu-launcher-args",
344*da0073e9SAndroid Build Coastguard Worker        "--cpu_launcher_args",
345*da0073e9SAndroid Build Coastguard Worker        type=str,
346*da0073e9SAndroid Build Coastguard Worker        default="",
347*da0073e9SAndroid Build Coastguard Worker        help="Provide the args of torch.backends.xeon.run_cpu. "
348*da0073e9SAndroid Build Coastguard Worker        "To look up what optional arguments this launcher offers: python -m torch.backends.xeon.run_cpu --help",
349*da0073e9SAndroid Build Coastguard Worker    )
350*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
351*da0073e9SAndroid Build Coastguard Worker        "--no-cold-start-latency",
352*da0073e9SAndroid Build Coastguard Worker        action="store_true",
353*da0073e9SAndroid Build Coastguard Worker        default=False,
354*da0073e9SAndroid Build Coastguard Worker        help="Do not include --cold-start-latency on inductor benchmarks",
355*da0073e9SAndroid Build Coastguard Worker    )
356*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
357*da0073e9SAndroid Build Coastguard Worker        "--inductor-compile-mode",
358*da0073e9SAndroid Build Coastguard Worker        default=None,
359*da0073e9SAndroid Build Coastguard Worker        help="torch.compile mode argument for inductor runs.",
360*da0073e9SAndroid Build Coastguard Worker    )
361*da0073e9SAndroid Build Coastguard Worker    args = parser.parse_args()
362*da0073e9SAndroid Build Coastguard Worker    return args
363*da0073e9SAndroid Build Coastguard Worker
364*da0073e9SAndroid Build Coastguard Worker
365*da0073e9SAndroid Build Coastguard Workerdef get_mode(args):
366*da0073e9SAndroid Build Coastguard Worker    if args.inference:
367*da0073e9SAndroid Build Coastguard Worker        return "inference"
368*da0073e9SAndroid Build Coastguard Worker    return "training"
369*da0073e9SAndroid Build Coastguard Worker
370*da0073e9SAndroid Build Coastguard Worker
371*da0073e9SAndroid Build Coastguard Workerdef get_skip_tests(suite, device, is_training: bool):
372*da0073e9SAndroid Build Coastguard Worker    """
373*da0073e9SAndroid Build Coastguard Worker    Generate -x seperated string to skip the unusual setup training tests
374*da0073e9SAndroid Build Coastguard Worker    """
375*da0073e9SAndroid Build Coastguard Worker    skip_tests = set()
376*da0073e9SAndroid Build Coastguard Worker    original_dir = abspath(os.getcwd())
377*da0073e9SAndroid Build Coastguard Worker    module = importlib.import_module(suite)
378*da0073e9SAndroid Build Coastguard Worker    os.chdir(original_dir)
379*da0073e9SAndroid Build Coastguard Worker
380*da0073e9SAndroid Build Coastguard Worker    if suite == "torchbench":
381*da0073e9SAndroid Build Coastguard Worker        skip_tests.update(module.TorchBenchmarkRunner().skip_models)
382*da0073e9SAndroid Build Coastguard Worker        if is_training:
383*da0073e9SAndroid Build Coastguard Worker            skip_tests.update(
384*da0073e9SAndroid Build Coastguard Worker                module.TorchBenchmarkRunner().skip_not_suitable_for_training_models
385*da0073e9SAndroid Build Coastguard Worker            )
386*da0073e9SAndroid Build Coastguard Worker        if device == "cpu":
387*da0073e9SAndroid Build Coastguard Worker            skip_tests.update(module.TorchBenchmarkRunner().skip_models_for_cpu)
388*da0073e9SAndroid Build Coastguard Worker        elif device == "cuda":
389*da0073e9SAndroid Build Coastguard Worker            skip_tests.update(module.TorchBenchmarkRunner().skip_models_for_cuda)
390*da0073e9SAndroid Build Coastguard Worker
391*da0073e9SAndroid Build Coastguard Worker    skip_tests = (f"-x {name}" for name in skip_tests)
392*da0073e9SAndroid Build Coastguard Worker    skip_str = " ".join(skip_tests)
393*da0073e9SAndroid Build Coastguard Worker    return skip_str
394*da0073e9SAndroid Build Coastguard Worker
395*da0073e9SAndroid Build Coastguard Worker
396*da0073e9SAndroid Build Coastguard Workerdef generate_csv_name(args, dtype, suite, device, compiler, testing):
397*da0073e9SAndroid Build Coastguard Worker    mode = get_mode(args)
398*da0073e9SAndroid Build Coastguard Worker    return f"{compiler}_{suite}_{dtype}_{mode}_{device}_{testing}.csv"
399*da0073e9SAndroid Build Coastguard Worker
400*da0073e9SAndroid Build Coastguard Worker
401*da0073e9SAndroid Build Coastguard Workerdef generate_commands(args, dtypes, suites, devices, compilers, output_dir):
402*da0073e9SAndroid Build Coastguard Worker    mode = get_mode(args)
403*da0073e9SAndroid Build Coastguard Worker    suites_str = "_".join(suites)
404*da0073e9SAndroid Build Coastguard Worker    devices_str = "_".join(devices)
405*da0073e9SAndroid Build Coastguard Worker    dtypes_str = "_".join(dtypes)
406*da0073e9SAndroid Build Coastguard Worker    compilers_str = "_".join(compilers)
407*da0073e9SAndroid Build Coastguard Worker    generated_file = (
408*da0073e9SAndroid Build Coastguard Worker        f"run_{mode}_{devices_str}_{dtypes_str}_{suites_str}_{compilers_str}.sh"
409*da0073e9SAndroid Build Coastguard Worker    )
410*da0073e9SAndroid Build Coastguard Worker    with open(generated_file, "w") as runfile:
411*da0073e9SAndroid Build Coastguard Worker        lines = []
412*da0073e9SAndroid Build Coastguard Worker
413*da0073e9SAndroid Build Coastguard Worker        lines.append("#!/bin/bash")
414*da0073e9SAndroid Build Coastguard Worker        lines.append("set -x")
415*da0073e9SAndroid Build Coastguard Worker        lines.append("# Setup the output directory")
416*da0073e9SAndroid Build Coastguard Worker        if not args.keep_output_dir:
417*da0073e9SAndroid Build Coastguard Worker            lines.append(f"rm -rf {output_dir}")
418*da0073e9SAndroid Build Coastguard Worker        # It's ok if the output directory already exists
419*da0073e9SAndroid Build Coastguard Worker        lines.append(f"mkdir -p {output_dir}")
420*da0073e9SAndroid Build Coastguard Worker        lines.append("")
421*da0073e9SAndroid Build Coastguard Worker
422*da0073e9SAndroid Build Coastguard Worker        for testing in ["performance", "accuracy"]:
423*da0073e9SAndroid Build Coastguard Worker            for iter in itertools.product(suites, devices, dtypes):
424*da0073e9SAndroid Build Coastguard Worker                suite, device, dtype = iter
425*da0073e9SAndroid Build Coastguard Worker                lines.append(
426*da0073e9SAndroid Build Coastguard Worker                    f"# Commands for {suite} for device={device}, dtype={dtype} for {mode} and for {testing} testing"
427*da0073e9SAndroid Build Coastguard Worker                )
428*da0073e9SAndroid Build Coastguard Worker                info = TABLE[mode]
429*da0073e9SAndroid Build Coastguard Worker                for compiler in compilers:
430*da0073e9SAndroid Build Coastguard Worker                    base_cmd = info[compiler]
431*da0073e9SAndroid Build Coastguard Worker                    output_filename = f"{output_dir}/{generate_csv_name(args, dtype, suite, device, compiler, testing)}"
432*da0073e9SAndroid Build Coastguard Worker                    launcher_cmd = "python"
433*da0073e9SAndroid Build Coastguard Worker                    if args.enable_cpu_launcher:
434*da0073e9SAndroid Build Coastguard Worker                        launcher_cmd = f"python -m torch.backends.xeon.run_cpu {args.cpu_launcher_args}"
435*da0073e9SAndroid Build Coastguard Worker                    cmd = f"{launcher_cmd} benchmarks/dynamo/{suite}.py --{testing} --{dtype} -d{device} --output={output_filename}"
436*da0073e9SAndroid Build Coastguard Worker                    cmd = f"{cmd} {base_cmd} {args.extra_args} --dashboard"
437*da0073e9SAndroid Build Coastguard Worker                    skip_tests_str = get_skip_tests(suite, device, args.training)
438*da0073e9SAndroid Build Coastguard Worker                    cmd = f"{cmd} {skip_tests_str}"
439*da0073e9SAndroid Build Coastguard Worker
440*da0073e9SAndroid Build Coastguard Worker                    if args.log_operator_inputs:
441*da0073e9SAndroid Build Coastguard Worker                        cmd = f"{cmd} --log-operator-inputs"
442*da0073e9SAndroid Build Coastguard Worker
443*da0073e9SAndroid Build Coastguard Worker                    if args.quick:
444*da0073e9SAndroid Build Coastguard Worker                        filters = DEFAULTS["quick"][suite]
445*da0073e9SAndroid Build Coastguard Worker                        cmd = f"{cmd} {filters}"
446*da0073e9SAndroid Build Coastguard Worker
447*da0073e9SAndroid Build Coastguard Worker                    if (
448*da0073e9SAndroid Build Coastguard Worker                        compiler
449*da0073e9SAndroid Build Coastguard Worker                        in (
450*da0073e9SAndroid Build Coastguard Worker                            "inductor",
451*da0073e9SAndroid Build Coastguard Worker                            "inductor_no_cudagraphs",
452*da0073e9SAndroid Build Coastguard Worker                        )
453*da0073e9SAndroid Build Coastguard Worker                        and not args.no_cold_start_latency
454*da0073e9SAndroid Build Coastguard Worker                    ):
455*da0073e9SAndroid Build Coastguard Worker                        cmd = f"{cmd} --cold-start-latency"
456*da0073e9SAndroid Build Coastguard Worker
457*da0073e9SAndroid Build Coastguard Worker                    if args.batch_size is not None:
458*da0073e9SAndroid Build Coastguard Worker                        cmd = f"{cmd} --batch-size {args.batch_size}"
459*da0073e9SAndroid Build Coastguard Worker
460*da0073e9SAndroid Build Coastguard Worker                    if args.threads is not None:
461*da0073e9SAndroid Build Coastguard Worker                        cmd = f"{cmd} --threads {args.threads}"
462*da0073e9SAndroid Build Coastguard Worker
463*da0073e9SAndroid Build Coastguard Worker                    if args.total_partitions is not None:
464*da0073e9SAndroid Build Coastguard Worker                        cmd = f"{cmd} --total-partitions {args.total_partitions}"
465*da0073e9SAndroid Build Coastguard Worker
466*da0073e9SAndroid Build Coastguard Worker                    if args.partition_id is not None:
467*da0073e9SAndroid Build Coastguard Worker                        cmd = f"{cmd} --partition-id {args.partition_id}"
468*da0073e9SAndroid Build Coastguard Worker
469*da0073e9SAndroid Build Coastguard Worker                    if args.inductor_compile_mode is not None:
470*da0073e9SAndroid Build Coastguard Worker                        cmd = f"{cmd} --inductor-compile-mode {args.inductor_compile_mode}"
471*da0073e9SAndroid Build Coastguard Worker                    lines.append(cmd)
472*da0073e9SAndroid Build Coastguard Worker                lines.append("")
473*da0073e9SAndroid Build Coastguard Worker        runfile.writelines([line + "\n" for line in lines])
474*da0073e9SAndroid Build Coastguard Worker    return generated_file
475*da0073e9SAndroid Build Coastguard Worker
476*da0073e9SAndroid Build Coastguard Worker
477*da0073e9SAndroid Build Coastguard Workerdef generate_dropdown_comment(title, body):
478*da0073e9SAndroid Build Coastguard Worker    str_io = io.StringIO()
479*da0073e9SAndroid Build Coastguard Worker    str_io.write(f"{title}\n")
480*da0073e9SAndroid Build Coastguard Worker    str_io.write("<details>\n")
481*da0073e9SAndroid Build Coastguard Worker    str_io.write("<summary>see more</summary>\n")
482*da0073e9SAndroid Build Coastguard Worker    str_io.write(f"{body}")
483*da0073e9SAndroid Build Coastguard Worker    str_io.write("\n")
484*da0073e9SAndroid Build Coastguard Worker    str_io.write("</details>\n\n")
485*da0073e9SAndroid Build Coastguard Worker    return str_io.getvalue()
486*da0073e9SAndroid Build Coastguard Worker
487*da0073e9SAndroid Build Coastguard Worker
488*da0073e9SAndroid Build Coastguard Workerdef build_summary(args):
489*da0073e9SAndroid Build Coastguard Worker    out_io = io.StringIO()
490*da0073e9SAndroid Build Coastguard Worker
491*da0073e9SAndroid Build Coastguard Worker    def print_commit_hash(path, name):
492*da0073e9SAndroid Build Coastguard Worker        if args.base_sha is not None:
493*da0073e9SAndroid Build Coastguard Worker            if name == "pytorch":
494*da0073e9SAndroid Build Coastguard Worker                out_io.write(f"{name} commit: {args.base_sha}\n")
495*da0073e9SAndroid Build Coastguard Worker        elif exists(path):
496*da0073e9SAndroid Build Coastguard Worker            import git
497*da0073e9SAndroid Build Coastguard Worker
498*da0073e9SAndroid Build Coastguard Worker            repo = git.Repo(path, search_parent_directories=True)
499*da0073e9SAndroid Build Coastguard Worker            sha = repo.head.object.hexsha
500*da0073e9SAndroid Build Coastguard Worker            date = repo.head.object.committed_datetime
501*da0073e9SAndroid Build Coastguard Worker            out_io.write(f"{name} commit: {sha}\n")
502*da0073e9SAndroid Build Coastguard Worker            out_io.write(f"{name} commit date: {date}\n")
503*da0073e9SAndroid Build Coastguard Worker        else:
504*da0073e9SAndroid Build Coastguard Worker            out_io.write(f"{name} Absent\n")
505*da0073e9SAndroid Build Coastguard Worker
506*da0073e9SAndroid Build Coastguard Worker    def env_var(name):
507*da0073e9SAndroid Build Coastguard Worker        if name in os.environ:
508*da0073e9SAndroid Build Coastguard Worker            out_io.write(f"{name} = {os.environ[name]}\n")
509*da0073e9SAndroid Build Coastguard Worker        else:
510*da0073e9SAndroid Build Coastguard Worker            out_io.write(f"{name} = {None}\n")
511*da0073e9SAndroid Build Coastguard Worker
512*da0073e9SAndroid Build Coastguard Worker    out_io.write("\n")
513*da0073e9SAndroid Build Coastguard Worker    out_io.write("### Run name ###\n")
514*da0073e9SAndroid Build Coastguard Worker    out_io.write(get_archive_name(args, args.dtypes[0]))
515*da0073e9SAndroid Build Coastguard Worker    out_io.write("\n")
516*da0073e9SAndroid Build Coastguard Worker
517*da0073e9SAndroid Build Coastguard Worker    out_io.write("\n")
518*da0073e9SAndroid Build Coastguard Worker    out_io.write("### Commit hashes ###\n")
519*da0073e9SAndroid Build Coastguard Worker    print_commit_hash("../pytorch", "pytorch")
520*da0073e9SAndroid Build Coastguard Worker    print_commit_hash("../torchbenchmark", "torchbench")
521*da0073e9SAndroid Build Coastguard Worker
522*da0073e9SAndroid Build Coastguard Worker    out_io.write("\n")
523*da0073e9SAndroid Build Coastguard Worker    out_io.write("### TorchDynamo config flags ###\n")
524*da0073e9SAndroid Build Coastguard Worker    for key in dir(torch._dynamo.config):
525*da0073e9SAndroid Build Coastguard Worker        val = getattr(torch._dynamo.config, key)
526*da0073e9SAndroid Build Coastguard Worker        if not key.startswith("__") and isinstance(val, bool):
527*da0073e9SAndroid Build Coastguard Worker            out_io.write(f"torch._dynamo.config.{key} = {val}\n")
528*da0073e9SAndroid Build Coastguard Worker
529*da0073e9SAndroid Build Coastguard Worker    out_io.write("\n")
530*da0073e9SAndroid Build Coastguard Worker    out_io.write("### Torch version ###\n")
531*da0073e9SAndroid Build Coastguard Worker    out_io.write(f"torch: {torch.__version__}\n")
532*da0073e9SAndroid Build Coastguard Worker
533*da0073e9SAndroid Build Coastguard Worker    out_io.write("\n")
534*da0073e9SAndroid Build Coastguard Worker    out_io.write("### Environment variables ###\n")
535*da0073e9SAndroid Build Coastguard Worker    env_var("TORCH_CUDA_ARCH_LIST")
536*da0073e9SAndroid Build Coastguard Worker    env_var("CUDA_HOME")
537*da0073e9SAndroid Build Coastguard Worker    env_var("USE_LLVM")
538*da0073e9SAndroid Build Coastguard Worker
539*da0073e9SAndroid Build Coastguard Worker    if "cuda" in args.devices:
540*da0073e9SAndroid Build Coastguard Worker        out_io.write("\n")
541*da0073e9SAndroid Build Coastguard Worker        out_io.write("### GPU details ###\n")
542*da0073e9SAndroid Build Coastguard Worker        out_io.write(f"CUDNN VERSION: {torch.backends.cudnn.version()}\n")
543*da0073e9SAndroid Build Coastguard Worker        out_io.write(f"Number CUDA Devices: {torch.cuda.device_count()}\n")
544*da0073e9SAndroid Build Coastguard Worker        out_io.write(f"Device Name: {torch.cuda.get_device_name(0)}\n")
545*da0073e9SAndroid Build Coastguard Worker        out_io.write(
546*da0073e9SAndroid Build Coastguard Worker            f"Device Memory [GB]: {torch.cuda.get_device_properties(0).total_memory/1e9}\n"
547*da0073e9SAndroid Build Coastguard Worker        )
548*da0073e9SAndroid Build Coastguard Worker
549*da0073e9SAndroid Build Coastguard Worker    title = "## Build Summary"
550*da0073e9SAndroid Build Coastguard Worker    comment = generate_dropdown_comment(title, out_io.getvalue())
551*da0073e9SAndroid Build Coastguard Worker    with open(f"{output_dir}/gh_build_summary.txt", "w") as gh_fh:
552*da0073e9SAndroid Build Coastguard Worker        gh_fh.write(comment)
553*da0073e9SAndroid Build Coastguard Worker
554*da0073e9SAndroid Build Coastguard Worker
555*da0073e9SAndroid Build Coastguard Worker@functools.lru_cache(None)
556*da0073e9SAndroid Build Coastguard Workerdef archive_data(archive_name):
557*da0073e9SAndroid Build Coastguard Worker    if archive_name is not None:
558*da0073e9SAndroid Build Coastguard Worker        prefix_match = re.search(r"\w+(?=_performance)", archive_name)
559*da0073e9SAndroid Build Coastguard Worker        if prefix_match is not None:
560*da0073e9SAndroid Build Coastguard Worker            prefix = prefix_match.group(0)
561*da0073e9SAndroid Build Coastguard Worker        else:
562*da0073e9SAndroid Build Coastguard Worker            prefix = ""
563*da0073e9SAndroid Build Coastguard Worker        day_match = re.search(r"day_(\d+)_", archive_name)
564*da0073e9SAndroid Build Coastguard Worker        if day_match is not None:
565*da0073e9SAndroid Build Coastguard Worker            day = day_match.group(1)
566*da0073e9SAndroid Build Coastguard Worker        else:
567*da0073e9SAndroid Build Coastguard Worker            day = "000"
568*da0073e9SAndroid Build Coastguard Worker    else:
569*da0073e9SAndroid Build Coastguard Worker        now = datetime.now(tz=timezone(timedelta(hours=-8)))
570*da0073e9SAndroid Build Coastguard Worker        day = now.strftime("%j")
571*da0073e9SAndroid Build Coastguard Worker        prefix = now.strftime(f"day_{day}_%d_%m_%y")
572*da0073e9SAndroid Build Coastguard Worker    return day, prefix
573*da0073e9SAndroid Build Coastguard Worker
574*da0073e9SAndroid Build Coastguard Worker
575*da0073e9SAndroid Build Coastguard Worker@functools.lru_cache(None)
576*da0073e9SAndroid Build Coastguard Workerdef default_archive_name(dtype):
577*da0073e9SAndroid Build Coastguard Worker    _, prefix = archive_data(None)
578*da0073e9SAndroid Build Coastguard Worker    return f"{prefix}_performance_{dtype}_{randint(100, 999)}"
579*da0073e9SAndroid Build Coastguard Worker
580*da0073e9SAndroid Build Coastguard Worker
581*da0073e9SAndroid Build Coastguard Workerdef get_archive_name(args, dtype):
582*da0073e9SAndroid Build Coastguard Worker    return (
583*da0073e9SAndroid Build Coastguard Worker        default_archive_name(dtype) if args.archive_name is None else args.archive_name
584*da0073e9SAndroid Build Coastguard Worker    )
585*da0073e9SAndroid Build Coastguard Worker
586*da0073e9SAndroid Build Coastguard Worker
587*da0073e9SAndroid Build Coastguard Workerdef archive(src_dir, dest_dir_prefix, archive_name, dtype):
588*da0073e9SAndroid Build Coastguard Worker    if archive_name is None:
589*da0073e9SAndroid Build Coastguard Worker        archive_name = default_archive_name(dtype)
590*da0073e9SAndroid Build Coastguard Worker    # Copy the folder to archived location
591*da0073e9SAndroid Build Coastguard Worker    dest = os.path.join(dest_dir_prefix, archive_name)
592*da0073e9SAndroid Build Coastguard Worker    shutil.copytree(src_dir, dest, dirs_exist_ok=True)
593*da0073e9SAndroid Build Coastguard Worker    print(f"copied contents of {src_dir} to {dest}")
594*da0073e9SAndroid Build Coastguard Worker
595*da0073e9SAndroid Build Coastguard Worker
596*da0073e9SAndroid Build Coastguard Workerdef get_metric_title(metric):
597*da0073e9SAndroid Build Coastguard Worker    if metric == "speedup":
598*da0073e9SAndroid Build Coastguard Worker        return "Performance speedup"
599*da0073e9SAndroid Build Coastguard Worker    elif metric == "accuracy":
600*da0073e9SAndroid Build Coastguard Worker        return "Accuracy"
601*da0073e9SAndroid Build Coastguard Worker    elif metric == "compilation_latency":
602*da0073e9SAndroid Build Coastguard Worker        return "Compilation latency (sec)"
603*da0073e9SAndroid Build Coastguard Worker    elif metric == "compression_ratio":
604*da0073e9SAndroid Build Coastguard Worker        return "Peak Memory Compression Ratio"
605*da0073e9SAndroid Build Coastguard Worker    elif metric == "abs_latency":
606*da0073e9SAndroid Build Coastguard Worker        return "Absolute latency (ms)"
607*da0073e9SAndroid Build Coastguard Worker    raise RuntimeError("unknown metric")
608*da0073e9SAndroid Build Coastguard Worker
609*da0073e9SAndroid Build Coastguard Worker
610*da0073e9SAndroid Build Coastguard Workerclass Parser:
611*da0073e9SAndroid Build Coastguard Worker    def __init__(
612*da0073e9SAndroid Build Coastguard Worker        self, suites, devices, dtypes, compilers, flag_compilers, mode, output_dir
613*da0073e9SAndroid Build Coastguard Worker    ):
614*da0073e9SAndroid Build Coastguard Worker        self.suites = suites
615*da0073e9SAndroid Build Coastguard Worker        self.devices = devices
616*da0073e9SAndroid Build Coastguard Worker        self.dtypes = dtypes
617*da0073e9SAndroid Build Coastguard Worker        self.compilers = compilers
618*da0073e9SAndroid Build Coastguard Worker        self.flag_compilers = flag_compilers
619*da0073e9SAndroid Build Coastguard Worker        self.output_dir = output_dir
620*da0073e9SAndroid Build Coastguard Worker        self.mode = mode
621*da0073e9SAndroid Build Coastguard Worker
622*da0073e9SAndroid Build Coastguard Worker    def has_header(self, output_filename):
623*da0073e9SAndroid Build Coastguard Worker        header_present = False
624*da0073e9SAndroid Build Coastguard Worker        with open(output_filename) as f:
625*da0073e9SAndroid Build Coastguard Worker            line = f.readline()
626*da0073e9SAndroid Build Coastguard Worker            if "dev" in line:
627*da0073e9SAndroid Build Coastguard Worker                header_present = True
628*da0073e9SAndroid Build Coastguard Worker        return header_present
629*da0073e9SAndroid Build Coastguard Worker
630*da0073e9SAndroid Build Coastguard Worker
631*da0073e9SAndroid Build Coastguard Workerclass ParsePerformanceLogs(Parser):
632*da0073e9SAndroid Build Coastguard Worker    def __init__(
633*da0073e9SAndroid Build Coastguard Worker        self,
634*da0073e9SAndroid Build Coastguard Worker        suites,
635*da0073e9SAndroid Build Coastguard Worker        devices,
636*da0073e9SAndroid Build Coastguard Worker        dtypes,
637*da0073e9SAndroid Build Coastguard Worker        compilers,
638*da0073e9SAndroid Build Coastguard Worker        flag_compilers,
639*da0073e9SAndroid Build Coastguard Worker        mode,
640*da0073e9SAndroid Build Coastguard Worker        output_dir,
641*da0073e9SAndroid Build Coastguard Worker        include_slowdowns=False,
642*da0073e9SAndroid Build Coastguard Worker    ):
643*da0073e9SAndroid Build Coastguard Worker        super().__init__(
644*da0073e9SAndroid Build Coastguard Worker            suites,
645*da0073e9SAndroid Build Coastguard Worker            devices,
646*da0073e9SAndroid Build Coastguard Worker            dtypes,
647*da0073e9SAndroid Build Coastguard Worker            compilers,
648*da0073e9SAndroid Build Coastguard Worker            flag_compilers,
649*da0073e9SAndroid Build Coastguard Worker            mode,
650*da0073e9SAndroid Build Coastguard Worker            output_dir,
651*da0073e9SAndroid Build Coastguard Worker        )
652*da0073e9SAndroid Build Coastguard Worker        self.parsed_frames = defaultdict(lambda: defaultdict(None))
653*da0073e9SAndroid Build Coastguard Worker        self.untouched_parsed_frames = defaultdict(lambda: defaultdict(None))
654*da0073e9SAndroid Build Coastguard Worker        self.metrics = [
655*da0073e9SAndroid Build Coastguard Worker            "speedup",
656*da0073e9SAndroid Build Coastguard Worker            "abs_latency",
657*da0073e9SAndroid Build Coastguard Worker            "compilation_latency",
658*da0073e9SAndroid Build Coastguard Worker            "compression_ratio",
659*da0073e9SAndroid Build Coastguard Worker        ]
660*da0073e9SAndroid Build Coastguard Worker        self.bottom_k = 50
661*da0073e9SAndroid Build Coastguard Worker        self.parse()
662*da0073e9SAndroid Build Coastguard Worker        self.include_slowdowns = include_slowdowns
663*da0073e9SAndroid Build Coastguard Worker
664*da0073e9SAndroid Build Coastguard Worker    def plot_graph(self, df, title):
665*da0073e9SAndroid Build Coastguard Worker        labels = df.columns.values.tolist()
666*da0073e9SAndroid Build Coastguard Worker        labels = labels[3:]
667*da0073e9SAndroid Build Coastguard Worker        df.plot(
668*da0073e9SAndroid Build Coastguard Worker            x="name",
669*da0073e9SAndroid Build Coastguard Worker            y=labels,
670*da0073e9SAndroid Build Coastguard Worker            kind="bar",
671*da0073e9SAndroid Build Coastguard Worker            width=0.65,
672*da0073e9SAndroid Build Coastguard Worker            title=title,
673*da0073e9SAndroid Build Coastguard Worker            ylabel="Speedup over eager",
674*da0073e9SAndroid Build Coastguard Worker            xlabel="",
675*da0073e9SAndroid Build Coastguard Worker            grid=True,
676*da0073e9SAndroid Build Coastguard Worker            figsize=(max(len(df.index) / 4, 5), 10),
677*da0073e9SAndroid Build Coastguard Worker            edgecolor="black",
678*da0073e9SAndroid Build Coastguard Worker        )
679*da0073e9SAndroid Build Coastguard Worker        plt.tight_layout()
680*da0073e9SAndroid Build Coastguard Worker        plt.savefig(f"{self.output_dir}/{title}.png")
681*da0073e9SAndroid Build Coastguard Worker
682*da0073e9SAndroid Build Coastguard Worker    def read_csv(self, output_filename):
683*da0073e9SAndroid Build Coastguard Worker        if self.has_header(output_filename):
684*da0073e9SAndroid Build Coastguard Worker            return pd.read_csv(output_filename)
685*da0073e9SAndroid Build Coastguard Worker        else:
686*da0073e9SAndroid Build Coastguard Worker            return pd.read_csv(
687*da0073e9SAndroid Build Coastguard Worker                output_filename,
688*da0073e9SAndroid Build Coastguard Worker                names=[
689*da0073e9SAndroid Build Coastguard Worker                    "dev",
690*da0073e9SAndroid Build Coastguard Worker                    "name",
691*da0073e9SAndroid Build Coastguard Worker                    "batch_size",
692*da0073e9SAndroid Build Coastguard Worker                    "speedup",
693*da0073e9SAndroid Build Coastguard Worker                    "abs_latency",
694*da0073e9SAndroid Build Coastguard Worker                    "compilation_latency",
695*da0073e9SAndroid Build Coastguard Worker                    "compression_ratio",
696*da0073e9SAndroid Build Coastguard Worker                ],
697*da0073e9SAndroid Build Coastguard Worker                header=None,
698*da0073e9SAndroid Build Coastguard Worker                engine="python",
699*da0073e9SAndroid Build Coastguard Worker            )
700*da0073e9SAndroid Build Coastguard Worker
701*da0073e9SAndroid Build Coastguard Worker    def parse(self):
702*da0073e9SAndroid Build Coastguard Worker        self.extract_df("accuracy", "accuracy")
703*da0073e9SAndroid Build Coastguard Worker        for metric in self.metrics:
704*da0073e9SAndroid Build Coastguard Worker            self.extract_df(metric, "performance")
705*da0073e9SAndroid Build Coastguard Worker
706*da0073e9SAndroid Build Coastguard Worker    def clean_batch_sizes(self, frames):
707*da0073e9SAndroid Build Coastguard Worker        # Clean up batch sizes when its 0
708*da0073e9SAndroid Build Coastguard Worker        if len(frames) == 1:
709*da0073e9SAndroid Build Coastguard Worker            return frames
710*da0073e9SAndroid Build Coastguard Worker        batch_sizes = frames[0]["batch_size"].to_list()
711*da0073e9SAndroid Build Coastguard Worker        for frame in frames[1:]:
712*da0073e9SAndroid Build Coastguard Worker            frame_batch_sizes = frame["batch_size"].to_list()
713*da0073e9SAndroid Build Coastguard Worker            for idx, (batch_a, batch_b) in enumerate(
714*da0073e9SAndroid Build Coastguard Worker                zip(batch_sizes, frame_batch_sizes)
715*da0073e9SAndroid Build Coastguard Worker            ):
716*da0073e9SAndroid Build Coastguard Worker                assert batch_a == batch_b or batch_a == 0 or batch_b == 0, print(
717*da0073e9SAndroid Build Coastguard Worker                    f"a={batch_a}, b={batch_b}"
718*da0073e9SAndroid Build Coastguard Worker                )
719*da0073e9SAndroid Build Coastguard Worker                batch_sizes[idx] = max(batch_a, batch_b)
720*da0073e9SAndroid Build Coastguard Worker        for frame in frames:
721*da0073e9SAndroid Build Coastguard Worker            frame["batch_size"] = batch_sizes
722*da0073e9SAndroid Build Coastguard Worker        return frames
723*da0073e9SAndroid Build Coastguard Worker
724*da0073e9SAndroid Build Coastguard Worker    def extract_df(self, metric, testing):
725*da0073e9SAndroid Build Coastguard Worker        for iter in itertools.product(self.suites, self.devices, self.dtypes):
726*da0073e9SAndroid Build Coastguard Worker            suite, device, dtype = iter
727*da0073e9SAndroid Build Coastguard Worker            frames = []
728*da0073e9SAndroid Build Coastguard Worker            for compiler in self.compilers:
729*da0073e9SAndroid Build Coastguard Worker                output_filename = f"{self.output_dir}/{compiler}_{suite}_{dtype}_{self.mode}_{device}_{testing}.csv"
730*da0073e9SAndroid Build Coastguard Worker                df = self.read_csv(output_filename)
731*da0073e9SAndroid Build Coastguard Worker                if metric not in df:
732*da0073e9SAndroid Build Coastguard Worker                    df.insert(len(df.columns), metric, np.nan)
733*da0073e9SAndroid Build Coastguard Worker                df = df[["dev", "name", "batch_size", metric]]
734*da0073e9SAndroid Build Coastguard Worker                df.rename(columns={metric: compiler}, inplace=True)
735*da0073e9SAndroid Build Coastguard Worker                df["batch_size"] = df["batch_size"].astype(int)
736*da0073e9SAndroid Build Coastguard Worker                frames.append(df)
737*da0073e9SAndroid Build Coastguard Worker
738*da0073e9SAndroid Build Coastguard Worker            # Merge the results
739*da0073e9SAndroid Build Coastguard Worker            frames = self.clean_batch_sizes(frames)
740*da0073e9SAndroid Build Coastguard Worker            if len(self.compilers) == 1:
741*da0073e9SAndroid Build Coastguard Worker                df = frames[0]
742*da0073e9SAndroid Build Coastguard Worker            else:
743*da0073e9SAndroid Build Coastguard Worker                # Merge data frames
744*da0073e9SAndroid Build Coastguard Worker                df = pd.merge(frames[0], frames[1], on=["dev", "name", "batch_size"])
745*da0073e9SAndroid Build Coastguard Worker                for idx in range(2, len(frames)):
746*da0073e9SAndroid Build Coastguard Worker                    df = pd.merge(df, frames[idx], on=["dev", "name", "batch_size"])
747*da0073e9SAndroid Build Coastguard Worker
748*da0073e9SAndroid Build Coastguard Worker            if testing == "performance":
749*da0073e9SAndroid Build Coastguard Worker                for compiler in self.compilers:
750*da0073e9SAndroid Build Coastguard Worker                    df[compiler] = pd.to_numeric(df[compiler], errors="coerce").fillna(
751*da0073e9SAndroid Build Coastguard Worker                        0
752*da0073e9SAndroid Build Coastguard Worker                    )
753*da0073e9SAndroid Build Coastguard Worker
754*da0073e9SAndroid Build Coastguard Worker            df_copy = df.copy()
755*da0073e9SAndroid Build Coastguard Worker            df_copy = df_copy.sort_values(
756*da0073e9SAndroid Build Coastguard Worker                by=list(reversed(self.compilers)), ascending=False
757*da0073e9SAndroid Build Coastguard Worker            )
758*da0073e9SAndroid Build Coastguard Worker            if "inductor" in self.compilers:
759*da0073e9SAndroid Build Coastguard Worker                df_copy = df_copy.sort_values(by="inductor", ascending=False)
760*da0073e9SAndroid Build Coastguard Worker            self.untouched_parsed_frames[suite][metric] = df_copy
761*da0073e9SAndroid Build Coastguard Worker
762*da0073e9SAndroid Build Coastguard Worker            if testing == "performance":
763*da0073e9SAndroid Build Coastguard Worker                df_accuracy = self.parsed_frames[suite]["accuracy"]
764*da0073e9SAndroid Build Coastguard Worker                perf_rows = []
765*da0073e9SAndroid Build Coastguard Worker                for model_name in df["name"]:
766*da0073e9SAndroid Build Coastguard Worker                    perf_row = df[df["name"] == model_name].copy()
767*da0073e9SAndroid Build Coastguard Worker                    acc_row = df_accuracy[df_accuracy["name"] == model_name]
768*da0073e9SAndroid Build Coastguard Worker                    for compiler in self.compilers:
769*da0073e9SAndroid Build Coastguard Worker                        if not perf_row.empty:
770*da0073e9SAndroid Build Coastguard Worker                            if acc_row.empty:
771*da0073e9SAndroid Build Coastguard Worker                                perf_row[compiler] = 0.0
772*da0073e9SAndroid Build Coastguard Worker                            elif acc_row[compiler].iloc[0] in (
773*da0073e9SAndroid Build Coastguard Worker                                "model_fail_to_load",
774*da0073e9SAndroid Build Coastguard Worker                                "eager_fail_to_run",
775*da0073e9SAndroid Build Coastguard Worker                            ):
776*da0073e9SAndroid Build Coastguard Worker                                perf_row = pd.DataFrame()
777*da0073e9SAndroid Build Coastguard Worker                            elif acc_row[compiler].iloc[0] not in (
778*da0073e9SAndroid Build Coastguard Worker                                "pass",
779*da0073e9SAndroid Build Coastguard Worker                                "pass_due_to_skip",
780*da0073e9SAndroid Build Coastguard Worker                            ):
781*da0073e9SAndroid Build Coastguard Worker                                perf_row[compiler] = 0.0
782*da0073e9SAndroid Build Coastguard Worker                    if not perf_row.empty:
783*da0073e9SAndroid Build Coastguard Worker                        perf_rows.append(perf_row)
784*da0073e9SAndroid Build Coastguard Worker                df = pd.concat(perf_rows)
785*da0073e9SAndroid Build Coastguard Worker            df = df.sort_values(by=list(reversed(self.compilers)), ascending=False)
786*da0073e9SAndroid Build Coastguard Worker
787*da0073e9SAndroid Build Coastguard Worker            if "inductor" in self.compilers:
788*da0073e9SAndroid Build Coastguard Worker                df = df.sort_values(by="inductor", ascending=False)
789*da0073e9SAndroid Build Coastguard Worker            self.parsed_frames[suite][metric] = df
790*da0073e9SAndroid Build Coastguard Worker
791*da0073e9SAndroid Build Coastguard Worker    def get_passing_entries(self, compiler, df):
792*da0073e9SAndroid Build Coastguard Worker        return df[compiler][df[compiler] > 0]
793*da0073e9SAndroid Build Coastguard Worker
794*da0073e9SAndroid Build Coastguard Worker    def comp_time(self, compiler, df):
795*da0073e9SAndroid Build Coastguard Worker        df = self.get_passing_entries(compiler, df)
796*da0073e9SAndroid Build Coastguard Worker        # df = df.sort_values(by=compiler, ascending=False)[compiler][: self.bottom_k]
797*da0073e9SAndroid Build Coastguard Worker        if df.empty:
798*da0073e9SAndroid Build Coastguard Worker            return "0.0"
799*da0073e9SAndroid Build Coastguard Worker
800*da0073e9SAndroid Build Coastguard Worker        return f"{df.mean():.2f}"
801*da0073e9SAndroid Build Coastguard Worker
802*da0073e9SAndroid Build Coastguard Worker    def geomean(self, compiler, df):
803*da0073e9SAndroid Build Coastguard Worker        cleaned_df = self.get_passing_entries(compiler, df)
804*da0073e9SAndroid Build Coastguard Worker        if not self.include_slowdowns:
805*da0073e9SAndroid Build Coastguard Worker            cleaned_df = cleaned_df.clip(1)
806*da0073e9SAndroid Build Coastguard Worker        if cleaned_df.empty:
807*da0073e9SAndroid Build Coastguard Worker            return "0.0x"
808*da0073e9SAndroid Build Coastguard Worker        return f"{gmean(cleaned_df):.2f}x"
809*da0073e9SAndroid Build Coastguard Worker
810*da0073e9SAndroid Build Coastguard Worker    def passrate(self, compiler, df):
811*da0073e9SAndroid Build Coastguard Worker        total = len(df.index)
812*da0073e9SAndroid Build Coastguard Worker        passing = df[df[compiler] > 0.0][compiler].count()
813*da0073e9SAndroid Build Coastguard Worker        perc = int(percentage(passing, total, decimals=0))
814*da0073e9SAndroid Build Coastguard Worker        return f"{perc}%, {passing}/{total}"
815*da0073e9SAndroid Build Coastguard Worker
816*da0073e9SAndroid Build Coastguard Worker    def memory(self, compiler, df):
817*da0073e9SAndroid Build Coastguard Worker        df = self.get_passing_entries(compiler, df)
818*da0073e9SAndroid Build Coastguard Worker        df = df.fillna(0)
819*da0073e9SAndroid Build Coastguard Worker        df = df[df > 0]
820*da0073e9SAndroid Build Coastguard Worker        if df.empty:
821*da0073e9SAndroid Build Coastguard Worker            return "0.0x"
822*da0073e9SAndroid Build Coastguard Worker        return f"{df.mean():.2f}x"
823*da0073e9SAndroid Build Coastguard Worker
824*da0073e9SAndroid Build Coastguard Worker    def exec_summary_df(self, fn, metric):
825*da0073e9SAndroid Build Coastguard Worker        """
826*da0073e9SAndroid Build Coastguard Worker        Generate a table with passrate and geomean perf
827*da0073e9SAndroid Build Coastguard Worker        """
828*da0073e9SAndroid Build Coastguard Worker        cols = {}
829*da0073e9SAndroid Build Coastguard Worker        cols["Compiler"] = self.compilers
830*da0073e9SAndroid Build Coastguard Worker        for suite in self.suites:
831*da0073e9SAndroid Build Coastguard Worker            df = self.parsed_frames[suite][metric]
832*da0073e9SAndroid Build Coastguard Worker            # speedups = [self.geomean(compiler, df) for compiler in self.compilers]
833*da0073e9SAndroid Build Coastguard Worker            speedups = [fn(compiler, df) for compiler in self.compilers]
834*da0073e9SAndroid Build Coastguard Worker            col = pd.Series(data=speedups, index=self.compilers)
835*da0073e9SAndroid Build Coastguard Worker            cols[suite] = col
836*da0073e9SAndroid Build Coastguard Worker        df = pd.DataFrame(cols)
837*da0073e9SAndroid Build Coastguard Worker        df = df.fillna(0)
838*da0073e9SAndroid Build Coastguard Worker        df.to_csv(os.path.join(self.output_dir, f"{fn.__name__}.csv"))
839*da0073e9SAndroid Build Coastguard Worker        return df
840*da0073e9SAndroid Build Coastguard Worker
841*da0073e9SAndroid Build Coastguard Worker    def exec_summary_text(self, caption, fn, metric):
842*da0073e9SAndroid Build Coastguard Worker        df = self.exec_summary_df(fn, metric)
843*da0073e9SAndroid Build Coastguard Worker        tabform = tabulate(df, headers="keys", tablefmt="pretty", showindex="never")
844*da0073e9SAndroid Build Coastguard Worker
845*da0073e9SAndroid Build Coastguard Worker        str_io = io.StringIO()
846*da0073e9SAndroid Build Coastguard Worker        str_io.write(f"{caption}")
847*da0073e9SAndroid Build Coastguard Worker        str_io.write("~~~\n")
848*da0073e9SAndroid Build Coastguard Worker        str_io.write(f"{tabform}\n")
849*da0073e9SAndroid Build Coastguard Worker        str_io.write("~~~\n")
850*da0073e9SAndroid Build Coastguard Worker        return str_io.getvalue()
851*da0073e9SAndroid Build Coastguard Worker
852*da0073e9SAndroid Build Coastguard Worker    def generate_executive_summary(self):
853*da0073e9SAndroid Build Coastguard Worker        machine = "A100 GPUs"
854*da0073e9SAndroid Build Coastguard Worker        if "cpu" in self.devices:
855*da0073e9SAndroid Build Coastguard Worker            get_machine_cmd = "lscpu| grep 'Model name' | awk -F':' '{print $2}'"
856*da0073e9SAndroid Build Coastguard Worker            machine = subprocess.getstatusoutput(get_machine_cmd)[1].strip()
857*da0073e9SAndroid Build Coastguard Worker        description = (
858*da0073e9SAndroid Build Coastguard Worker            "We evaluate different backends "
859*da0073e9SAndroid Build Coastguard Worker            "across three benchmark suites - torchbench, huggingface and timm. We run "
860*da0073e9SAndroid Build Coastguard Worker            "these experiments on "
861*da0073e9SAndroid Build Coastguard Worker            + machine
862*da0073e9SAndroid Build Coastguard Worker            + ". Each experiment runs one iteration of forward pass "
863*da0073e9SAndroid Build Coastguard Worker            "and backward pass for training and forward pass only for inference. "
864*da0073e9SAndroid Build Coastguard Worker            "For accuracy, we check the numerical correctness of forward pass outputs and gradients "
865*da0073e9SAndroid Build Coastguard Worker            "by comparing with native pytorch. We measure speedup "
866*da0073e9SAndroid Build Coastguard Worker            "by normalizing against the performance of native pytorch. We report mean "
867*da0073e9SAndroid Build Coastguard Worker            "compilation latency numbers and peak memory footprint reduction ratio. \n\n"
868*da0073e9SAndroid Build Coastguard Worker            "Caveats\n"
869*da0073e9SAndroid Build Coastguard Worker            "1) Batch size has been reduced to workaround OOM errors. Work is in progress to "
870*da0073e9SAndroid Build Coastguard Worker            "reduce peak memory footprint.\n"
871*da0073e9SAndroid Build Coastguard Worker            "2) Experiments do not cover dynamic shapes.\n"
872*da0073e9SAndroid Build Coastguard Worker            "3) Experimental setup does not have optimizer.\n\n"
873*da0073e9SAndroid Build Coastguard Worker        )
874*da0073e9SAndroid Build Coastguard Worker        comment = generate_dropdown_comment("", description)
875*da0073e9SAndroid Build Coastguard Worker        str_io = io.StringIO()
876*da0073e9SAndroid Build Coastguard Worker        str_io.write("\n")
877*da0073e9SAndroid Build Coastguard Worker        str_io.write("## Executive Summary ##\n")
878*da0073e9SAndroid Build Coastguard Worker        str_io.write(comment)
879*da0073e9SAndroid Build Coastguard Worker
880*da0073e9SAndroid Build Coastguard Worker        speedup_caption = "Geometric mean speedup \n"
881*da0073e9SAndroid Build Coastguard Worker        speedup_summary = self.exec_summary_text(
882*da0073e9SAndroid Build Coastguard Worker            speedup_caption, self.geomean, "speedup"
883*da0073e9SAndroid Build Coastguard Worker        )
884*da0073e9SAndroid Build Coastguard Worker
885*da0073e9SAndroid Build Coastguard Worker        passrate_caption = "Passrate\n"
886*da0073e9SAndroid Build Coastguard Worker        passrate_summary = self.exec_summary_text(
887*da0073e9SAndroid Build Coastguard Worker            passrate_caption, self.passrate, "speedup"
888*da0073e9SAndroid Build Coastguard Worker        )
889*da0073e9SAndroid Build Coastguard Worker
890*da0073e9SAndroid Build Coastguard Worker        comp_time_caption = "Mean compilation time (seconds)\n"
891*da0073e9SAndroid Build Coastguard Worker        comp_time_summary = self.exec_summary_text(
892*da0073e9SAndroid Build Coastguard Worker            comp_time_caption, self.comp_time, "compilation_latency"
893*da0073e9SAndroid Build Coastguard Worker        )
894*da0073e9SAndroid Build Coastguard Worker
895*da0073e9SAndroid Build Coastguard Worker        peak_memory_caption = (
896*da0073e9SAndroid Build Coastguard Worker            "Peak memory footprint compression ratio (higher is better)\n"
897*da0073e9SAndroid Build Coastguard Worker        )
898*da0073e9SAndroid Build Coastguard Worker        peak_memory_summary = self.exec_summary_text(
899*da0073e9SAndroid Build Coastguard Worker            peak_memory_caption, self.memory, "compression_ratio"
900*da0073e9SAndroid Build Coastguard Worker        )
901*da0073e9SAndroid Build Coastguard Worker
902*da0073e9SAndroid Build Coastguard Worker        str_io.write(
903*da0073e9SAndroid Build Coastguard Worker            "To measure performance, compilation latency and memory footprint reduction, "
904*da0073e9SAndroid Build Coastguard Worker            "we remove the models that fail accuracy checks.\n\n"
905*da0073e9SAndroid Build Coastguard Worker        )
906*da0073e9SAndroid Build Coastguard Worker        str_io.write(passrate_summary)
907*da0073e9SAndroid Build Coastguard Worker        str_io.write(speedup_summary)
908*da0073e9SAndroid Build Coastguard Worker        str_io.write(comp_time_summary)
909*da0073e9SAndroid Build Coastguard Worker        str_io.write(peak_memory_summary)
910*da0073e9SAndroid Build Coastguard Worker        self.executive_summary = str_io.getvalue()
911*da0073e9SAndroid Build Coastguard Worker
912*da0073e9SAndroid Build Coastguard Worker    def flag_bad_entries(self, suite, metric, flag_fn):
913*da0073e9SAndroid Build Coastguard Worker        df = self.untouched_parsed_frames[suite][metric]
914*da0073e9SAndroid Build Coastguard Worker        df = df.drop("dev", axis=1)
915*da0073e9SAndroid Build Coastguard Worker        df = df.rename(columns={"batch_size": "bs"})
916*da0073e9SAndroid Build Coastguard Worker        # apply flag_fn elementwise to flag_compilers columns,
917*da0073e9SAndroid Build Coastguard Worker        # if one element fails, the entire row is flagged
918*da0073e9SAndroid Build Coastguard Worker        flag = np.logical_or.reduce(
919*da0073e9SAndroid Build Coastguard Worker            df[self.flag_compilers].applymap(flag_fn),
920*da0073e9SAndroid Build Coastguard Worker            axis=1,
921*da0073e9SAndroid Build Coastguard Worker        )
922*da0073e9SAndroid Build Coastguard Worker        df = df[flag]
923*da0073e9SAndroid Build Coastguard Worker        df = df.assign(suite=suite)
924*da0073e9SAndroid Build Coastguard Worker        return df.reindex(columns=["suite", "name"] + self.flag_compilers)
925*da0073e9SAndroid Build Coastguard Worker
926*da0073e9SAndroid Build Coastguard Worker    def generate_warnings(self):
927*da0073e9SAndroid Build Coastguard Worker        title = "## Warnings ##"
928*da0073e9SAndroid Build Coastguard Worker        body = (
929*da0073e9SAndroid Build Coastguard Worker            "We flag models where:\n\n"
930*da0073e9SAndroid Build Coastguard Worker            " - accuracy fails\n"
931*da0073e9SAndroid Build Coastguard Worker            " - speedup < 0.95x (NOTE: 0.0 speedup typically signifies a failure in the performance test)\n"
932*da0073e9SAndroid Build Coastguard Worker            " - compilation latency > 120 sec.\n"
933*da0073e9SAndroid Build Coastguard Worker            " - compression ratio < 0.9\n"
934*da0073e9SAndroid Build Coastguard Worker            "\n"
935*da0073e9SAndroid Build Coastguard Worker        )
936*da0073e9SAndroid Build Coastguard Worker        for metric in [
937*da0073e9SAndroid Build Coastguard Worker            "accuracy",
938*da0073e9SAndroid Build Coastguard Worker            "speedup",
939*da0073e9SAndroid Build Coastguard Worker            "compilation_latency",
940*da0073e9SAndroid Build Coastguard Worker            "compression_ratio",
941*da0073e9SAndroid Build Coastguard Worker        ]:
942*da0073e9SAndroid Build Coastguard Worker            dfs = []
943*da0073e9SAndroid Build Coastguard Worker            for suite in self.suites:
944*da0073e9SAndroid Build Coastguard Worker                dfs.append(self.flag_bad_entries(suite, metric, FLAG_FNS[metric]))
945*da0073e9SAndroid Build Coastguard Worker            df = pd.concat(dfs, axis=0)
946*da0073e9SAndroid Build Coastguard Worker            if df.empty:
947*da0073e9SAndroid Build Coastguard Worker                continue
948*da0073e9SAndroid Build Coastguard Worker            tabform = tabulate(df, headers="keys", tablefmt="pretty", showindex="never")
949*da0073e9SAndroid Build Coastguard Worker            str_io = io.StringIO()
950*da0073e9SAndroid Build Coastguard Worker            str_io.write("\n")
951*da0073e9SAndroid Build Coastguard Worker            str_io.write(get_metric_title(metric) + " warnings\n")
952*da0073e9SAndroid Build Coastguard Worker            str_io.write("~~~\n")
953*da0073e9SAndroid Build Coastguard Worker            str_io.write(f"{tabform}\n")
954*da0073e9SAndroid Build Coastguard Worker            str_io.write("~~~\n")
955*da0073e9SAndroid Build Coastguard Worker            body += str_io.getvalue()
956*da0073e9SAndroid Build Coastguard Worker
957*da0073e9SAndroid Build Coastguard Worker        comment = generate_dropdown_comment(title, body)
958*da0073e9SAndroid Build Coastguard Worker        return comment
959*da0073e9SAndroid Build Coastguard Worker
960*da0073e9SAndroid Build Coastguard Worker    def prepare_message(self, suite):
961*da0073e9SAndroid Build Coastguard Worker        title = f"## {suite} suite with {self.dtypes[0]} precision ##"
962*da0073e9SAndroid Build Coastguard Worker        body = ""
963*da0073e9SAndroid Build Coastguard Worker        for metric in [
964*da0073e9SAndroid Build Coastguard Worker            "speedup",
965*da0073e9SAndroid Build Coastguard Worker            "accuracy",
966*da0073e9SAndroid Build Coastguard Worker            "compilation_latency",
967*da0073e9SAndroid Build Coastguard Worker            "compression_ratio",
968*da0073e9SAndroid Build Coastguard Worker            "abs_latency",
969*da0073e9SAndroid Build Coastguard Worker        ]:
970*da0073e9SAndroid Build Coastguard Worker            df = self.untouched_parsed_frames[suite][metric]
971*da0073e9SAndroid Build Coastguard Worker            df = df.drop("dev", axis=1)
972*da0073e9SAndroid Build Coastguard Worker            df = df.rename(columns={"batch_size": "bs"})
973*da0073e9SAndroid Build Coastguard Worker            tabform = tabulate(df, headers="keys", tablefmt="pretty", showindex="never")
974*da0073e9SAndroid Build Coastguard Worker            str_io = io.StringIO()
975*da0073e9SAndroid Build Coastguard Worker            str_io.write("\n")
976*da0073e9SAndroid Build Coastguard Worker            str_io.write(get_metric_title(metric) + "\n")
977*da0073e9SAndroid Build Coastguard Worker            str_io.write("~~~\n")
978*da0073e9SAndroid Build Coastguard Worker            str_io.write(f"{tabform}\n")
979*da0073e9SAndroid Build Coastguard Worker            str_io.write("~~~\n")
980*da0073e9SAndroid Build Coastguard Worker            body += str_io.getvalue()
981*da0073e9SAndroid Build Coastguard Worker
982*da0073e9SAndroid Build Coastguard Worker        comment = generate_dropdown_comment(title, body)
983*da0073e9SAndroid Build Coastguard Worker        return comment
984*da0073e9SAndroid Build Coastguard Worker
985*da0073e9SAndroid Build Coastguard Worker    def gen_summary_files(self):
986*da0073e9SAndroid Build Coastguard Worker        self.generate_executive_summary()
987*da0073e9SAndroid Build Coastguard Worker        for suite in self.suites:
988*da0073e9SAndroid Build Coastguard Worker            self.plot_graph(
989*da0073e9SAndroid Build Coastguard Worker                self.untouched_parsed_frames[suite]["speedup"],
990*da0073e9SAndroid Build Coastguard Worker                f"{suite}_{self.dtypes[0]}",
991*da0073e9SAndroid Build Coastguard Worker            )
992*da0073e9SAndroid Build Coastguard Worker
993*da0073e9SAndroid Build Coastguard Worker        with open(f"{self.output_dir}/gh_title.txt", "w") as gh_fh:
994*da0073e9SAndroid Build Coastguard Worker            str_io = io.StringIO()
995*da0073e9SAndroid Build Coastguard Worker            str_io.write("\n")
996*da0073e9SAndroid Build Coastguard Worker            str_io.write(f"# Performance Dashboard for {self.dtypes[0]} precision ##\n")
997*da0073e9SAndroid Build Coastguard Worker            str_io.write("\n")
998*da0073e9SAndroid Build Coastguard Worker            gh_fh.write(str_io.getvalue())
999*da0073e9SAndroid Build Coastguard Worker
1000*da0073e9SAndroid Build Coastguard Worker        with open(f"{self.output_dir}/gh_executive_summary.txt", "w") as gh_fh:
1001*da0073e9SAndroid Build Coastguard Worker            gh_fh.write(self.executive_summary)
1002*da0073e9SAndroid Build Coastguard Worker
1003*da0073e9SAndroid Build Coastguard Worker        with open(f"{self.output_dir}/gh_warnings.txt", "w") as gh_fh:
1004*da0073e9SAndroid Build Coastguard Worker            warnings_body = self.generate_warnings()
1005*da0073e9SAndroid Build Coastguard Worker            gh_fh.write(warnings_body)
1006*da0073e9SAndroid Build Coastguard Worker
1007*da0073e9SAndroid Build Coastguard Worker        str_io = io.StringIO()
1008*da0073e9SAndroid Build Coastguard Worker        for suite in self.suites:
1009*da0073e9SAndroid Build Coastguard Worker            str_io.write(self.prepare_message(suite))
1010*da0073e9SAndroid Build Coastguard Worker        str_io.write("\n")
1011*da0073e9SAndroid Build Coastguard Worker        with open(f"{self.output_dir}/gh_{self.mode}.txt", "w") as gh_fh:
1012*da0073e9SAndroid Build Coastguard Worker            gh_fh.write(str_io.getvalue())
1013*da0073e9SAndroid Build Coastguard Worker
1014*da0073e9SAndroid Build Coastguard Worker
1015*da0073e9SAndroid Build Coastguard Workerdef parse_logs(args, dtypes, suites, devices, compilers, flag_compilers, output_dir):
1016*da0073e9SAndroid Build Coastguard Worker    mode = get_mode(args)
1017*da0073e9SAndroid Build Coastguard Worker    build_summary(args)
1018*da0073e9SAndroid Build Coastguard Worker    include_slowdowns = args.include_slowdowns
1019*da0073e9SAndroid Build Coastguard Worker
1020*da0073e9SAndroid Build Coastguard Worker    parser_class = ParsePerformanceLogs
1021*da0073e9SAndroid Build Coastguard Worker    parser = parser_class(
1022*da0073e9SAndroid Build Coastguard Worker        suites,
1023*da0073e9SAndroid Build Coastguard Worker        devices,
1024*da0073e9SAndroid Build Coastguard Worker        dtypes,
1025*da0073e9SAndroid Build Coastguard Worker        compilers,
1026*da0073e9SAndroid Build Coastguard Worker        flag_compilers,
1027*da0073e9SAndroid Build Coastguard Worker        mode,
1028*da0073e9SAndroid Build Coastguard Worker        output_dir,
1029*da0073e9SAndroid Build Coastguard Worker        include_slowdowns,
1030*da0073e9SAndroid Build Coastguard Worker    )
1031*da0073e9SAndroid Build Coastguard Worker    parser.gen_summary_files()
1032*da0073e9SAndroid Build Coastguard Worker    return
1033*da0073e9SAndroid Build Coastguard Worker
1034*da0073e9SAndroid Build Coastguard Worker
1035*da0073e9SAndroid Build Coastguard Worker@dataclasses.dataclass
1036*da0073e9SAndroid Build Coastguard Workerclass LogInfo:
1037*da0073e9SAndroid Build Coastguard Worker    # Day of the year this log was generated
1038*da0073e9SAndroid Build Coastguard Worker    day: str
1039*da0073e9SAndroid Build Coastguard Worker
1040*da0073e9SAndroid Build Coastguard Worker    # Directory path where all logs are present
1041*da0073e9SAndroid Build Coastguard Worker    dir_path: str
1042*da0073e9SAndroid Build Coastguard Worker
1043*da0073e9SAndroid Build Coastguard Worker
1044*da0073e9SAndroid Build Coastguard Workerdef get_date(log_info):
1045*da0073e9SAndroid Build Coastguard Worker    return datetime.strptime(f"{log_info.day}", "%j").strftime("%m-%d")
1046*da0073e9SAndroid Build Coastguard Worker
1047*da0073e9SAndroid Build Coastguard Worker
1048*da0073e9SAndroid Build Coastguard Workerdef find_last_2_with_filenames(lookup_file, dashboard_archive_path, dtype, filenames):
1049*da0073e9SAndroid Build Coastguard Worker    df = pd.read_csv(lookup_file, names=("day", "mode", "prec", "path"))
1050*da0073e9SAndroid Build Coastguard Worker    df = df[df["mode"] == "performance"]
1051*da0073e9SAndroid Build Coastguard Worker    df = df[df["prec"] == dtype]
1052*da0073e9SAndroid Build Coastguard Worker    df = df[::-1]
1053*da0073e9SAndroid Build Coastguard Worker    last2 = []
1054*da0073e9SAndroid Build Coastguard Worker    for path in df["path"]:
1055*da0073e9SAndroid Build Coastguard Worker        output_dir = os.path.join(dashboard_archive_path, path)
1056*da0073e9SAndroid Build Coastguard Worker        fullpaths = [
1057*da0073e9SAndroid Build Coastguard Worker            os.path.join(dashboard_archive_path, path, name) for name in filenames
1058*da0073e9SAndroid Build Coastguard Worker        ]
1059*da0073e9SAndroid Build Coastguard Worker        if all(os.path.exists(fullpath) for fullpath in fullpaths):
1060*da0073e9SAndroid Build Coastguard Worker            last2.append(output_dir)
1061*da0073e9SAndroid Build Coastguard Worker        if len(last2) >= 2:
1062*da0073e9SAndroid Build Coastguard Worker            return last2
1063*da0073e9SAndroid Build Coastguard Worker    return None
1064*da0073e9SAndroid Build Coastguard Worker
1065*da0073e9SAndroid Build Coastguard Worker
1066*da0073e9SAndroid Build Coastguard Workerclass SummaryStatDiffer:
1067*da0073e9SAndroid Build Coastguard Worker    def __init__(self, args):
1068*da0073e9SAndroid Build Coastguard Worker        self.args = args
1069*da0073e9SAndroid Build Coastguard Worker        self.lookup_file = os.path.join(self.args.dashboard_archive_path, "lookup.csv")
1070*da0073e9SAndroid Build Coastguard Worker        assert os.path.exists(self.lookup_file)
1071*da0073e9SAndroid Build Coastguard Worker
1072*da0073e9SAndroid Build Coastguard Worker    def generate_diff(self, last2, filename, caption):
1073*da0073e9SAndroid Build Coastguard Worker        df_cur, df_prev = (pd.read_csv(os.path.join(path, filename)) for path in last2)
1074*da0073e9SAndroid Build Coastguard Worker        df_merge = df_cur.merge(df_prev, on="Compiler", suffixes=("_cur", "_prev"))
1075*da0073e9SAndroid Build Coastguard Worker        data = {col: [] for col in ("compiler", "suite", "prev_value", "cur_value")}
1076*da0073e9SAndroid Build Coastguard Worker        for _, row in df_merge.iterrows():
1077*da0073e9SAndroid Build Coastguard Worker            if row["Compiler"] in self.args.flag_compilers:
1078*da0073e9SAndroid Build Coastguard Worker                for suite in self.args.suites:
1079*da0073e9SAndroid Build Coastguard Worker                    if suite + "_prev" not in row or suite + "_cur" not in row:
1080*da0073e9SAndroid Build Coastguard Worker                        continue
1081*da0073e9SAndroid Build Coastguard Worker                    data["compiler"].append(row["Compiler"])
1082*da0073e9SAndroid Build Coastguard Worker                    data["suite"].append(suite)
1083*da0073e9SAndroid Build Coastguard Worker                    data["prev_value"].append(row[suite + "_prev"])
1084*da0073e9SAndroid Build Coastguard Worker                    data["cur_value"].append(row[suite + "_cur"])
1085*da0073e9SAndroid Build Coastguard Worker
1086*da0073e9SAndroid Build Coastguard Worker        df = pd.DataFrame(data)
1087*da0073e9SAndroid Build Coastguard Worker        tabform = tabulate(df, headers="keys", tablefmt="pretty", showindex="never")
1088*da0073e9SAndroid Build Coastguard Worker        str_io = io.StringIO()
1089*da0073e9SAndroid Build Coastguard Worker        str_io.write("\n")
1090*da0073e9SAndroid Build Coastguard Worker        str_io.write(f"{caption}\n")
1091*da0073e9SAndroid Build Coastguard Worker        str_io.write("~~~\n")
1092*da0073e9SAndroid Build Coastguard Worker        str_io.write(f"{tabform}\n")
1093*da0073e9SAndroid Build Coastguard Worker        str_io.write("~~~\n")
1094*da0073e9SAndroid Build Coastguard Worker        return str_io.getvalue()
1095*da0073e9SAndroid Build Coastguard Worker
1096*da0073e9SAndroid Build Coastguard Worker    def generate_comment(self):
1097*da0073e9SAndroid Build Coastguard Worker        title = "## Summary Statistics Diff ##\n"
1098*da0073e9SAndroid Build Coastguard Worker        body = (
1099*da0073e9SAndroid Build Coastguard Worker            "For each relevant compiler, we compare the summary statistics "
1100*da0073e9SAndroid Build Coastguard Worker            "for the most 2 recent reports that actually run the compiler.\n\n"
1101*da0073e9SAndroid Build Coastguard Worker        )
1102*da0073e9SAndroid Build Coastguard Worker        dtype = self.args.dtypes[0]
1103*da0073e9SAndroid Build Coastguard Worker        last2 = find_last_2_with_filenames(
1104*da0073e9SAndroid Build Coastguard Worker            self.lookup_file,
1105*da0073e9SAndroid Build Coastguard Worker            self.args.dashboard_archive_path,
1106*da0073e9SAndroid Build Coastguard Worker            dtype,
1107*da0073e9SAndroid Build Coastguard Worker            ["geomean.csv", "passrate.csv"],
1108*da0073e9SAndroid Build Coastguard Worker        )
1109*da0073e9SAndroid Build Coastguard Worker
1110*da0073e9SAndroid Build Coastguard Worker        if last2 is None:
1111*da0073e9SAndroid Build Coastguard Worker            body += "Could not find most 2 recent reports.\n\n"
1112*da0073e9SAndroid Build Coastguard Worker        else:
1113*da0073e9SAndroid Build Coastguard Worker            for state, path in zip(("Current", "Previous"), last2):
1114*da0073e9SAndroid Build Coastguard Worker                body += f"{state} report name: {path}\n\n"
1115*da0073e9SAndroid Build Coastguard Worker            body += self.generate_diff(last2, "passrate.csv", "Passrate diff")
1116*da0073e9SAndroid Build Coastguard Worker            body += self.generate_diff(
1117*da0073e9SAndroid Build Coastguard Worker                last2, "geomean.csv", "Geometric mean speedup diff"
1118*da0073e9SAndroid Build Coastguard Worker            )
1119*da0073e9SAndroid Build Coastguard Worker
1120*da0073e9SAndroid Build Coastguard Worker        comment = generate_dropdown_comment(title, body)
1121*da0073e9SAndroid Build Coastguard Worker
1122*da0073e9SAndroid Build Coastguard Worker        with open(f"{self.args.output_dir}/gh_summary_diff.txt", "w") as gh_fh:
1123*da0073e9SAndroid Build Coastguard Worker            gh_fh.write(comment)
1124*da0073e9SAndroid Build Coastguard Worker
1125*da0073e9SAndroid Build Coastguard Worker
1126*da0073e9SAndroid Build Coastguard Workerclass RegressionDetector:
1127*da0073e9SAndroid Build Coastguard Worker    """
1128*da0073e9SAndroid Build Coastguard Worker    Compares the most recent 2 benchmarks to find previously unflagged models
1129*da0073e9SAndroid Build Coastguard Worker    that are now flagged.
1130*da0073e9SAndroid Build Coastguard Worker    """
1131*da0073e9SAndroid Build Coastguard Worker
1132*da0073e9SAndroid Build Coastguard Worker    def __init__(self, args):
1133*da0073e9SAndroid Build Coastguard Worker        self.args = args
1134*da0073e9SAndroid Build Coastguard Worker        self.lookup_file = os.path.join(self.args.dashboard_archive_path, "lookup.csv")
1135*da0073e9SAndroid Build Coastguard Worker        assert os.path.exists(self.lookup_file)
1136*da0073e9SAndroid Build Coastguard Worker
1137*da0073e9SAndroid Build Coastguard Worker    def generate_comment(self):
1138*da0073e9SAndroid Build Coastguard Worker        title = "## Recent Regressions ##\n"
1139*da0073e9SAndroid Build Coastguard Worker        body = (
1140*da0073e9SAndroid Build Coastguard Worker            "For each relevant compiler, we compare the most recent 2 reports "
1141*da0073e9SAndroid Build Coastguard Worker            "(that actually run the compiler) to find previously unflagged "
1142*da0073e9SAndroid Build Coastguard Worker            "models that are now flagged as problematic (according to the "
1143*da0073e9SAndroid Build Coastguard Worker            "'Warnings' section).\n\n"
1144*da0073e9SAndroid Build Coastguard Worker        )
1145*da0073e9SAndroid Build Coastguard Worker        dtype = self.args.dtypes[0]
1146*da0073e9SAndroid Build Coastguard Worker        device = self.args.devices[0]
1147*da0073e9SAndroid Build Coastguard Worker        for suite in self.args.suites:
1148*da0073e9SAndroid Build Coastguard Worker            body += f"### Regressions for {suite} ###\n"
1149*da0073e9SAndroid Build Coastguard Worker            last2 = {}
1150*da0073e9SAndroid Build Coastguard Worker
1151*da0073e9SAndroid Build Coastguard Worker            for compiler in self.args.flag_compilers:
1152*da0073e9SAndroid Build Coastguard Worker                filenames = [
1153*da0073e9SAndroid Build Coastguard Worker                    generate_csv_name(
1154*da0073e9SAndroid Build Coastguard Worker                        self.args, dtype, suite, device, compiler, testing
1155*da0073e9SAndroid Build Coastguard Worker                    )
1156*da0073e9SAndroid Build Coastguard Worker                    for testing in ["performance", "accuracy"]
1157*da0073e9SAndroid Build Coastguard Worker                ]
1158*da0073e9SAndroid Build Coastguard Worker                compiler_last2 = find_last_2_with_filenames(
1159*da0073e9SAndroid Build Coastguard Worker                    self.lookup_file, self.args.dashboard_archive_path, dtype, filenames
1160*da0073e9SAndroid Build Coastguard Worker                )
1161*da0073e9SAndroid Build Coastguard Worker                if compiler_last2 is not None:
1162*da0073e9SAndroid Build Coastguard Worker                    last2[compiler] = [
1163*da0073e9SAndroid Build Coastguard Worker                        ParsePerformanceLogs(
1164*da0073e9SAndroid Build Coastguard Worker                            [suite],
1165*da0073e9SAndroid Build Coastguard Worker                            [device],
1166*da0073e9SAndroid Build Coastguard Worker                            [dtype],
1167*da0073e9SAndroid Build Coastguard Worker                            [compiler],
1168*da0073e9SAndroid Build Coastguard Worker                            [compiler],
1169*da0073e9SAndroid Build Coastguard Worker                            get_mode(self.args),
1170*da0073e9SAndroid Build Coastguard Worker                            output_dir,
1171*da0073e9SAndroid Build Coastguard Worker                        )
1172*da0073e9SAndroid Build Coastguard Worker                        for output_dir in compiler_last2
1173*da0073e9SAndroid Build Coastguard Worker                    ]
1174*da0073e9SAndroid Build Coastguard Worker                    for state, path in zip(("Current", "Previous"), compiler_last2):
1175*da0073e9SAndroid Build Coastguard Worker                        body += (
1176*da0073e9SAndroid Build Coastguard Worker                            f"{state} report name (compiler: {compiler}, "
1177*da0073e9SAndroid Build Coastguard Worker                            f"suite: {suite}): {path}\n\n"
1178*da0073e9SAndroid Build Coastguard Worker                        )
1179*da0073e9SAndroid Build Coastguard Worker
1180*da0073e9SAndroid Build Coastguard Worker            regressions_present = False
1181*da0073e9SAndroid Build Coastguard Worker            for metric in [
1182*da0073e9SAndroid Build Coastguard Worker                "accuracy",
1183*da0073e9SAndroid Build Coastguard Worker                "speedup",
1184*da0073e9SAndroid Build Coastguard Worker                "compilation_latency",
1185*da0073e9SAndroid Build Coastguard Worker                "compression_ratio",
1186*da0073e9SAndroid Build Coastguard Worker            ]:
1187*da0073e9SAndroid Build Coastguard Worker                dfs = []
1188*da0073e9SAndroid Build Coastguard Worker                for compiler in self.args.flag_compilers:
1189*da0073e9SAndroid Build Coastguard Worker                    if last2[compiler] is None:
1190*da0073e9SAndroid Build Coastguard Worker                        continue
1191*da0073e9SAndroid Build Coastguard Worker
1192*da0073e9SAndroid Build Coastguard Worker                    df_cur, df_prev = (
1193*da0073e9SAndroid Build Coastguard Worker                        last2[compiler][i].untouched_parsed_frames[suite][metric]
1194*da0073e9SAndroid Build Coastguard Worker                        for i in (0, 1)
1195*da0073e9SAndroid Build Coastguard Worker                    )
1196*da0073e9SAndroid Build Coastguard Worker                    df_merge = df_cur.merge(
1197*da0073e9SAndroid Build Coastguard Worker                        df_prev, on="name", suffixes=("_cur", "_prev")
1198*da0073e9SAndroid Build Coastguard Worker                    )
1199*da0073e9SAndroid Build Coastguard Worker                    flag_fn = FLAG_FNS[metric]
1200*da0073e9SAndroid Build Coastguard Worker                    flag = np.logical_and(
1201*da0073e9SAndroid Build Coastguard Worker                        df_merge[compiler + "_prev"].apply(
1202*da0073e9SAndroid Build Coastguard Worker                            lambda x: not pd.isna(x) and not flag_fn(x)
1203*da0073e9SAndroid Build Coastguard Worker                        ),
1204*da0073e9SAndroid Build Coastguard Worker                        df_merge[compiler + "_cur"].apply(
1205*da0073e9SAndroid Build Coastguard Worker                            lambda x: not pd.isna(x) and flag_fn(x)
1206*da0073e9SAndroid Build Coastguard Worker                        ),
1207*da0073e9SAndroid Build Coastguard Worker                    )
1208*da0073e9SAndroid Build Coastguard Worker                    df_bad = df_merge[flag]
1209*da0073e9SAndroid Build Coastguard Worker                    dfs.append(
1210*da0073e9SAndroid Build Coastguard Worker                        pd.DataFrame(
1211*da0073e9SAndroid Build Coastguard Worker                            data={
1212*da0073e9SAndroid Build Coastguard Worker                                "compiler": compiler,
1213*da0073e9SAndroid Build Coastguard Worker                                "name": df_bad["name"],
1214*da0073e9SAndroid Build Coastguard Worker                                "prev_status": df_bad[compiler + "_prev"],
1215*da0073e9SAndroid Build Coastguard Worker                                "cur_status": df_bad[compiler + "_cur"],
1216*da0073e9SAndroid Build Coastguard Worker                            }
1217*da0073e9SAndroid Build Coastguard Worker                        )
1218*da0073e9SAndroid Build Coastguard Worker                    )
1219*da0073e9SAndroid Build Coastguard Worker
1220*da0073e9SAndroid Build Coastguard Worker                if not dfs:
1221*da0073e9SAndroid Build Coastguard Worker                    continue
1222*da0073e9SAndroid Build Coastguard Worker                df = pd.concat(dfs, axis=0)
1223*da0073e9SAndroid Build Coastguard Worker                if df.empty:
1224*da0073e9SAndroid Build Coastguard Worker                    continue
1225*da0073e9SAndroid Build Coastguard Worker                regressions_present = True
1226*da0073e9SAndroid Build Coastguard Worker                tabform = tabulate(
1227*da0073e9SAndroid Build Coastguard Worker                    df, headers="keys", tablefmt="pretty", showindex="never"
1228*da0073e9SAndroid Build Coastguard Worker                )
1229*da0073e9SAndroid Build Coastguard Worker                str_io = io.StringIO()
1230*da0073e9SAndroid Build Coastguard Worker                str_io.write("\n")
1231*da0073e9SAndroid Build Coastguard Worker                str_io.write(f"{get_metric_title(metric)} regressions\n")
1232*da0073e9SAndroid Build Coastguard Worker                str_io.write("~~~\n")
1233*da0073e9SAndroid Build Coastguard Worker                str_io.write(f"{tabform}\n")
1234*da0073e9SAndroid Build Coastguard Worker                str_io.write("~~~\n")
1235*da0073e9SAndroid Build Coastguard Worker                body += str_io.getvalue()
1236*da0073e9SAndroid Build Coastguard Worker
1237*da0073e9SAndroid Build Coastguard Worker            if not regressions_present:
1238*da0073e9SAndroid Build Coastguard Worker                body += "No regressions found.\n"
1239*da0073e9SAndroid Build Coastguard Worker
1240*da0073e9SAndroid Build Coastguard Worker        comment = generate_dropdown_comment(title, body)
1241*da0073e9SAndroid Build Coastguard Worker
1242*da0073e9SAndroid Build Coastguard Worker        with open(f"{self.args.output_dir}/gh_metric_regression.txt", "w") as gh_fh:
1243*da0073e9SAndroid Build Coastguard Worker            gh_fh.write(comment)
1244*da0073e9SAndroid Build Coastguard Worker
1245*da0073e9SAndroid Build Coastguard Worker
1246*da0073e9SAndroid Build Coastguard Workerclass RegressionTracker:
1247*da0073e9SAndroid Build Coastguard Worker    """
1248*da0073e9SAndroid Build Coastguard Worker    Plots progress of different metrics over time to detect regressions.
1249*da0073e9SAndroid Build Coastguard Worker    """
1250*da0073e9SAndroid Build Coastguard Worker
1251*da0073e9SAndroid Build Coastguard Worker    def __init__(self, args):
1252*da0073e9SAndroid Build Coastguard Worker        self.args = args
1253*da0073e9SAndroid Build Coastguard Worker        self.suites = self.args.suites
1254*da0073e9SAndroid Build Coastguard Worker        self.lookup_file = os.path.join(self.args.dashboard_archive_path, "lookup.csv")
1255*da0073e9SAndroid Build Coastguard Worker        assert os.path.exists(self.lookup_file)
1256*da0073e9SAndroid Build Coastguard Worker        self.k = 10
1257*da0073e9SAndroid Build Coastguard Worker
1258*da0073e9SAndroid Build Coastguard Worker    def find_last_k(self):
1259*da0073e9SAndroid Build Coastguard Worker        """
1260*da0073e9SAndroid Build Coastguard Worker        Find the last k pairs of (day number, log_path)
1261*da0073e9SAndroid Build Coastguard Worker        """
1262*da0073e9SAndroid Build Coastguard Worker        dtype = self.args.dtypes[0]
1263*da0073e9SAndroid Build Coastguard Worker        df = pd.read_csv(self.lookup_file, names=("day", "mode", "prec", "path"))
1264*da0073e9SAndroid Build Coastguard Worker        df = df[df["mode"] == "performance"]
1265*da0073e9SAndroid Build Coastguard Worker        df = df[df["prec"] == dtype]
1266*da0073e9SAndroid Build Coastguard Worker        log_infos = []
1267*da0073e9SAndroid Build Coastguard Worker        for day, path in zip(df["day"], df["path"]):
1268*da0073e9SAndroid Build Coastguard Worker            log_infos.append(LogInfo(day, path))
1269*da0073e9SAndroid Build Coastguard Worker
1270*da0073e9SAndroid Build Coastguard Worker        assert len(log_infos) >= self.k
1271*da0073e9SAndroid Build Coastguard Worker        log_infos = log_infos[len(log_infos) - self.k :]
1272*da0073e9SAndroid Build Coastguard Worker        return log_infos
1273*da0073e9SAndroid Build Coastguard Worker
1274*da0073e9SAndroid Build Coastguard Worker    def generate_comment(self):
1275*da0073e9SAndroid Build Coastguard Worker        title = "## Metrics over time ##\n"
1276*da0073e9SAndroid Build Coastguard Worker        str_io = io.StringIO()
1277*da0073e9SAndroid Build Coastguard Worker        if not self.args.update_dashboard_test and not self.args.no_graphs:
1278*da0073e9SAndroid Build Coastguard Worker            for name in glob.glob(self.args.output_dir + "/*over_time.png"):
1279*da0073e9SAndroid Build Coastguard Worker                output = (
1280*da0073e9SAndroid Build Coastguard Worker                    subprocess.check_output([self.args.dashboard_image_uploader, name])
1281*da0073e9SAndroid Build Coastguard Worker                    .decode("ascii")
1282*da0073e9SAndroid Build Coastguard Worker                    .rstrip()
1283*da0073e9SAndroid Build Coastguard Worker                )
1284*da0073e9SAndroid Build Coastguard Worker                str_io.write(f"\n{name} : ![]({output})\n")
1285*da0073e9SAndroid Build Coastguard Worker        comment = generate_dropdown_comment(title, str_io.getvalue())
1286*da0073e9SAndroid Build Coastguard Worker
1287*da0073e9SAndroid Build Coastguard Worker        with open(f"{self.args.output_dir}/gh_regression.txt", "w") as gh_fh:
1288*da0073e9SAndroid Build Coastguard Worker            gh_fh.write(comment)
1289*da0073e9SAndroid Build Coastguard Worker
1290*da0073e9SAndroid Build Coastguard Worker    def diff(self):
1291*da0073e9SAndroid Build Coastguard Worker        log_infos = self.find_last_k()
1292*da0073e9SAndroid Build Coastguard Worker
1293*da0073e9SAndroid Build Coastguard Worker        for metric in ["geomean", "passrate", "comp_time", "memory"]:
1294*da0073e9SAndroid Build Coastguard Worker            fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(15, 5))
1295*da0073e9SAndroid Build Coastguard Worker            for idx, suite in enumerate(self.suites):
1296*da0073e9SAndroid Build Coastguard Worker                dfs = []
1297*da0073e9SAndroid Build Coastguard Worker                for log_info in log_infos:
1298*da0073e9SAndroid Build Coastguard Worker                    dir_path = os.path.join(
1299*da0073e9SAndroid Build Coastguard Worker                        self.args.dashboard_archive_path, log_info.dir_path
1300*da0073e9SAndroid Build Coastguard Worker                    )
1301*da0073e9SAndroid Build Coastguard Worker                    assert os.path.exists(dir_path)
1302*da0073e9SAndroid Build Coastguard Worker                    gmean_filename = os.path.join(dir_path, f"{metric}.csv")
1303*da0073e9SAndroid Build Coastguard Worker                    if not os.path.exists(gmean_filename):
1304*da0073e9SAndroid Build Coastguard Worker                        continue
1305*da0073e9SAndroid Build Coastguard Worker                    df = pd.read_csv(gmean_filename)
1306*da0073e9SAndroid Build Coastguard Worker                    if suite not in df:
1307*da0073e9SAndroid Build Coastguard Worker                        continue
1308*da0073e9SAndroid Build Coastguard Worker                    if metric == "geomean" or metric == "memory":
1309*da0073e9SAndroid Build Coastguard Worker                        df[suite] = df[suite].str.replace("x", "").astype(float)
1310*da0073e9SAndroid Build Coastguard Worker                    elif metric == "passrate":
1311*da0073e9SAndroid Build Coastguard Worker                        df[suite] = df[suite].str.split("%").str[0].astype(float)
1312*da0073e9SAndroid Build Coastguard Worker                    df.insert(0, "day", get_date(log_info))
1313*da0073e9SAndroid Build Coastguard Worker                    df = df.pivot(index="day", columns="Compiler", values=suite)
1314*da0073e9SAndroid Build Coastguard Worker
1315*da0073e9SAndroid Build Coastguard Worker                    # Interim stage when both inductor_cudagraphs and inductor exist
1316*da0073e9SAndroid Build Coastguard Worker                    df = df.rename(columns={"inductor_cudagraphs": "inductor"})
1317*da0073e9SAndroid Build Coastguard Worker                    for col_name in df.columns:
1318*da0073e9SAndroid Build Coastguard Worker                        if col_name not in self.args.compilers:
1319*da0073e9SAndroid Build Coastguard Worker                            df = df.drop(columns=[col_name])
1320*da0073e9SAndroid Build Coastguard Worker                    dfs.append(df)
1321*da0073e9SAndroid Build Coastguard Worker
1322*da0073e9SAndroid Build Coastguard Worker                df = pd.concat(dfs)
1323*da0073e9SAndroid Build Coastguard Worker                df = df.interpolate(method="linear")
1324*da0073e9SAndroid Build Coastguard Worker                ax = df.plot(
1325*da0073e9SAndroid Build Coastguard Worker                    ax=axes[idx],
1326*da0073e9SAndroid Build Coastguard Worker                    kind="line",
1327*da0073e9SAndroid Build Coastguard Worker                    ylabel=metric,
1328*da0073e9SAndroid Build Coastguard Worker                    xlabel="Date",
1329*da0073e9SAndroid Build Coastguard Worker                    grid=True,
1330*da0073e9SAndroid Build Coastguard Worker                    ylim=0 if metric == "passrate" else 0.8,
1331*da0073e9SAndroid Build Coastguard Worker                    title=suite,
1332*da0073e9SAndroid Build Coastguard Worker                    style=".-",
1333*da0073e9SAndroid Build Coastguard Worker                    legend=False,
1334*da0073e9SAndroid Build Coastguard Worker                )
1335*da0073e9SAndroid Build Coastguard Worker                ax.legend(loc="lower right", ncol=2)
1336*da0073e9SAndroid Build Coastguard Worker
1337*da0073e9SAndroid Build Coastguard Worker            plt.tight_layout()
1338*da0073e9SAndroid Build Coastguard Worker            plt.savefig(os.path.join(output_dir, f"{metric}_over_time.png"))
1339*da0073e9SAndroid Build Coastguard Worker
1340*da0073e9SAndroid Build Coastguard Worker        self.generate_comment()
1341*da0073e9SAndroid Build Coastguard Worker
1342*da0073e9SAndroid Build Coastguard Worker
1343*da0073e9SAndroid Build Coastguard Workerclass DashboardUpdater:
1344*da0073e9SAndroid Build Coastguard Worker    """
1345*da0073e9SAndroid Build Coastguard Worker    Aggregates the information and makes a comment to Performance Dashboard.
1346*da0073e9SAndroid Build Coastguard Worker    https://github.com/pytorch/torchdynamo/issues/681
1347*da0073e9SAndroid Build Coastguard Worker    """
1348*da0073e9SAndroid Build Coastguard Worker
1349*da0073e9SAndroid Build Coastguard Worker    def __init__(self, args):
1350*da0073e9SAndroid Build Coastguard Worker        self.args = args
1351*da0073e9SAndroid Build Coastguard Worker        self.output_dir = args.output_dir
1352*da0073e9SAndroid Build Coastguard Worker        self.lookup_file = os.path.join(self.args.dashboard_archive_path, "lookup.csv")
1353*da0073e9SAndroid Build Coastguard Worker        assert os.path.exists(self.lookup_file)
1354*da0073e9SAndroid Build Coastguard Worker        try:
1355*da0073e9SAndroid Build Coastguard Worker            if not self.args.update_dashboard_test and not self.args.no_update_archive:
1356*da0073e9SAndroid Build Coastguard Worker                self.update_lookup_file()
1357*da0073e9SAndroid Build Coastguard Worker        except subprocess.CalledProcessError:
1358*da0073e9SAndroid Build Coastguard Worker            sys.stderr.write("failed to update lookup file\n")
1359*da0073e9SAndroid Build Coastguard Worker
1360*da0073e9SAndroid Build Coastguard Worker    def update_lookup_file(self):
1361*da0073e9SAndroid Build Coastguard Worker        dtype = self.args.dtypes[0]
1362*da0073e9SAndroid Build Coastguard Worker        day, _ = archive_data(self.args.archive_name)
1363*da0073e9SAndroid Build Coastguard Worker        target_dir = get_archive_name(self.args, dtype)
1364*da0073e9SAndroid Build Coastguard Worker        # Update lookup csv the folder to arhived logs
1365*da0073e9SAndroid Build Coastguard Worker        subprocess.check_call(
1366*da0073e9SAndroid Build Coastguard Worker            f'echo "{day},performance,{dtype},{target_dir}" >> {self.lookup_file}',
1367*da0073e9SAndroid Build Coastguard Worker            shell=True,
1368*da0073e9SAndroid Build Coastguard Worker        )
1369*da0073e9SAndroid Build Coastguard Worker
1370*da0073e9SAndroid Build Coastguard Worker    def archive(self):
1371*da0073e9SAndroid Build Coastguard Worker        dtype = self.args.dtypes[0]
1372*da0073e9SAndroid Build Coastguard Worker        # Copy the folder to archived location
1373*da0073e9SAndroid Build Coastguard Worker        archive(
1374*da0073e9SAndroid Build Coastguard Worker            self.output_dir,
1375*da0073e9SAndroid Build Coastguard Worker            self.args.dashboard_archive_path,
1376*da0073e9SAndroid Build Coastguard Worker            self.args.archive_name,
1377*da0073e9SAndroid Build Coastguard Worker            dtype,
1378*da0073e9SAndroid Build Coastguard Worker        )
1379*da0073e9SAndroid Build Coastguard Worker
1380*da0073e9SAndroid Build Coastguard Worker    def upload_graphs(self):
1381*da0073e9SAndroid Build Coastguard Worker        title = "## Performance graphs ##\n"
1382*da0073e9SAndroid Build Coastguard Worker        str_io = io.StringIO()
1383*da0073e9SAndroid Build Coastguard Worker        if not self.args.update_dashboard_test and not self.args.no_graphs:
1384*da0073e9SAndroid Build Coastguard Worker            for name in glob.glob(self.output_dir + "/*png"):
1385*da0073e9SAndroid Build Coastguard Worker                if "over_time" not in name:
1386*da0073e9SAndroid Build Coastguard Worker                    output = (
1387*da0073e9SAndroid Build Coastguard Worker                        subprocess.check_output(
1388*da0073e9SAndroid Build Coastguard Worker                            [self.args.dashboard_image_uploader, name]
1389*da0073e9SAndroid Build Coastguard Worker                        )
1390*da0073e9SAndroid Build Coastguard Worker                        .decode("ascii")
1391*da0073e9SAndroid Build Coastguard Worker                        .rstrip()
1392*da0073e9SAndroid Build Coastguard Worker                    )
1393*da0073e9SAndroid Build Coastguard Worker                    str_io.write(f"\n{name} : ![]({output})\n")
1394*da0073e9SAndroid Build Coastguard Worker        comment = generate_dropdown_comment(title, str_io.getvalue())
1395*da0073e9SAndroid Build Coastguard Worker
1396*da0073e9SAndroid Build Coastguard Worker        with open(f"{self.output_dir}/gh_graphs.txt", "w") as gh_fh:
1397*da0073e9SAndroid Build Coastguard Worker            gh_fh.write(comment)
1398*da0073e9SAndroid Build Coastguard Worker
1399*da0073e9SAndroid Build Coastguard Worker    def gen_comment(self):
1400*da0073e9SAndroid Build Coastguard Worker        files = [
1401*da0073e9SAndroid Build Coastguard Worker            "gh_title.txt",
1402*da0073e9SAndroid Build Coastguard Worker            "gh_executive_summary.txt",
1403*da0073e9SAndroid Build Coastguard Worker            "gh_summary_diff.txt",
1404*da0073e9SAndroid Build Coastguard Worker            "gh_warnings.txt",
1405*da0073e9SAndroid Build Coastguard Worker            "gh_regression.txt",
1406*da0073e9SAndroid Build Coastguard Worker            "gh_metric_regression.txt",
1407*da0073e9SAndroid Build Coastguard Worker            "gh_training.txt" if self.args.training else "gh_inference.txt",
1408*da0073e9SAndroid Build Coastguard Worker            "gh_graphs.txt",
1409*da0073e9SAndroid Build Coastguard Worker            "gh_build_summary.txt",
1410*da0073e9SAndroid Build Coastguard Worker        ]
1411*da0073e9SAndroid Build Coastguard Worker        all_lines = []
1412*da0073e9SAndroid Build Coastguard Worker        for f in files:
1413*da0073e9SAndroid Build Coastguard Worker            try:
1414*da0073e9SAndroid Build Coastguard Worker                with open(os.path.join(self.output_dir, f)) as fh:
1415*da0073e9SAndroid Build Coastguard Worker                    all_lines.extend(fh.readlines())
1416*da0073e9SAndroid Build Coastguard Worker            except FileNotFoundError:
1417*da0073e9SAndroid Build Coastguard Worker                pass
1418*da0073e9SAndroid Build Coastguard Worker
1419*da0073e9SAndroid Build Coastguard Worker        return "\n".join([x.rstrip() for x in all_lines])
1420*da0073e9SAndroid Build Coastguard Worker
1421*da0073e9SAndroid Build Coastguard Worker    def comment_on_gh(self, comment):
1422*da0073e9SAndroid Build Coastguard Worker        """
1423*da0073e9SAndroid Build Coastguard Worker        Send a commment to dashboard
1424*da0073e9SAndroid Build Coastguard Worker        """
1425*da0073e9SAndroid Build Coastguard Worker        with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
1426*da0073e9SAndroid Build Coastguard Worker            f.write(comment)
1427*da0073e9SAndroid Build Coastguard Worker            filename = f.name
1428*da0073e9SAndroid Build Coastguard Worker
1429*da0073e9SAndroid Build Coastguard Worker        issue_number = "93794"
1430*da0073e9SAndroid Build Coastguard Worker        if self.args.dtypes[0] == "float32":
1431*da0073e9SAndroid Build Coastguard Worker            issue_number = "93518"
1432*da0073e9SAndroid Build Coastguard Worker
1433*da0073e9SAndroid Build Coastguard Worker        subprocess.check_call(
1434*da0073e9SAndroid Build Coastguard Worker            [
1435*da0073e9SAndroid Build Coastguard Worker                self.args.dashboard_gh_cli_path,
1436*da0073e9SAndroid Build Coastguard Worker                "issue",
1437*da0073e9SAndroid Build Coastguard Worker                "comment",
1438*da0073e9SAndroid Build Coastguard Worker                "--repo=https://github.com/pytorch/pytorch.git",
1439*da0073e9SAndroid Build Coastguard Worker                issue_number,
1440*da0073e9SAndroid Build Coastguard Worker                "-F",
1441*da0073e9SAndroid Build Coastguard Worker                filename,
1442*da0073e9SAndroid Build Coastguard Worker            ]
1443*da0073e9SAndroid Build Coastguard Worker        )
1444*da0073e9SAndroid Build Coastguard Worker
1445*da0073e9SAndroid Build Coastguard Worker        os.remove(filename)
1446*da0073e9SAndroid Build Coastguard Worker
1447*da0073e9SAndroid Build Coastguard Worker    def update(self):
1448*da0073e9SAndroid Build Coastguard Worker        self.upload_graphs()
1449*da0073e9SAndroid Build Coastguard Worker        if not self.args.no_detect_regressions:
1450*da0073e9SAndroid Build Coastguard Worker            SummaryStatDiffer(self.args).generate_comment()
1451*da0073e9SAndroid Build Coastguard Worker            RegressionDetector(self.args).generate_comment()
1452*da0073e9SAndroid Build Coastguard Worker            try:
1453*da0073e9SAndroid Build Coastguard Worker                RegressionTracker(self.args).diff()
1454*da0073e9SAndroid Build Coastguard Worker            except Exception as e:
1455*da0073e9SAndroid Build Coastguard Worker                logging.exception("")
1456*da0073e9SAndroid Build Coastguard Worker                with open(f"{self.args.output_dir}/gh_regression.txt", "w") as gh_fh:
1457*da0073e9SAndroid Build Coastguard Worker                    gh_fh.write("")
1458*da0073e9SAndroid Build Coastguard Worker
1459*da0073e9SAndroid Build Coastguard Worker        comment = self.gen_comment()
1460*da0073e9SAndroid Build Coastguard Worker        print(comment)
1461*da0073e9SAndroid Build Coastguard Worker
1462*da0073e9SAndroid Build Coastguard Worker        if not self.args.update_dashboard_test:
1463*da0073e9SAndroid Build Coastguard Worker            if not self.args.no_gh_comment:
1464*da0073e9SAndroid Build Coastguard Worker                self.comment_on_gh(comment)
1465*da0073e9SAndroid Build Coastguard Worker            if not self.args.no_update_archive:
1466*da0073e9SAndroid Build Coastguard Worker                self.archive()
1467*da0073e9SAndroid Build Coastguard Worker
1468*da0073e9SAndroid Build Coastguard Worker
1469*da0073e9SAndroid Build Coastguard Workerif __name__ == "__main__":
1470*da0073e9SAndroid Build Coastguard Worker    args = parse_args()
1471*da0073e9SAndroid Build Coastguard Worker
1472*da0073e9SAndroid Build Coastguard Worker    def extract(key):
1473*da0073e9SAndroid Build Coastguard Worker        return DEFAULTS[key] if getattr(args, key, None) is None else getattr(args, key)
1474*da0073e9SAndroid Build Coastguard Worker
1475*da0073e9SAndroid Build Coastguard Worker    dtypes = extract("dtypes")
1476*da0073e9SAndroid Build Coastguard Worker    suites = extract("suites")
1477*da0073e9SAndroid Build Coastguard Worker    devices = extract("devices")
1478*da0073e9SAndroid Build Coastguard Worker
1479*da0073e9SAndroid Build Coastguard Worker    if args.inference:
1480*da0073e9SAndroid Build Coastguard Worker        compilers = DEFAULTS["inference"] if args.compilers is None else args.compilers
1481*da0073e9SAndroid Build Coastguard Worker        flag_compilers = (
1482*da0073e9SAndroid Build Coastguard Worker            DEFAULTS["flag_compilers"]["inference"]
1483*da0073e9SAndroid Build Coastguard Worker            if args.flag_compilers is None
1484*da0073e9SAndroid Build Coastguard Worker            else args.flag_compilers
1485*da0073e9SAndroid Build Coastguard Worker        )
1486*da0073e9SAndroid Build Coastguard Worker    else:
1487*da0073e9SAndroid Build Coastguard Worker        assert args.training
1488*da0073e9SAndroid Build Coastguard Worker        compilers = DEFAULTS["training"] if args.compilers is None else args.compilers
1489*da0073e9SAndroid Build Coastguard Worker        flag_compilers = (
1490*da0073e9SAndroid Build Coastguard Worker            DEFAULTS["flag_compilers"]["training"]
1491*da0073e9SAndroid Build Coastguard Worker            if args.flag_compilers is None
1492*da0073e9SAndroid Build Coastguard Worker            else args.flag_compilers
1493*da0073e9SAndroid Build Coastguard Worker        )
1494*da0073e9SAndroid Build Coastguard Worker
1495*da0073e9SAndroid Build Coastguard Worker    output_dir = args.output_dir
1496*da0073e9SAndroid Build Coastguard Worker    args.compilers = compilers
1497*da0073e9SAndroid Build Coastguard Worker    args.devices = devices
1498*da0073e9SAndroid Build Coastguard Worker    args.dtypes = dtypes
1499*da0073e9SAndroid Build Coastguard Worker    flag_compilers = list(set(flag_compilers) & set(compilers))
1500*da0073e9SAndroid Build Coastguard Worker    args.flag_compilers = flag_compilers
1501*da0073e9SAndroid Build Coastguard Worker    args.suites = suites
1502*da0073e9SAndroid Build Coastguard Worker
1503*da0073e9SAndroid Build Coastguard Worker    if args.print_run_commands:
1504*da0073e9SAndroid Build Coastguard Worker        generated_file = generate_commands(
1505*da0073e9SAndroid Build Coastguard Worker            args, dtypes, suites, devices, compilers, output_dir
1506*da0073e9SAndroid Build Coastguard Worker        )
1507*da0073e9SAndroid Build Coastguard Worker        print(
1508*da0073e9SAndroid Build Coastguard Worker            f"Running commands are generated in file {generated_file}. Please run (bash {generated_file})."
1509*da0073e9SAndroid Build Coastguard Worker        )
1510*da0073e9SAndroid Build Coastguard Worker    elif args.visualize_logs:
1511*da0073e9SAndroid Build Coastguard Worker        parse_logs(args, dtypes, suites, devices, compilers, flag_compilers, output_dir)
1512*da0073e9SAndroid Build Coastguard Worker    elif args.run:
1513*da0073e9SAndroid Build Coastguard Worker        generated_file = generate_commands(
1514*da0073e9SAndroid Build Coastguard Worker            args, dtypes, suites, devices, compilers, output_dir
1515*da0073e9SAndroid Build Coastguard Worker        )
1516*da0073e9SAndroid Build Coastguard Worker        # generate memoized archive name now so that the date is reflective
1517*da0073e9SAndroid Build Coastguard Worker        # of when the run started
1518*da0073e9SAndroid Build Coastguard Worker        get_archive_name(args, dtypes[0])
1519*da0073e9SAndroid Build Coastguard Worker        # TODO - Do we need to worry about segfaults
1520*da0073e9SAndroid Build Coastguard Worker        try:
1521*da0073e9SAndroid Build Coastguard Worker            os.system(f"bash {generated_file}")
1522*da0073e9SAndroid Build Coastguard Worker        except Exception as e:
1523*da0073e9SAndroid Build Coastguard Worker            print(
1524*da0073e9SAndroid Build Coastguard Worker                f"Running commands failed. Please run manually (bash {generated_file}) and inspect the errors."
1525*da0073e9SAndroid Build Coastguard Worker            )
1526*da0073e9SAndroid Build Coastguard Worker            raise e
1527*da0073e9SAndroid Build Coastguard Worker        if not args.log_operator_inputs:
1528*da0073e9SAndroid Build Coastguard Worker            if not args.no_update_archive:
1529*da0073e9SAndroid Build Coastguard Worker                archive(
1530*da0073e9SAndroid Build Coastguard Worker                    output_dir,
1531*da0073e9SAndroid Build Coastguard Worker                    args.dashboard_archive_path,
1532*da0073e9SAndroid Build Coastguard Worker                    args.archive_name,
1533*da0073e9SAndroid Build Coastguard Worker                    dtypes[0],
1534*da0073e9SAndroid Build Coastguard Worker                )
1535*da0073e9SAndroid Build Coastguard Worker            parse_logs(
1536*da0073e9SAndroid Build Coastguard Worker                args, dtypes, suites, devices, compilers, flag_compilers, output_dir
1537*da0073e9SAndroid Build Coastguard Worker            )
1538*da0073e9SAndroid Build Coastguard Worker            if not args.no_update_archive:
1539*da0073e9SAndroid Build Coastguard Worker                archive(
1540*da0073e9SAndroid Build Coastguard Worker                    output_dir,
1541*da0073e9SAndroid Build Coastguard Worker                    args.dashboard_archive_path,
1542*da0073e9SAndroid Build Coastguard Worker                    args.archive_name,
1543*da0073e9SAndroid Build Coastguard Worker                    dtypes[0],
1544*da0073e9SAndroid Build Coastguard Worker                )
1545*da0073e9SAndroid Build Coastguard Worker
1546*da0073e9SAndroid Build Coastguard Worker    if args.update_dashboard:
1547*da0073e9SAndroid Build Coastguard Worker        DashboardUpdater(args).update()
1548