| """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) |