xref: /aosp_15_r20/external/pytorch/benchmarks/upload_scribe.py (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1*da0073e9SAndroid Build Coastguard Worker"""Scribe Uploader for Pytorch Benchmark Data
2*da0073e9SAndroid Build Coastguard Worker
3*da0073e9SAndroid Build Coastguard WorkerCurrently supports data in pytest-benchmark format but can be extended.
4*da0073e9SAndroid Build Coastguard Worker
5*da0073e9SAndroid Build Coastguard WorkerNew fields can be added just by modifying the schema in this file, schema
6*da0073e9SAndroid Build Coastguard Workerchecking is only here to encourage reusing existing fields and avoiding typos.
7*da0073e9SAndroid Build Coastguard Worker"""
8*da0073e9SAndroid Build Coastguard Worker
9*da0073e9SAndroid Build Coastguard Workerimport argparse
10*da0073e9SAndroid Build Coastguard Workerimport json
11*da0073e9SAndroid Build Coastguard Workerimport os
12*da0073e9SAndroid Build Coastguard Workerimport subprocess
13*da0073e9SAndroid Build Coastguard Workerimport time
14*da0073e9SAndroid Build Coastguard Workerfrom collections import defaultdict
15*da0073e9SAndroid Build Coastguard Worker
16*da0073e9SAndroid Build Coastguard Workerimport requests
17*da0073e9SAndroid Build Coastguard Worker
18*da0073e9SAndroid Build Coastguard Worker
19*da0073e9SAndroid Build Coastguard Workerclass ScribeUploader:
20*da0073e9SAndroid Build Coastguard Worker    def __init__(self, category):
21*da0073e9SAndroid Build Coastguard Worker        self.category = category
22*da0073e9SAndroid Build Coastguard Worker
23*da0073e9SAndroid Build Coastguard Worker    def format_message(self, field_dict):
24*da0073e9SAndroid Build Coastguard Worker        assert "time" in field_dict, "Missing required Scribe field 'time'"
25*da0073e9SAndroid Build Coastguard Worker        message = defaultdict(dict)
26*da0073e9SAndroid Build Coastguard Worker        for field, value in field_dict.items():
27*da0073e9SAndroid Build Coastguard Worker            if field in self.schema["normal"]:
28*da0073e9SAndroid Build Coastguard Worker                message["normal"][field] = str(value)
29*da0073e9SAndroid Build Coastguard Worker            elif field in self.schema["int"]:
30*da0073e9SAndroid Build Coastguard Worker                message["int"][field] = int(value)
31*da0073e9SAndroid Build Coastguard Worker            elif field in self.schema["float"]:
32*da0073e9SAndroid Build Coastguard Worker                message["float"][field] = float(value)
33*da0073e9SAndroid Build Coastguard Worker            else:
34*da0073e9SAndroid Build Coastguard Worker                raise ValueError(
35*da0073e9SAndroid Build Coastguard Worker                    f"Field {field} is not currently used, be intentional about adding new fields"
36*da0073e9SAndroid Build Coastguard Worker                )
37*da0073e9SAndroid Build Coastguard Worker        return message
38*da0073e9SAndroid Build Coastguard Worker
39*da0073e9SAndroid Build Coastguard Worker    def _upload_intern(self, messages):
40*da0073e9SAndroid Build Coastguard Worker        for m in messages:
41*da0073e9SAndroid Build Coastguard Worker            json_str = json.dumps(m)
42*da0073e9SAndroid Build Coastguard Worker            cmd = ["scribe_cat", self.category, json_str]
43*da0073e9SAndroid Build Coastguard Worker            subprocess.run(cmd)
44*da0073e9SAndroid Build Coastguard Worker
45*da0073e9SAndroid Build Coastguard Worker    def upload(self, messages):
46*da0073e9SAndroid Build Coastguard Worker        if os.environ.get("SCRIBE_INTERN"):
47*da0073e9SAndroid Build Coastguard Worker            return self._upload_intern(messages)
48*da0073e9SAndroid Build Coastguard Worker        access_token = os.environ.get("SCRIBE_GRAPHQL_ACCESS_TOKEN")
49*da0073e9SAndroid Build Coastguard Worker        if not access_token:
50*da0073e9SAndroid Build Coastguard Worker            raise ValueError("Can't find access token from environment variable")
51*da0073e9SAndroid Build Coastguard Worker        url = "https://graph.facebook.com/scribe_logs"
52*da0073e9SAndroid Build Coastguard Worker        r = requests.post(
53*da0073e9SAndroid Build Coastguard Worker            url,
54*da0073e9SAndroid Build Coastguard Worker            data={
55*da0073e9SAndroid Build Coastguard Worker                "access_token": access_token,
56*da0073e9SAndroid Build Coastguard Worker                "logs": json.dumps(
57*da0073e9SAndroid Build Coastguard Worker                    [
58*da0073e9SAndroid Build Coastguard Worker                        {
59*da0073e9SAndroid Build Coastguard Worker                            "category": self.category,
60*da0073e9SAndroid Build Coastguard Worker                            "message": json.dumps(message),
61*da0073e9SAndroid Build Coastguard Worker                            "line_escape": False,
62*da0073e9SAndroid Build Coastguard Worker                        }
63*da0073e9SAndroid Build Coastguard Worker                        for message in messages
64*da0073e9SAndroid Build Coastguard Worker                    ]
65*da0073e9SAndroid Build Coastguard Worker                ),
66*da0073e9SAndroid Build Coastguard Worker            },
67*da0073e9SAndroid Build Coastguard Worker        )
68*da0073e9SAndroid Build Coastguard Worker        print(r.text)
69*da0073e9SAndroid Build Coastguard Worker        r.raise_for_status()
70*da0073e9SAndroid Build Coastguard Worker
71*da0073e9SAndroid Build Coastguard Worker
72*da0073e9SAndroid Build Coastguard Workerclass PytorchBenchmarkUploader(ScribeUploader):
73*da0073e9SAndroid Build Coastguard Worker    def __init__(self):
74*da0073e9SAndroid Build Coastguard Worker        super().__init__("perfpipe_pytorch_benchmarks")
75*da0073e9SAndroid Build Coastguard Worker        self.schema = {
76*da0073e9SAndroid Build Coastguard Worker            "int": [
77*da0073e9SAndroid Build Coastguard Worker                "time",
78*da0073e9SAndroid Build Coastguard Worker                "rounds",
79*da0073e9SAndroid Build Coastguard Worker            ],
80*da0073e9SAndroid Build Coastguard Worker            "normal": [
81*da0073e9SAndroid Build Coastguard Worker                "benchmark_group",
82*da0073e9SAndroid Build Coastguard Worker                "benchmark_name",
83*da0073e9SAndroid Build Coastguard Worker                "benchmark_executor",
84*da0073e9SAndroid Build Coastguard Worker                "benchmark_fuser",
85*da0073e9SAndroid Build Coastguard Worker                "benchmark_class",
86*da0073e9SAndroid Build Coastguard Worker                "benchmark_time",
87*da0073e9SAndroid Build Coastguard Worker                "pytorch_commit_id",
88*da0073e9SAndroid Build Coastguard Worker                "pytorch_branch",
89*da0073e9SAndroid Build Coastguard Worker                "pytorch_commit_time",
90*da0073e9SAndroid Build Coastguard Worker                "pytorch_version",
91*da0073e9SAndroid Build Coastguard Worker                "pytorch_git_dirty",
92*da0073e9SAndroid Build Coastguard Worker                "machine_kernel",
93*da0073e9SAndroid Build Coastguard Worker                "machine_processor",
94*da0073e9SAndroid Build Coastguard Worker                "machine_hostname",
95*da0073e9SAndroid Build Coastguard Worker                "circle_build_num",
96*da0073e9SAndroid Build Coastguard Worker                "circle_project_reponame",
97*da0073e9SAndroid Build Coastguard Worker            ],
98*da0073e9SAndroid Build Coastguard Worker            "float": [
99*da0073e9SAndroid Build Coastguard Worker                "stddev",
100*da0073e9SAndroid Build Coastguard Worker                "min",
101*da0073e9SAndroid Build Coastguard Worker                "median",
102*da0073e9SAndroid Build Coastguard Worker                "max",
103*da0073e9SAndroid Build Coastguard Worker                "mean",
104*da0073e9SAndroid Build Coastguard Worker            ],
105*da0073e9SAndroid Build Coastguard Worker        }
106*da0073e9SAndroid Build Coastguard Worker
107*da0073e9SAndroid Build Coastguard Worker    def post_pytest_benchmarks(self, pytest_json):
108*da0073e9SAndroid Build Coastguard Worker        machine_info = pytest_json["machine_info"]
109*da0073e9SAndroid Build Coastguard Worker        commit_info = pytest_json["commit_info"]
110*da0073e9SAndroid Build Coastguard Worker        upload_time = int(time.time())
111*da0073e9SAndroid Build Coastguard Worker        messages = []
112*da0073e9SAndroid Build Coastguard Worker        for b in pytest_json["benchmarks"]:
113*da0073e9SAndroid Build Coastguard Worker            test = b["name"].split("[")[0]
114*da0073e9SAndroid Build Coastguard Worker            net_name = b["params"]["net_name"]
115*da0073e9SAndroid Build Coastguard Worker            benchmark_name = f"{test}[{net_name}]"
116*da0073e9SAndroid Build Coastguard Worker            executor = b["params"]["executor"]
117*da0073e9SAndroid Build Coastguard Worker            fuser = b["params"]["fuser"]
118*da0073e9SAndroid Build Coastguard Worker            m = self.format_message(
119*da0073e9SAndroid Build Coastguard Worker                {
120*da0073e9SAndroid Build Coastguard Worker                    "time": upload_time,
121*da0073e9SAndroid Build Coastguard Worker                    "benchmark_group": b["group"],
122*da0073e9SAndroid Build Coastguard Worker                    "benchmark_name": benchmark_name,
123*da0073e9SAndroid Build Coastguard Worker                    "benchmark_executor": executor,
124*da0073e9SAndroid Build Coastguard Worker                    "benchmark_fuser": fuser,
125*da0073e9SAndroid Build Coastguard Worker                    "benchmark_class": b["fullname"],
126*da0073e9SAndroid Build Coastguard Worker                    "benchmark_time": pytest_json["datetime"],
127*da0073e9SAndroid Build Coastguard Worker                    "pytorch_commit_id": commit_info["id"],
128*da0073e9SAndroid Build Coastguard Worker                    "pytorch_branch": commit_info["branch"],
129*da0073e9SAndroid Build Coastguard Worker                    "pytorch_commit_time": commit_info["time"],
130*da0073e9SAndroid Build Coastguard Worker                    "pytorch_version": None,
131*da0073e9SAndroid Build Coastguard Worker                    "pytorch_git_dirty": commit_info["dirty"],
132*da0073e9SAndroid Build Coastguard Worker                    "machine_kernel": machine_info["release"],
133*da0073e9SAndroid Build Coastguard Worker                    "machine_processor": machine_info["processor"],
134*da0073e9SAndroid Build Coastguard Worker                    "machine_hostname": machine_info["node"],
135*da0073e9SAndroid Build Coastguard Worker                    "circle_build_num": os.environ.get("CIRCLE_BUILD_NUM"),
136*da0073e9SAndroid Build Coastguard Worker                    "circle_project_reponame": os.environ.get(
137*da0073e9SAndroid Build Coastguard Worker                        "CIRCLE_PROJECT_REPONAME"
138*da0073e9SAndroid Build Coastguard Worker                    ),
139*da0073e9SAndroid Build Coastguard Worker                    "stddev": b["stats"]["stddev"],
140*da0073e9SAndroid Build Coastguard Worker                    "rounds": b["stats"]["rounds"],
141*da0073e9SAndroid Build Coastguard Worker                    "min": b["stats"]["min"],
142*da0073e9SAndroid Build Coastguard Worker                    "median": b["stats"]["median"],
143*da0073e9SAndroid Build Coastguard Worker                    "max": b["stats"]["max"],
144*da0073e9SAndroid Build Coastguard Worker                    "mean": b["stats"]["mean"],
145*da0073e9SAndroid Build Coastguard Worker                }
146*da0073e9SAndroid Build Coastguard Worker            )
147*da0073e9SAndroid Build Coastguard Worker            messages.append(m)
148*da0073e9SAndroid Build Coastguard Worker        self.upload(messages)
149*da0073e9SAndroid Build Coastguard Worker
150*da0073e9SAndroid Build Coastguard Worker
151*da0073e9SAndroid Build Coastguard Workerif __name__ == "__main__":
152*da0073e9SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser(description=__doc__)
153*da0073e9SAndroid Build Coastguard Worker    parser.add_argument(
154*da0073e9SAndroid Build Coastguard Worker        "--pytest-bench-json",
155*da0073e9SAndroid Build Coastguard Worker        "--pytest_bench_json",
156*da0073e9SAndroid Build Coastguard Worker        type=argparse.FileType("r"),
157*da0073e9SAndroid Build Coastguard Worker        help="Upload json data formatted by pytest-benchmark module",
158*da0073e9SAndroid Build Coastguard Worker    )
159*da0073e9SAndroid Build Coastguard Worker    args = parser.parse_args()
160*da0073e9SAndroid Build Coastguard Worker    if args.pytest_bench_json:
161*da0073e9SAndroid Build Coastguard Worker        benchmark_uploader = PytorchBenchmarkUploader()
162*da0073e9SAndroid Build Coastguard Worker        json_data = json.load(args.pytest_bench_json)
163*da0073e9SAndroid Build Coastguard Worker        benchmark_uploader.post_pytest_benchmarks(json_data)
164