blob: ddcf053ae5ec9a92aead775bc55a4c3332665faa [file] [log] [blame]
Jan Tattermusch6d7fa552016-04-14 17:42:54 -07001#!/usr/bin/env python2.7
Jan Tattermuschefd98032016-04-14 16:29:24 -07002# Copyright 2016, Google Inc.
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9# * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# * Redistributions in binary form must reproduce the above
12# copyright notice, this list of conditions and the following disclaimer
13# in the documentation and/or other materials provided with the
14# distribution.
15# * Neither the name of Google Inc. nor the names of its
16# contributors may be used to endorse or promote products derived from
17# this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
Jan Tattermusch6d7fa552016-04-14 17:42:54 -070031# Uploads performance benchmark result file to bigquery.
Jan Tattermuschefd98032016-04-14 16:29:24 -070032
Jan Tattermusch6d7fa552016-04-14 17:42:54 -070033import argparse
Jan Tattermusch4843b512016-04-15 13:43:39 -070034import calendar
Jan Tattermuschefd98032016-04-14 16:29:24 -070035import json
36import os
37import sys
Jan Tattermusch4843b512016-04-15 13:43:39 -070038import time
Jan Tattermuschefd98032016-04-14 16:29:24 -070039import uuid
40
41
42gcp_utils_dir = os.path.abspath(os.path.join(
43 os.path.dirname(__file__), '../../gcp/utils'))
44sys.path.append(gcp_utils_dir)
45import big_query_utils
46
47
48_PROJECT_ID='grpc-testing'
Jan Tattermuschefd98032016-04-14 16:29:24 -070049
50
Jan Tattermusch4de2c322016-05-10 14:33:07 -070051def _upload_netperf_latency_csv_to_bigquery(dataset_id, table_id, result_file):
52 with open(result_file, 'r') as f:
53 (col1, col2, col3) = f.read().split(',')
54 latency50 = float(col1.strip()) * 1000
55 latency90 = float(col2.strip()) * 1000
56 latency99 = float(col3.strip()) * 1000
57
58 scenario_result = {
59 'scenario': {
60 'name': 'netperf_tcp_rr'
61 },
62 'summary': {
63 'latency50': latency50,
64 'latency90': latency90,
65 'latency99': latency99
66 }
67 }
68
Jan Tattermuschefd98032016-04-14 16:29:24 -070069 bq = big_query_utils.create_big_query()
Jan Tattermusch6d7fa552016-04-14 17:42:54 -070070 _create_results_table(bq, dataset_id, table_id)
Jan Tattermuschefd98032016-04-14 16:29:24 -070071
Jan Tattermusch4de2c322016-05-10 14:33:07 -070072 if not _insert_result(bq, dataset_id, table_id, scenario_result, flatten=False):
73 print 'Error uploading result to bigquery.'
74 sys.exit(1)
75
76
77def _upload_scenario_result_to_bigquery(dataset_id, table_id, result_file):
Jan Tattermuschefd98032016-04-14 16:29:24 -070078 with open(result_file, 'r') as f:
79 scenario_result = json.loads(f.read())
Jan Tattermusch6d7fa552016-04-14 17:42:54 -070080
Jan Tattermusch4de2c322016-05-10 14:33:07 -070081 bq = big_query_utils.create_big_query()
82 _create_results_table(bq, dataset_id, table_id)
83
Jan Tattermusch6d7fa552016-04-14 17:42:54 -070084 if not _insert_result(bq, dataset_id, table_id, scenario_result):
85 print 'Error uploading result to bigquery.'
86 sys.exit(1)
Jan Tattermuschefd98032016-04-14 16:29:24 -070087
88
Jan Tattermusch4de2c322016-05-10 14:33:07 -070089def _insert_result(bq, dataset_id, table_id, scenario_result, flatten=True):
90 if flatten:
91 _flatten_result_inplace(scenario_result)
Jan Tattermusch4843b512016-04-15 13:43:39 -070092 _populate_metadata_inplace(scenario_result)
Jan Tattermuschefd98032016-04-14 16:29:24 -070093 row = big_query_utils.make_row(str(uuid.uuid4()), scenario_result)
94 return big_query_utils.insert_rows(bq,
95 _PROJECT_ID,
Jan Tattermusch6d7fa552016-04-14 17:42:54 -070096 dataset_id,
97 table_id,
Jan Tattermuschefd98032016-04-14 16:29:24 -070098 [row])
99
100
Jan Tattermusch6d7fa552016-04-14 17:42:54 -0700101def _create_results_table(bq, dataset_id, table_id):
Jan Tattermuschefd98032016-04-14 16:29:24 -0700102 with open(os.path.dirname(__file__) + '/scenario_result_schema.json', 'r') as f:
103 table_schema = json.loads(f.read())
104 desc = 'Results of performance benchmarks.'
Jan Tattermusch6d7fa552016-04-14 17:42:54 -0700105 return big_query_utils.create_table2(bq, _PROJECT_ID, dataset_id,
106 table_id, table_schema, desc)
Jan Tattermuschefd98032016-04-14 16:29:24 -0700107
108
109def _flatten_result_inplace(scenario_result):
110 """Bigquery is not really great for handling deeply nested data
111 and repeated fields. To maintain values of some fields while keeping
112 the schema relatively simple, we artificially leave some of the fields
113 as JSON strings.
114 """
115 scenario_result['scenario']['clientConfig'] = json.dumps(scenario_result['scenario']['clientConfig'])
116 scenario_result['scenario']['serverConfig'] = json.dumps(scenario_result['scenario']['serverConfig'])
117 scenario_result['latencies'] = json.dumps(scenario_result['latencies'])
Yuxuan Lid885a272016-11-09 15:46:06 -0800118 for stats in scenario_result['serverStats']:
119 stats.pop('totalCpuTime', None)
120 stats.pop('idleCpuTime', None)
Jan Tattermuschefd98032016-04-14 16:29:24 -0700121 for stats in scenario_result['clientStats']:
122 stats['latencies'] = json.dumps(stats['latencies'])
Craig Tillered531b82016-11-01 10:27:18 -0700123 stats.pop('requestResults', None)
Jan Tattermusch88cc4e22016-04-14 16:58:50 -0700124 scenario_result['serverCores'] = json.dumps(scenario_result['serverCores'])
Sree Kuchibhotla6dbfce02016-07-15 11:05:24 -0700125 scenario_result['clientSuccess'] = json.dumps(scenario_result['clientSuccess'])
126 scenario_result['serverSuccess'] = json.dumps(scenario_result['serverSuccess'])
Craig Tiller77fbc1c2016-10-31 14:04:03 -0700127 scenario_result['requestResults'] = json.dumps(scenario_result.get('requestResults', []))
Yuxuan Li9ba52e72016-11-09 14:45:25 -0800128 scenario_result['summary'].pop('serverCpuUsage', None)
Craig Tillerc9390222016-11-01 15:47:24 -0700129 scenario_result['summary'].pop('successfulRequestsPerSecond', None)
130 scenario_result['summary'].pop('failedRequestsPerSecond', None)
Jan Tattermusch6d7fa552016-04-14 17:42:54 -0700131
Yuxuan Li317f60b2016-11-09 15:08:26 -0800132
Jan Tattermusch4843b512016-04-15 13:43:39 -0700133def _populate_metadata_inplace(scenario_result):
134 """Populates metadata based on environment variables set by Jenkins."""
135 # NOTE: Grabbing the Jenkins environment variables will only work if the
136 # driver is running locally on the same machine where Jenkins has started
137 # the job. For our setup, this is currently the case, so just assume that.
138 build_number = os.getenv('BUILD_NUMBER')
139 build_url = os.getenv('BUILD_URL')
140 job_name = os.getenv('JOB_NAME')
141 git_commit = os.getenv('GIT_COMMIT')
142 # actual commit is the actual head of PR that is getting tested
143 git_actual_commit = os.getenv('ghprbActualCommit')
144
145 utc_timestamp = str(calendar.timegm(time.gmtime()))
146 metadata = {'created': utc_timestamp}
147
148 if build_number:
149 metadata['buildNumber'] = build_number
150 if build_url:
151 metadata['buildUrl'] = build_url
152 if job_name:
153 metadata['jobName'] = job_name
154 if git_commit:
155 metadata['gitCommit'] = git_commit
156 if git_actual_commit:
157 metadata['gitActualCommit'] = git_actual_commit
158
159 scenario_result['metadata'] = metadata
160
161
Jan Tattermusch6d7fa552016-04-14 17:42:54 -0700162argp = argparse.ArgumentParser(description='Upload result to big query.')
163argp.add_argument('--bq_result_table', required=True, default=None, type=str,
164 help='Bigquery "dataset.table" to upload results to.')
165argp.add_argument('--file_to_upload', default='scenario_result.json', type=str,
166 help='Report file to upload.')
Jan Tattermusch4de2c322016-05-10 14:33:07 -0700167argp.add_argument('--file_format',
168 choices=['scenario_result','netperf_latency_csv'],
169 default='scenario_result',
170 help='Format of the file to upload.')
Jan Tattermusch6d7fa552016-04-14 17:42:54 -0700171
172args = argp.parse_args()
173
174dataset_id, table_id = args.bq_result_table.split('.', 2)
Jan Tattermusch4de2c322016-05-10 14:33:07 -0700175
176if args.file_format == 'netperf_latency_csv':
177 _upload_netperf_latency_csv_to_bigquery(dataset_id, table_id, args.file_to_upload)
178else:
179 _upload_scenario_result_to_bigquery(dataset_id, table_id, args.file_to_upload)
Jan Tattermusch6d7fa552016-04-14 17:42:54 -0700180print 'Successfully uploaded %s to BigQuery.\n' % args.file_to_upload