blob: 280f217e6901272a8c6e6ae8f1ac0122259900f0 [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 Tillere177c242017-02-25 07:39:05 -080070 ('atm_add_per_iteration', 'float'),
71 ('end_of_stream', 'boolean'),
72 ('header_bytes_per_iteration', 'float'),
73 ('framing_bytes_per_iteration', 'float'),
Craig Tilleraa64ddf2017-02-08 14:20:08 -080074]
75
76if sys.argv[1] == '--schema':
77 print ',\n'.join('%s:%s' % (k, t.upper()) for k, t in columns)
78 sys.exit(0)
79
80with open(sys.argv[1]) as f:
81 js = json.loads(f.read())
82
83writer = csv.DictWriter(sys.stdout, [c for c,t in columns])
84
85bm_specs = {
86 'BM_UnaryPingPong': {
87 'tpl': ['fixture', 'client_mutator', 'server_mutator'],
88 'dyn': ['request_size', 'response_size'],
89 },
90 'BM_PumpStreamClientToServer': {
91 'tpl': ['fixture'],
92 'dyn': ['request_size'],
93 },
94 'BM_PumpStreamServerToClient': {
95 'tpl': ['fixture'],
96 'dyn': ['request_size'],
97 },
98 'BM_StreamingPingPong': {
99 'tpl': ['fixture', 'client_mutator', 'server_mutator'],
100 'dyn': ['request_size', 'request_count'],
101 },
102 'BM_StreamingPingPongMsgs': {
103 'tpl': ['fixture', 'client_mutator', 'server_mutator'],
104 'dyn': ['request_size'],
Craig Tillerd9bc2102017-02-15 08:24:55 -0800105 },
106 'BM_PumpStreamServerToClient_Trickle': {
107 'tpl': [],
108 'dyn': ['request_size', 'bandwidth_kilobits'],
109 },
Craig Tiller264307f2017-02-16 09:07:45 -0800110 'BM_ErrorStringOnNewError': {
111 'tpl': ['fixture'],
112 'dyn': [],
113 },
114 'BM_ErrorStringRepeatedly': {
115 'tpl': ['fixture'],
116 'dyn': [],
117 },
118 'BM_ErrorGetStatus': {
119 'tpl': ['fixture'],
120 'dyn': [],
121 },
122 'BM_ErrorGetStatusCode': {
123 'tpl': ['fixture'],
124 'dyn': [],
125 },
126 'BM_ErrorHttpError': {
127 'tpl': ['fixture'],
128 'dyn': [],
129 },
130 'BM_HasClearGrpcStatus': {
131 'tpl': ['fixture'],
132 'dyn': [],
133 },
Craig Tiller385b0092017-02-22 13:45:01 -0800134 'BM_IsolatedFilter' : {
135 'tpl': ['fixture', 'client_mutator'],
136 'dyn': [],
Craig Tillere177c242017-02-25 07:39:05 -0800137 },
138 'BM_HpackEncoderEncodeHeader' : {
139 'tpl': ['fixture'],
140 'dyn': ['end_of_stream', 'request_size'],
141 },
142 'BM_HpackParserParseHeader' : {
143 'tpl': ['fixture'],
144 'dyn': [],
145 },
Craig Tilleraa64ddf2017-02-08 14:20:08 -0800146}
147
148def numericalize(s):
149 if not s: return ''
150 if s[-1] == 'k':
151 return int(s[:-1]) * 1024
152 if s[-1] == 'M':
153 return int(s[:-1]) * 1024 * 1024
154 if 0 <= (ord(s[-1]) - ord('0')) <= 9:
155 return int(s)
156 assert 'not a number: %s' % s
157
158def parse_name(name):
Craig Tiller3f878bc2017-02-15 08:33:09 -0800159 if '<' not in name and '/' not in name and name not in bm_specs:
160 return {'name': name}
Craig Tilleraa64ddf2017-02-08 14:20:08 -0800161 rest = name
162 out = {}
163 tpl_args = []
164 dyn_args = []
165 if '<' in rest:
166 tpl_bit = rest[rest.find('<') + 1 : rest.rfind('>')]
167 arg = ''
168 nesting = 0
169 for c in tpl_bit:
170 if c == '<':
171 nesting += 1
172 arg += c
173 elif c == '>':
174 nesting -= 1
175 arg += c
176 elif c == ',':
177 if nesting == 0:
178 tpl_args.append(arg.strip())
179 arg = ''
180 else:
181 arg += c
182 else:
183 arg += c
184 tpl_args.append(arg.strip())
185 rest = rest[:rest.find('<')] + rest[rest.rfind('>') + 1:]
186 if '/' in rest:
187 s = rest.split('/')
188 rest = s[0]
189 dyn_args = s[1:]
190 name = rest
Craig Tiller3f878bc2017-02-15 08:33:09 -0800191 assert name in bm_specs, 'bm_specs needs to be expanded for %s' % name
Craig Tilleraa64ddf2017-02-08 14:20:08 -0800192 assert len(dyn_args) == len(bm_specs[name]['dyn'])
193 assert len(tpl_args) == len(bm_specs[name]['tpl'])
194 out['name'] = name
195 out.update(dict((k, numericalize(v)) for k, v in zip(bm_specs[name]['dyn'], dyn_args)))
196 out.update(dict(zip(bm_specs[name]['tpl'], tpl_args)))
197 return out
198
199for bm in js['benchmarks']:
200 context = js['context']
Craig Tiller3f878bc2017-02-15 08:33:09 -0800201 if 'label' in bm:
Craig Tiller385b0092017-02-22 13:45:01 -0800202 labels_list = [s.split(':') for s in bm['label'].strip().split(' ') if len(s) and s[0] != '#']
Craig Tiller3f878bc2017-02-15 08:33:09 -0800203 for el in labels_list:
204 el[0] = el[0].replace('/iter', '_per_iteration')
205 labels = dict(labels_list)
206 else:
207 labels = {}
Craig Tilleraa64ddf2017-02-08 14:20:08 -0800208 row = {
209 'jenkins_build': os.environ.get('BUILD_NUMBER', ''),
210 'jenkins_job': os.environ.get('JOB_NAME', ''),
211 }
212 row.update(context)
213 row.update(bm)
214 row.update(parse_name(row['name']))
215 row.update(labels)
Craig Tiller3f878bc2017-02-15 08:33:09 -0800216 if 'label' in row:
217 del row['label']
Craig Tilleraa64ddf2017-02-08 14:20:08 -0800218 writer.writerow(row)