From aa64ddf10962b811e0767b71775d8983ec89cab5 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 8 Feb 2017 14:20:08 -0800 Subject: Allow uploading results to BigQuery --- tools/profiling/microbenchmarks/bm2bq.py | 162 +++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100755 tools/profiling/microbenchmarks/bm2bq.py (limited to 'tools/profiling/microbenchmarks/bm2bq.py') diff --git a/tools/profiling/microbenchmarks/bm2bq.py b/tools/profiling/microbenchmarks/bm2bq.py new file mode 100755 index 0000000000..124dbdfec5 --- /dev/null +++ b/tools/profiling/microbenchmarks/bm2bq.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python2.7 +# +# Convert google-benchmark json output to something that can be uploaded to +# BigQuery +# +# +# Copyright 2017, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import sys +import json +import csv +import os + +columns = [ + ('jenkins_build', 'integer'), + ('jenkins_job', 'string'), + ('date', 'timestamp'), + ('cpu_scaling_enabled', 'boolean'), + ('num_cpus', 'integer'), + ('mhz_per_cpu', 'integer'), + ('library_build_type', 'string'), + ('name', 'string'), + ('fixture', 'string'), + ('client_mutator', 'string'), + ('server_mutator', 'string'), + ('request_size', 'integer'), + ('response_size', 'integer'), + ('request_count', 'integer'), + ('iterations', 'integer'), + ('time_unit', 'string'), + ('real_time', 'integer'), + ('cpu_time', 'integer'), + ('bytes_per_second', 'float'), + ('allocs_per_iteration', 'float'), + ('locks_per_iteration', 'float'), + ('writes_per_iteration', 'float'), +] + +if sys.argv[1] == '--schema': + print ',\n'.join('%s:%s' % (k, t.upper()) for k, t in columns) + sys.exit(0) + +with open(sys.argv[1]) as f: + js = json.loads(f.read()) + +writer = csv.DictWriter(sys.stdout, [c for c,t in columns]) + +bm_specs = { + 'BM_UnaryPingPong': { + 'tpl': ['fixture', 'client_mutator', 'server_mutator'], + 'dyn': ['request_size', 'response_size'], + }, + 'BM_PumpStreamClientToServer': { + 'tpl': ['fixture'], + 'dyn': ['request_size'], + }, + 'BM_PumpStreamServerToClient': { + 'tpl': ['fixture'], + 'dyn': ['request_size'], + }, + 'BM_StreamingPingPong': { + 'tpl': ['fixture', 'client_mutator', 'server_mutator'], + 'dyn': ['request_size', 'request_count'], + }, + 'BM_StreamingPingPongMsgs': { + 'tpl': ['fixture', 'client_mutator', 'server_mutator'], + 'dyn': ['request_size'], + } +} + +def numericalize(s): + if not s: return '' + if s[-1] == 'k': + return int(s[:-1]) * 1024 + if s[-1] == 'M': + return int(s[:-1]) * 1024 * 1024 + if 0 <= (ord(s[-1]) - ord('0')) <= 9: + return int(s) + assert 'not a number: %s' % s + +def parse_name(name): + rest = name + out = {} + tpl_args = [] + dyn_args = [] + if '<' in rest: + tpl_bit = rest[rest.find('<') + 1 : rest.rfind('>')] + arg = '' + nesting = 0 + for c in tpl_bit: + if c == '<': + nesting += 1 + arg += c + elif c == '>': + nesting -= 1 + arg += c + elif c == ',': + if nesting == 0: + tpl_args.append(arg.strip()) + arg = '' + else: + arg += c + else: + arg += c + tpl_args.append(arg.strip()) + rest = rest[:rest.find('<')] + rest[rest.rfind('>') + 1:] + if '/' in rest: + s = rest.split('/') + rest = s[0] + dyn_args = s[1:] + name = rest + assert name in bm_specs + assert len(dyn_args) == len(bm_specs[name]['dyn']) + assert len(tpl_args) == len(bm_specs[name]['tpl']) + out['name'] = name + out.update(dict((k, numericalize(v)) for k, v in zip(bm_specs[name]['dyn'], dyn_args))) + out.update(dict(zip(bm_specs[name]['tpl'], tpl_args))) + return out + +for bm in js['benchmarks']: + context = js['context'] + labels_list = [s.split(':') for s in bm.get('label', '').split(' ')] + for el in labels_list: + el[0] = el[0].replace('/iter', '_per_iteration') + labels = dict(labels_list) + row = { + 'jenkins_build': os.environ.get('BUILD_NUMBER', ''), + 'jenkins_job': os.environ.get('JOB_NAME', ''), + } + row.update(context) + row.update(bm) + row.update(parse_name(row['name'])) + row.update(labels) + del row['label'] + writer.writerow(row) -- cgit v1.2.3