blob: 3aa700388e78e758e7c277eddcd0aae528a2682d [file] [log] [blame]
Craig Tilleraa64ddf2017-02-08 14:20:08 -08001#!/usr/bin/env python2.7
2#
3# Convert google-benchmark json output to something that can be uploaded to
4# BigQuery
5#
6#
7# Copyright 2017, Google Inc.
8# All rights reserved.
9#
10# Redistribution and use in source and binary forms, with or without
11# modification, are permitted provided that the following conditions are
12# met:
13#
14# * Redistributions of source code must retain the above copyright
15# notice, this list of conditions and the following disclaimer.
16# * Redistributions in binary form must reproduce the above
17# copyright notice, this list of conditions and the following disclaimer
18# in the documentation and/or other materials provided with the
19# distribution.
20# * Neither the name of Google Inc. nor the names of its
21# contributors may be used to endorse or promote products derived from
22# this software without specific prior written permission.
23#
24# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
36import sys
37import json
38import csv
39import os
40
41columns = [
42 ('jenkins_build', 'integer'),
43 ('jenkins_job', 'string'),
44 ('date', 'timestamp'),
45 ('cpu_scaling_enabled', 'boolean'),
46 ('num_cpus', 'integer'),
47 ('mhz_per_cpu', 'integer'),
48 ('library_build_type', 'string'),
49 ('name', 'string'),
50 ('fixture', 'string'),
51 ('client_mutator', 'string'),
52 ('server_mutator', 'string'),
53 ('request_size', 'integer'),
54 ('response_size', 'integer'),
55 ('request_count', 'integer'),
56 ('iterations', 'integer'),
57 ('time_unit', 'string'),
58 ('real_time', 'integer'),
59 ('cpu_time', 'integer'),
60 ('bytes_per_second', 'float'),
61 ('allocs_per_iteration', 'float'),
62 ('locks_per_iteration', 'float'),
63 ('writes_per_iteration', 'float'),
Craig Tillerd9bc2102017-02-15 08:24:55 -080064 ('bandwidth_kilobits', 'integer'),
65 ('cli_transport_stalls_per_iteration', 'float'),
66 ('cli_stream_stalls_per_iteration', 'float'),
67 ('svr_transport_stalls_per_iteration', 'float'),
68 ('svr_stream_stalls_per_iteration', 'float'),
Craig Tillerebcba692017-02-21 13:31:24 -080069 ('atm_cas_per_iteration', 'float'),
Craig Tiller7f4d30a2017-02-21 10:24:00 -080070 ('atm_add_per_iteration', 'float')
Craig Tilleraa64ddf2017-02-08 14:20:08 -080071]
72
73if sys.argv[1] == '--schema':
74 print ',\n'.join('%s:%s' % (k, t.upper()) for k, t in columns)
75 sys.exit(0)
76
77with open(sys.argv[1]) as f:
78 js = json.loads(f.read())
79
80writer = csv.DictWriter(sys.stdout, [c for c,t in columns])
81
82bm_specs = {
83 'BM_UnaryPingPong': {
84 'tpl': ['fixture', 'client_mutator', 'server_mutator'],
85 'dyn': ['request_size', 'response_size'],
86 },
87 'BM_PumpStreamClientToServer': {
88 'tpl': ['fixture'],
89 'dyn': ['request_size'],
90 },
91 'BM_PumpStreamServerToClient': {
92 'tpl': ['fixture'],
93 'dyn': ['request_size'],
94 },
95 'BM_StreamingPingPong': {
96 'tpl': ['fixture', 'client_mutator', 'server_mutator'],
97 'dyn': ['request_size', 'request_count'],
98 },
99 'BM_StreamingPingPongMsgs': {
100 'tpl': ['fixture', 'client_mutator', 'server_mutator'],
101 'dyn': ['request_size'],
Craig Tillerd9bc2102017-02-15 08:24:55 -0800102 },
103 'BM_PumpStreamServerToClient_Trickle': {
104 'tpl': [],
105 'dyn': ['request_size', 'bandwidth_kilobits'],
106 },
Craig Tiller264307f2017-02-16 09:07:45 -0800107 'BM_ErrorStringOnNewError': {
108 'tpl': ['fixture'],
109 'dyn': [],
110 },
111 'BM_ErrorStringRepeatedly': {
112 'tpl': ['fixture'],
113 'dyn': [],
114 },
115 'BM_ErrorGetStatus': {
116 'tpl': ['fixture'],
117 'dyn': [],
118 },
119 'BM_ErrorGetStatusCode': {
120 'tpl': ['fixture'],
121 'dyn': [],
122 },
123 'BM_ErrorHttpError': {
124 'tpl': ['fixture'],
125 'dyn': [],
126 },
127 'BM_HasClearGrpcStatus': {
128 'tpl': ['fixture'],
129 'dyn': [],
130 },
Craig Tiller385b0092017-02-22 13:45:01 -0800131 'BM_IsolatedFilter' : {
132 'tpl': ['fixture', 'client_mutator'],
133 'dyn': [],
134 }
Craig Tilleraa64ddf2017-02-08 14:20:08 -0800135}
136
137def numericalize(s):
138 if not s: return ''
139 if s[-1] == 'k':
140 return int(s[:-1]) * 1024
141 if s[-1] == 'M':
142 return int(s[:-1]) * 1024 * 1024
143 if 0 <= (ord(s[-1]) - ord('0')) <= 9:
144 return int(s)
145 assert 'not a number: %s' % s
146
147def parse_name(name):
Craig Tiller3f878bc2017-02-15 08:33:09 -0800148 if '<' not in name and '/' not in name and name not in bm_specs:
149 return {'name': name}
Craig Tilleraa64ddf2017-02-08 14:20:08 -0800150 rest = name
151 out = {}
152 tpl_args = []
153 dyn_args = []
154 if '<' in rest:
155 tpl_bit = rest[rest.find('<') + 1 : rest.rfind('>')]
156 arg = ''
157 nesting = 0
158 for c in tpl_bit:
159 if c == '<':
160 nesting += 1
161 arg += c
162 elif c == '>':
163 nesting -= 1
164 arg += c
165 elif c == ',':
166 if nesting == 0:
167 tpl_args.append(arg.strip())
168 arg = ''
169 else:
170 arg += c
171 else:
172 arg += c
173 tpl_args.append(arg.strip())
174 rest = rest[:rest.find('<')] + rest[rest.rfind('>') + 1:]
175 if '/' in rest:
176 s = rest.split('/')
177 rest = s[0]
178 dyn_args = s[1:]
179 name = rest
Craig Tiller3f878bc2017-02-15 08:33:09 -0800180 assert name in bm_specs, 'bm_specs needs to be expanded for %s' % name
Craig Tilleraa64ddf2017-02-08 14:20:08 -0800181 assert len(dyn_args) == len(bm_specs[name]['dyn'])
182 assert len(tpl_args) == len(bm_specs[name]['tpl'])
183 out['name'] = name
184 out.update(dict((k, numericalize(v)) for k, v in zip(bm_specs[name]['dyn'], dyn_args)))
185 out.update(dict(zip(bm_specs[name]['tpl'], tpl_args)))
186 return out
187
188for bm in js['benchmarks']:
189 context = js['context']
Craig Tiller3f878bc2017-02-15 08:33:09 -0800190 if 'label' in bm:
Craig Tiller385b0092017-02-22 13:45:01 -0800191 labels_list = [s.split(':') for s in bm['label'].strip().split(' ') if len(s) and s[0] != '#']
Craig Tiller3f878bc2017-02-15 08:33:09 -0800192 for el in labels_list:
193 el[0] = el[0].replace('/iter', '_per_iteration')
194 labels = dict(labels_list)
195 else:
196 labels = {}
Craig Tilleraa64ddf2017-02-08 14:20:08 -0800197 row = {
198 'jenkins_build': os.environ.get('BUILD_NUMBER', ''),
199 'jenkins_job': os.environ.get('JOB_NAME', ''),
200 }
201 row.update(context)
202 row.update(bm)
203 row.update(parse_name(row['name']))
204 row.update(labels)
Craig Tiller3f878bc2017-02-15 08:33:09 -0800205 if 'label' in row:
206 del row['label']
Craig Tilleraa64ddf2017-02-08 14:20:08 -0800207 writer.writerow(row)