| """Scribe Uploader for Pytorch Benchmark Data | |
| Currently supports data in pytest-benchmark format but can be extended. | |
| New fields can be added just by modifying the schema in this file, schema | |
| checking is only here to encourage reusing existing fields and avoiding typos. | |
| """ | |
| import argparse | |
| import time | |
| import json | |
| import os | |
| import requests | |
| import subprocess | |
| from collections import defaultdict | |
| class ScribeUploader: | |
| def __init__(self, category): | |
| self.category = category | |
| def format_message(self, field_dict): | |
| assert 'time' in field_dict, "Missing required Scribe field 'time'" | |
| message = defaultdict(dict) | |
| for field, value in field_dict.items(): | |
| if field in self.schema['normal']: | |
| message['normal'][field] = str(value) | |
| elif field in self.schema['int']: | |
| message['int'][field] = int(value) | |
| elif field in self.schema['float']: | |
| message['float'][field] = float(value) | |
| else: | |
| raise ValueError("Field {} is not currently used, " | |
| "be intentional about adding new fields".format(field)) | |
| return message | |
| def _upload_intern(self, messages): | |
| for m in messages: | |
| json_str = json.dumps(m) | |
| cmd = ['scribe_cat', self.category, json_str] | |
| subprocess.run(cmd) | |
| def upload(self, messages): | |
| if os.environ.get('SCRIBE_INTERN'): | |
| return self._upload_intern(messages) | |
| access_token = os.environ.get("SCRIBE_GRAPHQL_ACCESS_TOKEN") | |
| if not access_token: | |
| raise ValueError("Can't find access token from environment variable") | |
| url = "https://graph.facebook.com/scribe_logs" | |
| r = requests.post( | |
| url, | |
| data={ | |
| "access_token": access_token, | |
| "logs": json.dumps( | |
| [ | |
| { | |
| "category": self.category, | |
| "message": json.dumps(message), | |
| "line_escape": False, | |
| } | |
| for message in messages | |
| ] | |
| ), | |
| }, | |
| ) | |
| print(r.text) | |
| r.raise_for_status() | |
| class PytorchBenchmarkUploader(ScribeUploader): | |
| def __init__(self): | |
| super().__init__('perfpipe_pytorch_benchmarks') | |
| self.schema = { | |
| 'int': [ | |
| 'time', 'rounds', | |
| ], | |
| 'normal': [ | |
| 'benchmark_group', 'benchmark_name', 'benchmark_executor', | |
| 'benchmark_fuser', 'benchmark_class', 'benchmark_time', | |
| 'pytorch_commit_id', 'pytorch_branch', 'pytorch_commit_time', 'pytorch_version', | |
| 'pytorch_git_dirty', | |
| 'machine_kernel', 'machine_processor', 'machine_hostname', | |
| 'circle_build_num', 'circle_project_reponame', | |
| ], | |
| 'float': [ | |
| 'stddev', 'min', 'median', 'max', 'mean', | |
| ] | |
| } | |
| def post_pytest_benchmarks(self, pytest_json): | |
| machine_info = pytest_json['machine_info'] | |
| commit_info = pytest_json['commit_info'] | |
| upload_time = int(time.time()) | |
| messages = [] | |
| for b in pytest_json['benchmarks']: | |
| test = b['name'].split('[')[0] | |
| net_name = b['params']['net_name'] | |
| benchmark_name = '{}[{}]'.format(test, net_name) | |
| executor = b['params']['executor'] | |
| fuser = b['params']['fuser'] | |
| m = self.format_message({ | |
| "time": upload_time, | |
| "benchmark_group": b['group'], | |
| "benchmark_name": benchmark_name, | |
| "benchmark_executor": executor, | |
| "benchmark_fuser": fuser, | |
| "benchmark_class": b['fullname'], | |
| "benchmark_time": pytest_json['datetime'], | |
| "pytorch_commit_id": commit_info['id'], | |
| "pytorch_branch": commit_info['branch'], | |
| "pytorch_commit_time": commit_info['time'], | |
| "pytorch_version": None, | |
| "pytorch_git_dirty": commit_info['dirty'], | |
| "machine_kernel": machine_info['release'], | |
| "machine_processor": machine_info['processor'], | |
| "machine_hostname": machine_info['node'], | |
| "circle_build_num": os.environ.get("CIRCLE_BUILD_NUM"), | |
| "circle_project_reponame": os.environ.get("CIRCLE_PROJECT_REPONAME"), | |
| "stddev": b['stats']['stddev'], | |
| "rounds": b['stats']['rounds'], | |
| "min": b['stats']['min'], | |
| "median": b['stats']['median'], | |
| "max": b['stats']['max'], | |
| "mean": b['stats']['mean'], | |
| }) | |
| messages.append(m) | |
| self.upload(messages) | |
| if __name__ == "__main__": | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--pytest_bench_json", type=argparse.FileType('r'), | |
| help='Upload json data formatted by pytest-benchmark module') | |
| args = parser.parse_args() | |
| if args.pytest_bench_json: | |
| benchmark_uploader = PytorchBenchmarkUploader() | |
| json_data = json.load(args.pytest_bench_json) | |
| benchmark_uploader.post_pytest_benchmarks(json_data) |