blob: 92149115fe2387ac6e2d79cef5a54d4c67ec1339 [file] [log] [blame]
Jan Tattermuschb2758442016-03-28 09:32:20 -07001#!/usr/bin/env python2.7
2# 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
31"""Run performance tests locally or remotely."""
32
siddharthshukla0589e532016-07-07 16:08:01 +020033from __future__ import print_function
34
Jan Tattermuschb2758442016-03-28 09:32:20 -070035import argparse
Craig Tilleraccf16b2016-09-15 09:08:32 -070036import collections
Jan Tattermuschbb1a4532016-03-30 18:04:01 -070037import itertools
Jan Tattermuschb2758442016-03-28 09:32:20 -070038import jobset
Craig Tiller0bda0b32016-03-03 12:51:53 -080039import json
Jan Tattermuschb2758442016-03-28 09:32:20 -070040import multiprocessing
41import os
Craig Tilleraccf16b2016-09-15 09:08:32 -070042import performance.scenario_config as scenario_config
Craig Tiller0bda0b32016-03-03 12:51:53 -080043import pipes
Jan Tattermusch38becc22016-04-14 08:00:35 -070044import re
Jan Tattermuschb2758442016-03-28 09:32:20 -070045import subprocess
46import sys
47import tempfile
48import time
Jan Tattermuschee9032c2016-04-14 08:35:51 -070049import traceback
Jan Tattermuschb2758442016-03-28 09:32:20 -070050import uuid
51
52
53_ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
54os.chdir(_ROOT)
55
56
57_REMOTE_HOST_USERNAME = 'jenkins'
58
59
Jan Tattermuschb2758442016-03-28 09:32:20 -070060class QpsWorkerJob:
61 """Encapsulates a qps worker server job."""
62
Jan Tattermuschbb1a4532016-03-30 18:04:01 -070063 def __init__(self, spec, language, host_and_port):
Jan Tattermuschb2758442016-03-28 09:32:20 -070064 self._spec = spec
Jan Tattermuschbb1a4532016-03-30 18:04:01 -070065 self.language = language
Jan Tattermuschb2758442016-03-28 09:32:20 -070066 self.host_and_port = host_and_port
Craig Tillerc1b54f22016-09-15 08:57:14 -070067 self._job = None
68
69 def start(self):
Craig Tillerc197ec12016-09-15 09:19:33 -070070 self._job = jobset.Job(self._spec, newline_on_success=True, travis=True, add_env={})
Jan Tattermuschb2758442016-03-28 09:32:20 -070071
72 def is_running(self):
73 """Polls a job and returns True if given job is still running."""
Craig Tillerc1b54f22016-09-15 08:57:14 -070074 return self._job and self._job.state() == jobset._RUNNING
Jan Tattermuschb2758442016-03-28 09:32:20 -070075
76 def kill(self):
Craig Tillerc1b54f22016-09-15 08:57:14 -070077 if self._job:
78 self._job.kill()
79 self._job = None
Jan Tattermuschb2758442016-03-28 09:32:20 -070080
81
Jan Tattermuschbb1a4532016-03-30 18:04:01 -070082def create_qpsworker_job(language, shortname=None,
83 port=10000, remote_host=None):
Jan Tattermuschbb1a4532016-03-30 18:04:01 -070084 cmdline = language.worker_cmdline() + ['--driver_port=%s' % port]
Jan Tattermuschb2758442016-03-28 09:32:20 -070085 if remote_host:
86 user_at_host = '%s@%s' % (_REMOTE_HOST_USERNAME, remote_host)
Jan Tattermuschbb1a4532016-03-30 18:04:01 -070087 cmdline = ['ssh',
88 str(user_at_host),
89 'cd ~/performance_workspace/grpc/ && %s' % ' '.join(cmdline)]
Jan Tattermuschb2758442016-03-28 09:32:20 -070090 host_and_port='%s:%s' % (remote_host, port)
91 else:
92 host_and_port='localhost:%s' % port
93
Jan Tattermusch38becc22016-04-14 08:00:35 -070094 # TODO(jtattermusch): with some care, we can calculate the right timeout
95 # of a worker from the sum of warmup + benchmark times for all the scenarios
Jan Tattermuschb2758442016-03-28 09:32:20 -070096 jobspec = jobset.JobSpec(
Jan Tattermuschbb1a4532016-03-30 18:04:01 -070097 cmdline=cmdline,
98 shortname=shortname,
Jan Tattermusch541d5d72016-05-05 16:08:49 -070099 timeout_seconds=2*60*60)
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700100 return QpsWorkerJob(jobspec, language, host_and_port)
Jan Tattermuschb2758442016-03-28 09:32:20 -0700101
102
Jan Tattermusch6d7fa552016-04-14 17:42:54 -0700103def create_scenario_jobspec(scenario_json, workers, remote_host=None,
104 bq_result_table=None):
Jan Tattermuschb2758442016-03-28 09:32:20 -0700105 """Runs one scenario using QPS driver."""
106 # setting QPS_WORKERS env variable here makes sure it works with SSH too.
Jan Tattermusch6d7fa552016-04-14 17:42:54 -0700107 cmd = 'QPS_WORKERS="%s" ' % ','.join(workers)
108 if bq_result_table:
109 cmd += 'BQ_RESULT_TABLE="%s" ' % bq_result_table
110 cmd += 'tools/run_tests/performance/run_qps_driver.sh '
111 cmd += '--scenarios_json=%s ' % pipes.quote(json.dumps({'scenarios': [scenario_json]}))
Vijay Paic23d33b2016-07-19 11:19:12 -0700112 cmd += '--scenario_result_file=scenario_result.json'
Jan Tattermuschb2758442016-03-28 09:32:20 -0700113 if remote_host:
114 user_at_host = '%s@%s' % (_REMOTE_HOST_USERNAME, remote_host)
Jan Tattermusch6d7fa552016-04-14 17:42:54 -0700115 cmd = 'ssh %s "cd ~/performance_workspace/grpc/ && "%s' % (user_at_host, pipes.quote(cmd))
Jan Tattermuschb2758442016-03-28 09:32:20 -0700116
117 return jobset.JobSpec(
118 cmdline=[cmd],
Craig Tiller0bda0b32016-03-03 12:51:53 -0800119 shortname='qps_json_driver.%s' % scenario_json['name'],
120 timeout_seconds=3*60,
121 shell=True,
122 verbose_success=True)
123
124
125def create_quit_jobspec(workers, remote_host=None):
126 """Runs quit using QPS driver."""
127 # setting QPS_WORKERS env variable here makes sure it works with SSH too.
Craig Tiller025972d2016-09-15 09:26:50 -0700128 cmd = 'QPS_WORKERS="%s" bins/opt/qps_json_driver --quit' % ','.join(w.host_and_port for w in workers)
Craig Tiller0bda0b32016-03-03 12:51:53 -0800129 if remote_host:
130 user_at_host = '%s@%s' % (_REMOTE_HOST_USERNAME, remote_host)
Jan Tattermusch6d7fa552016-04-14 17:42:54 -0700131 cmd = 'ssh %s "cd ~/performance_workspace/grpc/ && "%s' % (user_at_host, pipes.quote(cmd))
Craig Tiller0bda0b32016-03-03 12:51:53 -0800132
133 return jobset.JobSpec(
134 cmdline=[cmd],
vjpai29089c72016-04-20 12:38:16 -0700135 shortname='qps_json_driver.quit',
Jan Tattermuschb2758442016-03-28 09:32:20 -0700136 timeout_seconds=3*60,
137 shell=True,
138 verbose_success=True)
139
140
Jan Tattermusch4de2c322016-05-10 14:33:07 -0700141def create_netperf_jobspec(server_host='localhost', client_host=None,
142 bq_result_table=None):
143 """Runs netperf benchmark."""
144 cmd = 'NETPERF_SERVER_HOST="%s" ' % server_host
145 if bq_result_table:
146 cmd += 'BQ_RESULT_TABLE="%s" ' % bq_result_table
Jan Tattermuschad17bf72016-05-11 12:41:37 -0700147 if client_host:
148 # If netperf is running remotely, the env variables populated by Jenkins
149 # won't be available on the client, but we need them for uploading results
150 # to BigQuery.
151 jenkins_job_name = os.getenv('JOB_NAME')
152 if jenkins_job_name:
153 cmd += 'JOB_NAME="%s" ' % jenkins_job_name
154 jenkins_build_number = os.getenv('BUILD_NUMBER')
155 if jenkins_build_number:
156 cmd += 'BUILD_NUMBER="%s" ' % jenkins_build_number
157
Jan Tattermusch4de2c322016-05-10 14:33:07 -0700158 cmd += 'tools/run_tests/performance/run_netperf.sh'
159 if client_host:
160 user_at_host = '%s@%s' % (_REMOTE_HOST_USERNAME, client_host)
161 cmd = 'ssh %s "cd ~/performance_workspace/grpc/ && "%s' % (user_at_host, pipes.quote(cmd))
162
163 return jobset.JobSpec(
164 cmdline=[cmd],
165 shortname='netperf',
166 timeout_seconds=60,
167 shell=True,
168 verbose_success=True)
169
170
Jan Tattermuschde874a12016-04-18 09:21:37 -0700171def archive_repo(languages):
Jan Tattermuschb2758442016-03-28 09:32:20 -0700172 """Archives local version of repo including submodules."""
Jan Tattermuschde874a12016-04-18 09:21:37 -0700173 cmdline=['tar', '-cf', '../grpc.tar', '../grpc/']
174 if 'java' in languages:
175 cmdline.append('../grpc-java')
176 if 'go' in languages:
177 cmdline.append('../grpc-go')
178
Jan Tattermuschb2758442016-03-28 09:32:20 -0700179 archive_job = jobset.JobSpec(
Jan Tattermuschde874a12016-04-18 09:21:37 -0700180 cmdline=cmdline,
Jan Tattermuschb2758442016-03-28 09:32:20 -0700181 shortname='archive_repo',
182 timeout_seconds=3*60)
183
184 jobset.message('START', 'Archiving local repository.', do_newline=True)
185 num_failures, _ = jobset.run(
186 [archive_job], newline_on_success=True, maxjobs=1)
187 if num_failures == 0:
188 jobset.message('SUCCESS',
Jan Tattermuschde874a12016-04-18 09:21:37 -0700189 'Archive with local repository created successfully.',
Jan Tattermuschb2758442016-03-28 09:32:20 -0700190 do_newline=True)
191 else:
192 jobset.message('FAILED', 'Failed to archive local repository.',
193 do_newline=True)
194 sys.exit(1)
195
196
Jan Tattermusch14089202016-04-27 17:55:27 -0700197def prepare_remote_hosts(hosts, prepare_local=False):
198 """Prepares remote hosts (and maybe prepare localhost as well)."""
199 prepare_timeout = 5*60
Jan Tattermuschb2758442016-03-28 09:32:20 -0700200 prepare_jobs = []
201 for host in hosts:
202 user_at_host = '%s@%s' % (_REMOTE_HOST_USERNAME, host)
203 prepare_jobs.append(
204 jobset.JobSpec(
205 cmdline=['tools/run_tests/performance/remote_host_prepare.sh'],
206 shortname='remote_host_prepare.%s' % host,
207 environ = {'USER_AT_HOST': user_at_host},
Jan Tattermusch14089202016-04-27 17:55:27 -0700208 timeout_seconds=prepare_timeout))
209 if prepare_local:
210 # Prepare localhost as well
211 prepare_jobs.append(
212 jobset.JobSpec(
213 cmdline=['tools/run_tests/performance/kill_workers.sh'],
214 shortname='local_prepare',
215 timeout_seconds=prepare_timeout))
216 jobset.message('START', 'Preparing hosts.', do_newline=True)
Jan Tattermuschb2758442016-03-28 09:32:20 -0700217 num_failures, _ = jobset.run(
218 prepare_jobs, newline_on_success=True, maxjobs=10)
219 if num_failures == 0:
220 jobset.message('SUCCESS',
Jan Tattermusch14089202016-04-27 17:55:27 -0700221 'Prepare step completed successfully.',
Jan Tattermuschb2758442016-03-28 09:32:20 -0700222 do_newline=True)
223 else:
224 jobset.message('FAILED', 'Failed to prepare remote hosts.',
225 do_newline=True)
226 sys.exit(1)
227
228
Craig Tillerd92d5c52016-04-04 13:49:29 -0700229def build_on_remote_hosts(hosts, languages=scenario_config.LANGUAGES.keys(), build_local=False):
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700230 """Builds performance worker on remote hosts (and maybe also locally)."""
Jan Tattermuschb2758442016-03-28 09:32:20 -0700231 build_timeout = 15*60
232 build_jobs = []
233 for host in hosts:
234 user_at_host = '%s@%s' % (_REMOTE_HOST_USERNAME, host)
235 build_jobs.append(
236 jobset.JobSpec(
Craig Tiller7797e3f2016-04-01 07:41:05 -0700237 cmdline=['tools/run_tests/performance/remote_host_build.sh'] + languages,
Jan Tattermuschb2758442016-03-28 09:32:20 -0700238 shortname='remote_host_build.%s' % host,
239 environ = {'USER_AT_HOST': user_at_host, 'CONFIG': 'opt'},
240 timeout_seconds=build_timeout))
241 if build_local:
242 # Build locally as well
243 build_jobs.append(
244 jobset.JobSpec(
Craig Tiller7797e3f2016-04-01 07:41:05 -0700245 cmdline=['tools/run_tests/performance/build_performance.sh'] + languages,
Jan Tattermuschb2758442016-03-28 09:32:20 -0700246 shortname='local_build',
247 environ = {'CONFIG': 'opt'},
248 timeout_seconds=build_timeout))
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700249 jobset.message('START', 'Building.', do_newline=True)
Jan Tattermuschb2758442016-03-28 09:32:20 -0700250 num_failures, _ = jobset.run(
251 build_jobs, newline_on_success=True, maxjobs=10)
252 if num_failures == 0:
253 jobset.message('SUCCESS',
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700254 'Built successfully.',
Jan Tattermuschb2758442016-03-28 09:32:20 -0700255 do_newline=True)
256 else:
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700257 jobset.message('FAILED', 'Build failed.',
Jan Tattermuschb2758442016-03-28 09:32:20 -0700258 do_newline=True)
259 sys.exit(1)
260
261
Craig Tillerc1b54f22016-09-15 08:57:14 -0700262def create_qpsworkers(languages, worker_hosts):
263 """Creates QPS workers (but does not start them)."""
Jan Tattermuschb2758442016-03-28 09:32:20 -0700264 if not worker_hosts:
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700265 # run two workers locally (for each language)
Jan Tattermuschb2758442016-03-28 09:32:20 -0700266 workers=[(None, 10000), (None, 10010)]
267 elif len(worker_hosts) == 1:
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700268 # run two workers on the remote host (for each language)
Jan Tattermuschb2758442016-03-28 09:32:20 -0700269 workers=[(worker_hosts[0], 10000), (worker_hosts[0], 10010)]
270 else:
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700271 # run one worker per each remote host (for each language)
Jan Tattermuschb2758442016-03-28 09:32:20 -0700272 workers=[(worker_host, 10000) for worker_host in worker_hosts]
273
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700274 return [create_qpsworker_job(language,
275 shortname= 'qps_worker_%s_%s' % (language,
276 worker_idx),
277 port=worker[1] + language.worker_port_offset(),
Jan Tattermuschb2758442016-03-28 09:32:20 -0700278 remote_host=worker[0])
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700279 for language in languages
280 for worker_idx, worker in enumerate(workers)]
Jan Tattermuschb2758442016-03-28 09:32:20 -0700281
282
Craig Tiller677966a2016-09-26 07:37:28 -0700283Scenario = collections.namedtuple('Scenario', 'jobspec workers name')
Craig Tillerc1b54f22016-09-15 08:57:14 -0700284
285
Jan Tattermusch6d7fa552016-04-14 17:42:54 -0700286def create_scenarios(languages, workers_by_lang, remote_host=None, regex='.*',
Jan Tattermusch4de2c322016-05-10 14:33:07 -0700287 category='all', bq_result_table=None,
288 netperf=False, netperf_hosts=[]):
Jan Tattermuschb2758442016-03-28 09:32:20 -0700289 """Create jobspecs for scenarios to run."""
Ken Payson0482c102016-04-19 12:08:34 -0700290 all_workers = [worker
291 for workers in workers_by_lang.values()
292 for worker in workers]
Jan Tattermuschb2758442016-03-28 09:32:20 -0700293 scenarios = []
Craig Tillerc1b54f22016-09-15 08:57:14 -0700294 _NO_WORKERS = []
Jan Tattermusch4de2c322016-05-10 14:33:07 -0700295
296 if netperf:
297 if not netperf_hosts:
298 netperf_server='localhost'
299 netperf_client=None
300 elif len(netperf_hosts) == 1:
301 netperf_server=netperf_hosts[0]
302 netperf_client=netperf_hosts[0]
303 else:
304 netperf_server=netperf_hosts[0]
305 netperf_client=netperf_hosts[1]
Craig Tillerc1b54f22016-09-15 08:57:14 -0700306 scenarios.append(Scenario(
307 create_netperf_jobspec(server_host=netperf_server,
308 client_host=netperf_client,
309 bq_result_table=bq_result_table),
Craig Tiller677966a2016-09-26 07:37:28 -0700310 _NO_WORKERS, 'netperf'))
Jan Tattermusch4de2c322016-05-10 14:33:07 -0700311
Jan Tattermuschb2758442016-03-28 09:32:20 -0700312 for language in languages:
Craig Tiller0bda0b32016-03-03 12:51:53 -0800313 for scenario_json in language.scenarios():
Jan Tattermusch38becc22016-04-14 08:00:35 -0700314 if re.search(args.regex, scenario_json['name']):
Craig Tillerb6df2472016-09-13 09:41:26 -0700315 categories = scenario_json.get('CATEGORIES', ['scalable', 'smoketest'])
316 if category in categories or category == 'all':
Craig Tillerc1b54f22016-09-15 08:57:14 -0700317 workers = workers_by_lang[str(language)][:]
Jan Tattermusch427699b2016-05-05 18:10:14 -0700318 # 'SERVER_LANGUAGE' is an indicator for this script to pick
319 # a server in different language.
320 custom_server_lang = scenario_json.get('SERVER_LANGUAGE', None)
Jan Tattermusch37a907e2016-05-13 13:49:43 -0700321 custom_client_lang = scenario_json.get('CLIENT_LANGUAGE', None)
Jan Tattermusch427699b2016-05-05 18:10:14 -0700322 scenario_json = scenario_config.remove_nonproto_fields(scenario_json)
Jan Tattermusch37a907e2016-05-13 13:49:43 -0700323 if custom_server_lang and custom_client_lang:
324 raise Exception('Cannot set both custom CLIENT_LANGUAGE and SERVER_LANGUAGE'
325 'in the same scenario')
Jan Tattermusch427699b2016-05-05 18:10:14 -0700326 if custom_server_lang:
327 if not workers_by_lang.get(custom_server_lang, []):
siddharthshukla0589e532016-07-07 16:08:01 +0200328 print('Warning: Skipping scenario %s as' % scenario_json['name'])
Jan Tattermusch427699b2016-05-05 18:10:14 -0700329 print('SERVER_LANGUAGE is set to %s yet the language has '
330 'not been selected with -l' % custom_server_lang)
331 continue
332 for idx in range(0, scenario_json['num_servers']):
333 # replace first X workers by workers of a different language
334 workers[idx] = workers_by_lang[custom_server_lang][idx]
Jan Tattermusch37a907e2016-05-13 13:49:43 -0700335 if custom_client_lang:
336 if not workers_by_lang.get(custom_client_lang, []):
siddharthshukla0589e532016-07-07 16:08:01 +0200337 print('Warning: Skipping scenario %s as' % scenario_json['name'])
Jan Tattermusch37a907e2016-05-13 13:49:43 -0700338 print('CLIENT_LANGUAGE is set to %s yet the language has '
339 'not been selected with -l' % custom_client_lang)
340 continue
341 for idx in range(scenario_json['num_servers'], len(workers)):
342 # replace all client workers by workers of a different language,
343 # leave num_server workers as they are server workers.
344 workers[idx] = workers_by_lang[custom_client_lang][idx]
Craig Tillerc1b54f22016-09-15 08:57:14 -0700345 scenario = Scenario(
346 create_scenario_jobspec(scenario_json,
347 [w.host_and_port for w in workers],
348 remote_host=remote_host,
349 bq_result_table=bq_result_table),
Craig Tiller677966a2016-09-26 07:37:28 -0700350 workers,
351 scenario_json['name'])
Jan Tattermusch427699b2016-05-05 18:10:14 -0700352 scenarios.append(scenario)
Jan Tattermuschb2758442016-03-28 09:32:20 -0700353
Jan Tattermuschb2758442016-03-28 09:32:20 -0700354 return scenarios
355
356
357def finish_qps_workers(jobs):
358 """Waits for given jobs to finish and eventually kills them."""
359 retries = 0
360 while any(job.is_running() for job in jobs):
361 for job in qpsworker_jobs:
362 if job.is_running():
siddharthshukla0589e532016-07-07 16:08:01 +0200363 print('QPS worker "%s" is still running.' % job.host_and_port)
Jan Tattermuschb2758442016-03-28 09:32:20 -0700364 if retries > 10:
siddharthshukla0589e532016-07-07 16:08:01 +0200365 print('Killing all QPS workers.')
Jan Tattermuschb2758442016-03-28 09:32:20 -0700366 for job in jobs:
367 job.kill()
368 retries += 1
369 time.sleep(3)
siddharthshukla0589e532016-07-07 16:08:01 +0200370 print('All QPS workers finished.')
Jan Tattermuschb2758442016-03-28 09:32:20 -0700371
372
373argp = argparse.ArgumentParser(description='Run performance tests.')
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700374argp.add_argument('-l', '--language',
Craig Tillerd92d5c52016-04-04 13:49:29 -0700375 choices=['all'] + sorted(scenario_config.LANGUAGES.keys()),
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700376 nargs='+',
Jan Tattermusch427699b2016-05-05 18:10:14 -0700377 required=True,
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700378 help='Languages to benchmark.')
Jan Tattermuschb2758442016-03-28 09:32:20 -0700379argp.add_argument('--remote_driver_host',
380 default=None,
381 help='Run QPS driver on given host. By default, QPS driver is run locally.')
382argp.add_argument('--remote_worker_host',
383 nargs='+',
384 default=[],
385 help='Worker hosts where to start QPS workers.')
Craig Tiller677966a2016-09-26 07:37:28 -0700386argp.add_argument('--dry_run',
387 default=False,
388 action='store_const',
389 const=True,
390 help='Just list scenarios to be run, but don\'t run them.')
Jan Tattermusch38becc22016-04-14 08:00:35 -0700391argp.add_argument('-r', '--regex', default='.*', type=str,
392 help='Regex to select scenarios to run.')
Jan Tattermusch6d7fa552016-04-14 17:42:54 -0700393argp.add_argument('--bq_result_table', default=None, type=str,
394 help='Bigquery "dataset.table" to upload results to.')
Jan Tattermusch427699b2016-05-05 18:10:14 -0700395argp.add_argument('--category',
Craig Tiller6388da52016-09-07 17:06:29 -0700396 choices=['smoketest','all','scalable','sweep'],
Jan Tattermusch37a907e2016-05-13 13:49:43 -0700397 default='all',
398 help='Select a category of tests to run.')
Jan Tattermusch4de2c322016-05-10 14:33:07 -0700399argp.add_argument('--netperf',
400 default=False,
401 action='store_const',
402 const=True,
403 help='Run netperf benchmark as one of the scenarios.')
Jan Tattermuschb2758442016-03-28 09:32:20 -0700404
405args = argp.parse_args()
406
Craig Tillerd92d5c52016-04-04 13:49:29 -0700407languages = set(scenario_config.LANGUAGES[l]
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700408 for l in itertools.chain.from_iterable(
Craig Tillerd92d5c52016-04-04 13:49:29 -0700409 scenario_config.LANGUAGES.iterkeys() if x == 'all' else [x]
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700410 for x in args.language))
411
Jan Tattermusch6d7fa552016-04-14 17:42:54 -0700412
Jan Tattermuschb2758442016-03-28 09:32:20 -0700413# Put together set of remote hosts where to run and build
414remote_hosts = set()
415if args.remote_worker_host:
416 for host in args.remote_worker_host:
417 remote_hosts.add(host)
418if args.remote_driver_host:
419 remote_hosts.add(args.remote_driver_host)
420
Craig Tiller677966a2016-09-26 07:37:28 -0700421if not args.dry_run:
422 if remote_hosts:
423 archive_repo(languages=[str(l) for l in languages])
424 prepare_remote_hosts(remote_hosts, prepare_local=True)
425 else:
426 prepare_remote_hosts([], prepare_local=True)
Jan Tattermuschb2758442016-03-28 09:32:20 -0700427
428build_local = False
429if not args.remote_driver_host:
430 build_local = True
Craig Tiller677966a2016-09-26 07:37:28 -0700431if not args.dry_run:
432 build_on_remote_hosts(remote_hosts, languages=[str(l) for l in languages], build_local=build_local)
Jan Tattermuschb2758442016-03-28 09:32:20 -0700433
Craig Tillerc1b54f22016-09-15 08:57:14 -0700434qpsworker_jobs = create_qpsworkers(languages, args.remote_worker_host)
Jan Tattermusch38becc22016-04-14 08:00:35 -0700435
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700436# get list of worker addresses for each language.
Craig Tillerc1b54f22016-09-15 08:57:14 -0700437workers_by_lang = dict([(str(language), []) for language in languages])
Jan Tattermuschbb1a4532016-03-30 18:04:01 -0700438for job in qpsworker_jobs:
Craig Tillerc1b54f22016-09-15 08:57:14 -0700439 workers_by_lang[str(job.language)].append(job)
Jan Tattermuschb2758442016-03-28 09:32:20 -0700440
Craig Tillerc1b54f22016-09-15 08:57:14 -0700441scenarios = create_scenarios(languages,
Craig Tillerd82fccc2016-09-15 09:15:23 -0700442 workers_by_lang=workers_by_lang,
Craig Tillerc1b54f22016-09-15 08:57:14 -0700443 remote_host=args.remote_driver_host,
444 regex=args.regex,
445 category=args.category,
446 bq_result_table=args.bq_result_table,
447 netperf=args.netperf,
448 netperf_hosts=args.remote_worker_host)
Jan Tattermusch4de2c322016-05-10 14:33:07 -0700449
Craig Tillerc1b54f22016-09-15 08:57:14 -0700450if not scenarios:
451 raise Exception('No scenarios to run')
Jan Tattermuschb2758442016-03-28 09:32:20 -0700452
Craig Tillerc1b54f22016-09-15 08:57:14 -0700453for scenario in scenarios:
Craig Tiller677966a2016-09-26 07:37:28 -0700454 if args.dry_run:
455 print(scenario.name)
456 else:
457 try:
458 for worker in scenario.workers:
459 worker.start()
460 jobset.run([scenario.jobspec,
461 create_quit_jobspec(scenario.workers, remote_host=args.remote_driver_host)],
462 newline_on_success=True, maxjobs=1)
463 finally:
464 finish_qps_workers(scenario.workers)