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