1cb93a386Sopenharmony_ci#!/usr/bin/env python
2cb93a386Sopenharmony_ci
3cb93a386Sopenharmony_ci# Copyright 2016 Google Inc.
4cb93a386Sopenharmony_ci#
5cb93a386Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be
6cb93a386Sopenharmony_ci# found in the LICENSE file.
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_cifrom __future__ import print_function
9cb93a386Sopenharmony_cifrom _adb import Adb
10cb93a386Sopenharmony_cifrom _benchresult import BenchResult
11cb93a386Sopenharmony_cifrom _hardware import HardwareException, Hardware
12cb93a386Sopenharmony_cifrom argparse import ArgumentParser
13cb93a386Sopenharmony_cifrom multiprocessing import Queue
14cb93a386Sopenharmony_cifrom threading import Thread, Timer
15cb93a386Sopenharmony_ciimport collections
16cb93a386Sopenharmony_ciimport glob
17cb93a386Sopenharmony_ciimport math
18cb93a386Sopenharmony_ciimport re
19cb93a386Sopenharmony_ciimport subprocess
20cb93a386Sopenharmony_ciimport sys
21cb93a386Sopenharmony_ciimport time
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ci__argparse = ArgumentParser(description="""
24cb93a386Sopenharmony_ci
25cb93a386Sopenharmony_ciExecutes the skpbench binary with various configs and skps.
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ciAlso monitors the output in order to filter out and re-run results that have an
28cb93a386Sopenharmony_ciunacceptable stddev.
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ci""")
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_ci__argparse.add_argument('skpbench',
33cb93a386Sopenharmony_ci  help="path to the skpbench binary")
34cb93a386Sopenharmony_ci__argparse.add_argument('--adb',
35cb93a386Sopenharmony_ci  action='store_true', help="execute skpbench over adb")
36cb93a386Sopenharmony_ci__argparse.add_argument('--adb_binary', default='adb',
37cb93a386Sopenharmony_ci  help="The name of the adb binary to use.")
38cb93a386Sopenharmony_ci__argparse.add_argument('-s', '--device-serial',
39cb93a386Sopenharmony_ci  help="if using adb, ID of the specific device to target "
40cb93a386Sopenharmony_ci       "(only required if more than 1 device is attached)")
41cb93a386Sopenharmony_ci__argparse.add_argument('-m', '--max-stddev',
42cb93a386Sopenharmony_ci  type=float, default=4,
43cb93a386Sopenharmony_ci  help="initial max allowable relative standard deviation")
44cb93a386Sopenharmony_ci__argparse.add_argument('-x', '--suffix',
45cb93a386Sopenharmony_ci  help="suffix to append on config (e.g. '_before', '_after')")
46cb93a386Sopenharmony_ci__argparse.add_argument('-w','--write-path',
47cb93a386Sopenharmony_ci  help="directory to save .png proofs to disk.")
48cb93a386Sopenharmony_ci__argparse.add_argument('-v','--verbosity',
49cb93a386Sopenharmony_ci  type=int, default=1, help="level of verbosity (0=none to 5=debug)")
50cb93a386Sopenharmony_ci__argparse.add_argument('-d', '--duration',
51cb93a386Sopenharmony_ci  type=int, help="number of milliseconds to run each benchmark")
52cb93a386Sopenharmony_ci__argparse.add_argument('-l', '--sample-ms',
53cb93a386Sopenharmony_ci  type=int, help="duration of a sample (minimum)")
54cb93a386Sopenharmony_ci__argparse.add_argument('--gpu',
55cb93a386Sopenharmony_ci  action='store_true',
56cb93a386Sopenharmony_ci  help="perform timing on the gpu clock instead of cpu (gpu work only)")
57cb93a386Sopenharmony_ci__argparse.add_argument('--fps',
58cb93a386Sopenharmony_ci  action='store_true', help="use fps instead of ms")
59cb93a386Sopenharmony_ci__argparse.add_argument('--pr',
60cb93a386Sopenharmony_ci  help="comma- or space-separated list of GPU path renderers, including: "
61cb93a386Sopenharmony_ci       "[[~]all [~]default [~]dashline [~]msaa [~]aaconvex "
62cb93a386Sopenharmony_ci       "[~]aalinearizing [~]small [~]tess]")
63cb93a386Sopenharmony_ci__argparse.add_argument('--cc',
64cb93a386Sopenharmony_ci  action='store_true', help="allow coverage counting shortcuts to render paths")
65cb93a386Sopenharmony_ci__argparse.add_argument('--nocache',
66cb93a386Sopenharmony_ci  action='store_true', help="disable caching of path mask textures")
67cb93a386Sopenharmony_ci__argparse.add_argument('--allPathsVolatile',
68cb93a386Sopenharmony_ci  action='store_true',
69cb93a386Sopenharmony_ci  help="Causes all GPU paths to be processed as if 'setIsVolatile' had been called.")
70cb93a386Sopenharmony_ci__argparse.add_argument('-c', '--config',
71cb93a386Sopenharmony_ci  default='gl', help="comma- or space-separated list of GPU configs")
72cb93a386Sopenharmony_ci__argparse.add_argument('-a', '--resultsfile',
73cb93a386Sopenharmony_ci  help="optional file to append results into")
74cb93a386Sopenharmony_ci__argparse.add_argument('--ddl',
75cb93a386Sopenharmony_ci  action='store_true', help="record the skp into DDLs before rendering")
76cb93a386Sopenharmony_ci__argparse.add_argument('--lock-clocks',
77cb93a386Sopenharmony_ci  action='store_true', help="Put device in benchmarking mode (locked clocks, no other processes)")
78cb93a386Sopenharmony_ci__argparse.add_argument('--clock-speed',
79cb93a386Sopenharmony_ci  type=float, default=66.0, help="A number between 0 and 100 indicating how fast to lock the CPU and GPU clock."
80cb93a386Sopenharmony_ci  "Valid speeds are chosen from their respective available frequencies list.")
81cb93a386Sopenharmony_ci__argparse.add_argument('--ddlNumRecordingThreads',
82cb93a386Sopenharmony_ci  type=int, default=0,
83cb93a386Sopenharmony_ci  help="number of DDL recording threads (0=num_cores)")
84cb93a386Sopenharmony_ci__argparse.add_argument('--ddlTilingWidthHeight',
85cb93a386Sopenharmony_ci  type=int, default=0, help="number of tiles along one edge when in DDL mode")
86cb93a386Sopenharmony_ci__argparse.add_argument('--dontReduceOpsTaskSplitting',
87cb93a386Sopenharmony_ci  action='store_true', help="don't reorder GPU tasks to reduce render target swaps")
88cb93a386Sopenharmony_ci__argparse.add_argument('--gpuThreads',
89cb93a386Sopenharmony_ci  type=int, default=-1,
90cb93a386Sopenharmony_ci  help="Create this many extra threads to assist with GPU work, including"
91cb93a386Sopenharmony_ci       " software path rendering. Defaults to two.")
92cb93a386Sopenharmony_ci__argparse.add_argument('--internalSamples',
93cb93a386Sopenharmony_ci  type=int, default=-1,
94cb93a386Sopenharmony_ci  help="Number of samples for internal draws that use MSAA.")
95cb93a386Sopenharmony_ci__argparse.add_argument('srcs',
96cb93a386Sopenharmony_ci  nargs='+',
97cb93a386Sopenharmony_ci  help=".skp files or directories to expand for .skp files, and/or .svg files")
98cb93a386Sopenharmony_ci__argparse.add_argument('--gpuResourceCacheLimit',
99cb93a386Sopenharmony_ci  type=int, default=-1,
100cb93a386Sopenharmony_ci  help="Maximum number of bytes to use for budgeted GPU resources.")
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_ciFLAGS = __argparse.parse_args()
103cb93a386Sopenharmony_ciif FLAGS.adb:
104cb93a386Sopenharmony_ci  import _adb_path as _path
105cb93a386Sopenharmony_ci  _path.init(FLAGS.device_serial, FLAGS.adb_binary)
106cb93a386Sopenharmony_cielse:
107cb93a386Sopenharmony_ci  import _os_path as _path
108cb93a386Sopenharmony_ci
109cb93a386Sopenharmony_cidef dump_commandline_if_verbose(commandline):
110cb93a386Sopenharmony_ci  if FLAGS.verbosity >= 5:
111cb93a386Sopenharmony_ci    quoted = ['\'%s\'' % re.sub(r'([\\\'])', r'\\\1', x) for x in commandline]
112cb93a386Sopenharmony_ci    print(' '.join(quoted), file=sys.stderr)
113cb93a386Sopenharmony_ci
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ciclass StddevException(Exception):
116cb93a386Sopenharmony_ci  pass
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ciclass Message:
119cb93a386Sopenharmony_ci  READLINE = 0,
120cb93a386Sopenharmony_ci  POLL_HARDWARE = 1,
121cb93a386Sopenharmony_ci  EXIT = 2
122cb93a386Sopenharmony_ci  def __init__(self, message, value=None):
123cb93a386Sopenharmony_ci    self.message = message
124cb93a386Sopenharmony_ci    self.value = value
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ciclass SubprocessMonitor(Thread):
127cb93a386Sopenharmony_ci  def __init__(self, queue, proc):
128cb93a386Sopenharmony_ci    self._queue = queue
129cb93a386Sopenharmony_ci    self._proc = proc
130cb93a386Sopenharmony_ci    Thread.__init__(self)
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_ci  def run(self):
133cb93a386Sopenharmony_ci    """Runs on the background thread."""
134cb93a386Sopenharmony_ci    for line in iter(self._proc.stdout.readline, b''):
135cb93a386Sopenharmony_ci      self._queue.put(Message(Message.READLINE, line.decode('utf-8').rstrip()))
136cb93a386Sopenharmony_ci    self._queue.put(Message(Message.EXIT))
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ciclass SKPBench:
139cb93a386Sopenharmony_ci  ARGV = [FLAGS.skpbench, '--verbosity', str(FLAGS.verbosity)]
140cb93a386Sopenharmony_ci  if FLAGS.duration:
141cb93a386Sopenharmony_ci    ARGV.extend(['--duration', str(FLAGS.duration)])
142cb93a386Sopenharmony_ci  if FLAGS.sample_ms:
143cb93a386Sopenharmony_ci    ARGV.extend(['--sampleMs', str(FLAGS.sample_ms)])
144cb93a386Sopenharmony_ci  if FLAGS.gpu:
145cb93a386Sopenharmony_ci    ARGV.extend(['--gpuClock', 'true'])
146cb93a386Sopenharmony_ci  if FLAGS.fps:
147cb93a386Sopenharmony_ci    ARGV.extend(['--fps', 'true'])
148cb93a386Sopenharmony_ci  if FLAGS.pr:
149cb93a386Sopenharmony_ci    ARGV.extend(['--pr'] + re.split(r'[ ,]', FLAGS.pr))
150cb93a386Sopenharmony_ci  if FLAGS.cc:
151cb93a386Sopenharmony_ci    ARGV.extend(['--cc', 'true'])
152cb93a386Sopenharmony_ci  if FLAGS.nocache:
153cb93a386Sopenharmony_ci    ARGV.extend(['--cachePathMasks', 'false'])
154cb93a386Sopenharmony_ci  if FLAGS.allPathsVolatile:
155cb93a386Sopenharmony_ci    ARGV.extend(['--allPathsVolatile', 'true'])
156cb93a386Sopenharmony_ci  if FLAGS.gpuThreads != -1:
157cb93a386Sopenharmony_ci    ARGV.extend(['--gpuThreads', str(FLAGS.gpuThreads)])
158cb93a386Sopenharmony_ci  if FLAGS.internalSamples != -1:
159cb93a386Sopenharmony_ci    ARGV.extend(['--internalSamples', str(FLAGS.internalSamples)])
160cb93a386Sopenharmony_ci
161cb93a386Sopenharmony_ci  # DDL parameters
162cb93a386Sopenharmony_ci  if FLAGS.ddl:
163cb93a386Sopenharmony_ci    ARGV.extend(['--ddl', 'true'])
164cb93a386Sopenharmony_ci  if FLAGS.ddlNumRecordingThreads:
165cb93a386Sopenharmony_ci    ARGV.extend(['--ddlNumRecordingThreads',
166cb93a386Sopenharmony_ci                 str(FLAGS.ddlNumRecordingThreads)])
167cb93a386Sopenharmony_ci  if FLAGS.ddlTilingWidthHeight:
168cb93a386Sopenharmony_ci    ARGV.extend(['--ddlTilingWidthHeight', str(FLAGS.ddlTilingWidthHeight)])
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci  if FLAGS.dontReduceOpsTaskSplitting:
171cb93a386Sopenharmony_ci    ARGV.extend(['--dontReduceOpsTaskSplitting'])
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci  if FLAGS.gpuResourceCacheLimit:
174cb93a386Sopenharmony_ci    ARGV.extend(['--gpuResourceCacheLimit', str(FLAGS.gpuResourceCacheLimit)])
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ci  if FLAGS.adb:
177cb93a386Sopenharmony_ci    if FLAGS.device_serial is None:
178cb93a386Sopenharmony_ci      ARGV[:0] = [FLAGS.adb_binary, 'shell']
179cb93a386Sopenharmony_ci    else:
180cb93a386Sopenharmony_ci      ARGV[:0] = [FLAGS.adb_binary, '-s', FLAGS.device_serial, 'shell']
181cb93a386Sopenharmony_ci
182cb93a386Sopenharmony_ci  @classmethod
183cb93a386Sopenharmony_ci  def get_header(cls, outfile=sys.stdout):
184cb93a386Sopenharmony_ci    commandline = cls.ARGV + ['--duration', '0']
185cb93a386Sopenharmony_ci    dump_commandline_if_verbose(commandline)
186cb93a386Sopenharmony_ci    out = subprocess.check_output(commandline, stderr=subprocess.STDOUT)
187cb93a386Sopenharmony_ci    return out.rstrip()
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_ci  @classmethod
190cb93a386Sopenharmony_ci  def run_warmup(cls, warmup_time, config):
191cb93a386Sopenharmony_ci    if not warmup_time:
192cb93a386Sopenharmony_ci      return
193cb93a386Sopenharmony_ci    print('running %i second warmup...' % warmup_time, file=sys.stderr)
194cb93a386Sopenharmony_ci    commandline = cls.ARGV + ['--duration', str(warmup_time * 1000),
195cb93a386Sopenharmony_ci                              '--config', config,
196cb93a386Sopenharmony_ci                              '--src', 'warmup']
197cb93a386Sopenharmony_ci    dump_commandline_if_verbose(commandline)
198cb93a386Sopenharmony_ci    output = subprocess.check_output(commandline, stderr=subprocess.STDOUT)
199cb93a386Sopenharmony_ci
200cb93a386Sopenharmony_ci    # validate the warmup run output.
201cb93a386Sopenharmony_ci    for line in output.decode('utf-8').split('\n'):
202cb93a386Sopenharmony_ci      match = BenchResult.match(line.rstrip())
203cb93a386Sopenharmony_ci      if match and match.bench == 'warmup':
204cb93a386Sopenharmony_ci        return
205cb93a386Sopenharmony_ci    raise Exception('Invalid warmup output:\n%s' % output)
206cb93a386Sopenharmony_ci
207cb93a386Sopenharmony_ci  def __init__(self, src, config, max_stddev, best_result=None):
208cb93a386Sopenharmony_ci    self.src = src
209cb93a386Sopenharmony_ci    self.config = config
210cb93a386Sopenharmony_ci    self.max_stddev = max_stddev
211cb93a386Sopenharmony_ci    self.best_result = best_result
212cb93a386Sopenharmony_ci    self._queue = Queue()
213cb93a386Sopenharmony_ci    self._proc = None
214cb93a386Sopenharmony_ci    self._monitor = None
215cb93a386Sopenharmony_ci    self._hw_poll_timer = None
216cb93a386Sopenharmony_ci
217cb93a386Sopenharmony_ci  def __enter__(self):
218cb93a386Sopenharmony_ci    return self
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ci  def __exit__(self, exception_type, exception_value, traceback):
221cb93a386Sopenharmony_ci    if self._proc:
222cb93a386Sopenharmony_ci      self.terminate()
223cb93a386Sopenharmony_ci    if self._hw_poll_timer:
224cb93a386Sopenharmony_ci      self._hw_poll_timer.cancel()
225cb93a386Sopenharmony_ci
226cb93a386Sopenharmony_ci  def execute(self, hardware):
227cb93a386Sopenharmony_ci    hardware.sanity_check()
228cb93a386Sopenharmony_ci    self._schedule_hardware_poll()
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_ci    commandline = self.ARGV + ['--config', self.config,
231cb93a386Sopenharmony_ci                               '--src', self.src,
232cb93a386Sopenharmony_ci                               '--suppressHeader', 'true']
233cb93a386Sopenharmony_ci    if FLAGS.write_path:
234cb93a386Sopenharmony_ci      pngfile = _path.join(FLAGS.write_path, self.config,
235cb93a386Sopenharmony_ci                           _path.basename(self.src) + '.png')
236cb93a386Sopenharmony_ci      commandline.extend(['--png', pngfile])
237cb93a386Sopenharmony_ci    dump_commandline_if_verbose(commandline)
238cb93a386Sopenharmony_ci    self._proc = subprocess.Popen(commandline, stdout=subprocess.PIPE,
239cb93a386Sopenharmony_ci                                  stderr=subprocess.STDOUT)
240cb93a386Sopenharmony_ci    self._monitor = SubprocessMonitor(self._queue, self._proc)
241cb93a386Sopenharmony_ci    self._monitor.start()
242cb93a386Sopenharmony_ci
243cb93a386Sopenharmony_ci    while True:
244cb93a386Sopenharmony_ci      message = self._queue.get()
245cb93a386Sopenharmony_ci      if message.message == Message.READLINE:
246cb93a386Sopenharmony_ci        result = BenchResult.match(message.value)
247cb93a386Sopenharmony_ci        if result:
248cb93a386Sopenharmony_ci          hardware.sanity_check()
249cb93a386Sopenharmony_ci          self._process_result(result)
250cb93a386Sopenharmony_ci        elif hardware.filter_line(message.value):
251cb93a386Sopenharmony_ci          print(message.value, file=sys.stderr)
252cb93a386Sopenharmony_ci        continue
253cb93a386Sopenharmony_ci      if message.message == Message.POLL_HARDWARE:
254cb93a386Sopenharmony_ci        hardware.sanity_check()
255cb93a386Sopenharmony_ci        self._schedule_hardware_poll()
256cb93a386Sopenharmony_ci        continue
257cb93a386Sopenharmony_ci      if message.message == Message.EXIT:
258cb93a386Sopenharmony_ci        self._monitor.join()
259cb93a386Sopenharmony_ci        self._proc.wait()
260cb93a386Sopenharmony_ci        if self._proc.returncode != 0:
261cb93a386Sopenharmony_ci          raise Exception("skpbench exited with nonzero exit code %i" %
262cb93a386Sopenharmony_ci                          self._proc.returncode)
263cb93a386Sopenharmony_ci        self._proc = None
264cb93a386Sopenharmony_ci        break
265cb93a386Sopenharmony_ci
266cb93a386Sopenharmony_ci  def _schedule_hardware_poll(self):
267cb93a386Sopenharmony_ci    if self._hw_poll_timer:
268cb93a386Sopenharmony_ci      self._hw_poll_timer.cancel()
269cb93a386Sopenharmony_ci    self._hw_poll_timer = \
270cb93a386Sopenharmony_ci      Timer(1, lambda: self._queue.put(Message(Message.POLL_HARDWARE)))
271cb93a386Sopenharmony_ci    self._hw_poll_timer.start()
272cb93a386Sopenharmony_ci
273cb93a386Sopenharmony_ci  def _process_result(self, result):
274cb93a386Sopenharmony_ci    if not self.best_result or result.stddev <= self.best_result.stddev:
275cb93a386Sopenharmony_ci      self.best_result = result
276cb93a386Sopenharmony_ci    elif FLAGS.verbosity >= 2:
277cb93a386Sopenharmony_ci      print("reusing previous result for %s/%s with lower stddev "
278cb93a386Sopenharmony_ci            "(%s%% instead of %s%%)." %
279cb93a386Sopenharmony_ci            (result.config, result.bench, self.best_result.stddev,
280cb93a386Sopenharmony_ci             result.stddev), file=sys.stderr)
281cb93a386Sopenharmony_ci    if self.max_stddev and self.best_result.stddev > self.max_stddev:
282cb93a386Sopenharmony_ci      raise StddevException()
283cb93a386Sopenharmony_ci
284cb93a386Sopenharmony_ci  def terminate(self):
285cb93a386Sopenharmony_ci    if self._proc:
286cb93a386Sopenharmony_ci      self._proc.terminate()
287cb93a386Sopenharmony_ci      self._monitor.join()
288cb93a386Sopenharmony_ci      self._proc.wait()
289cb93a386Sopenharmony_ci      self._proc = None
290cb93a386Sopenharmony_ci
291cb93a386Sopenharmony_cidef emit_result(line, resultsfile=None):
292cb93a386Sopenharmony_ci  print(line)
293cb93a386Sopenharmony_ci  sys.stdout.flush()
294cb93a386Sopenharmony_ci  if resultsfile:
295cb93a386Sopenharmony_ci    print(line, file=resultsfile)
296cb93a386Sopenharmony_ci    resultsfile.flush()
297cb93a386Sopenharmony_ci
298cb93a386Sopenharmony_cidef run_benchmarks(configs, srcs, hardware, resultsfile=None):
299cb93a386Sopenharmony_ci  hasheader = False
300cb93a386Sopenharmony_ci  benches = collections.deque([(src, config, FLAGS.max_stddev)
301cb93a386Sopenharmony_ci                               for src in srcs
302cb93a386Sopenharmony_ci                               for config in configs])
303cb93a386Sopenharmony_ci  while benches:
304cb93a386Sopenharmony_ci    try:
305cb93a386Sopenharmony_ci      with hardware:
306cb93a386Sopenharmony_ci        SKPBench.run_warmup(hardware.warmup_time, configs[0])
307cb93a386Sopenharmony_ci        if not hasheader:
308cb93a386Sopenharmony_ci          emit_result(SKPBench.get_header(), resultsfile)
309cb93a386Sopenharmony_ci          hasheader = True
310cb93a386Sopenharmony_ci        while benches:
311cb93a386Sopenharmony_ci          benchargs = benches.popleft()
312cb93a386Sopenharmony_ci          with SKPBench(*benchargs) as skpbench:
313cb93a386Sopenharmony_ci            try:
314cb93a386Sopenharmony_ci              skpbench.execute(hardware)
315cb93a386Sopenharmony_ci              if skpbench.best_result:
316cb93a386Sopenharmony_ci                emit_result(skpbench.best_result.format(FLAGS.suffix),
317cb93a386Sopenharmony_ci                            resultsfile)
318cb93a386Sopenharmony_ci              else:
319cb93a386Sopenharmony_ci                print("WARNING: no result for %s with config %s" %
320cb93a386Sopenharmony_ci                      (skpbench.src, skpbench.config), file=sys.stderr)
321cb93a386Sopenharmony_ci
322cb93a386Sopenharmony_ci            except StddevException:
323cb93a386Sopenharmony_ci              retry_max_stddev = skpbench.max_stddev * math.sqrt(2)
324cb93a386Sopenharmony_ci              if FLAGS.verbosity >= 1:
325cb93a386Sopenharmony_ci                print("stddev is too high for %s/%s (%s%%, max=%.2f%%), "
326cb93a386Sopenharmony_ci                      "re-queuing with max=%.2f%%." %
327cb93a386Sopenharmony_ci                      (skpbench.best_result.config, skpbench.best_result.bench,
328cb93a386Sopenharmony_ci                       skpbench.best_result.stddev, skpbench.max_stddev,
329cb93a386Sopenharmony_ci                       retry_max_stddev),
330cb93a386Sopenharmony_ci                      file=sys.stderr)
331cb93a386Sopenharmony_ci              benches.append((skpbench.src, skpbench.config, retry_max_stddev,
332cb93a386Sopenharmony_ci                              skpbench.best_result))
333cb93a386Sopenharmony_ci
334cb93a386Sopenharmony_ci            except HardwareException as exception:
335cb93a386Sopenharmony_ci              skpbench.terminate()
336cb93a386Sopenharmony_ci              if FLAGS.verbosity >= 4:
337cb93a386Sopenharmony_ci                hardware.print_debug_diagnostics()
338cb93a386Sopenharmony_ci              if FLAGS.verbosity >= 1:
339cb93a386Sopenharmony_ci                print("%s; rebooting and taking a %i second nap..." %
340cb93a386Sopenharmony_ci                      (exception.message, exception.sleeptime), file=sys.stderr)
341cb93a386Sopenharmony_ci              benches.appendleft(benchargs) # retry the same bench next time.
342cb93a386Sopenharmony_ci              raise # wake hw up from benchmarking mode before the nap.
343cb93a386Sopenharmony_ci
344cb93a386Sopenharmony_ci    except HardwareException as exception:
345cb93a386Sopenharmony_ci      time.sleep(exception.sleeptime)
346cb93a386Sopenharmony_ci
347cb93a386Sopenharmony_cidef main():
348cb93a386Sopenharmony_ci  # Delimiter is ',' or ' ', skip if nested inside parens (e.g. gpu(a=b,c=d)).
349cb93a386Sopenharmony_ci  DELIMITER = r'[, ](?!(?:[^(]*\([^)]*\))*[^()]*\))'
350cb93a386Sopenharmony_ci  configs = re.split(DELIMITER, FLAGS.config)
351cb93a386Sopenharmony_ci  srcs = _path.find_skps(FLAGS.srcs)
352cb93a386Sopenharmony_ci  assert srcs
353cb93a386Sopenharmony_ci
354cb93a386Sopenharmony_ci
355cb93a386Sopenharmony_ci  if FLAGS.adb:
356cb93a386Sopenharmony_ci    adb = Adb(FLAGS.device_serial, FLAGS.adb_binary,
357cb93a386Sopenharmony_ci              echo=(FLAGS.verbosity >= 5))
358cb93a386Sopenharmony_ci    from _hardware_android import HardwareAndroid
359cb93a386Sopenharmony_ci
360cb93a386Sopenharmony_ci    model = adb.check('getprop ro.product.model').strip()
361cb93a386Sopenharmony_ci    if model == 'Pixel C':
362cb93a386Sopenharmony_ci      from _hardware_pixel_c import HardwarePixelC
363cb93a386Sopenharmony_ci      hardware = HardwarePixelC(adb)
364cb93a386Sopenharmony_ci    elif model == 'Pixel' or model == "Pixel XL":
365cb93a386Sopenharmony_ci      from _hardware_pixel import HardwarePixel
366cb93a386Sopenharmony_ci      hardware = HardwarePixel(adb)
367cb93a386Sopenharmony_ci    elif model == 'Pixel 2':
368cb93a386Sopenharmony_ci      from _hardware_pixel2 import HardwarePixel2
369cb93a386Sopenharmony_ci      hardware = HardwarePixel2(adb)
370cb93a386Sopenharmony_ci    elif model == 'Nexus 6P':
371cb93a386Sopenharmony_ci      from _hardware_nexus_6p import HardwareNexus6P
372cb93a386Sopenharmony_ci      hardware = HardwareNexus6P(adb)
373cb93a386Sopenharmony_ci    else:
374cb93a386Sopenharmony_ci      print("WARNING: %s: don't know how to monitor this hardware; results "
375cb93a386Sopenharmony_ci            "may be unreliable." % model, file=sys.stderr)
376cb93a386Sopenharmony_ci      hardware = HardwareAndroid(adb)
377cb93a386Sopenharmony_ci
378cb93a386Sopenharmony_ci    if FLAGS.lock_clocks:
379cb93a386Sopenharmony_ci      hardware.__enter__()
380cb93a386Sopenharmony_ci      print("Entered benchmarking mode, not running benchmarks. Reboot to restore.");
381cb93a386Sopenharmony_ci      return;
382cb93a386Sopenharmony_ci
383cb93a386Sopenharmony_ci    if FLAGS.clock_speed:
384cb93a386Sopenharmony_ci      hardware.setDesiredClock(FLAGS.clock_speed)
385cb93a386Sopenharmony_ci  else:
386cb93a386Sopenharmony_ci    hardware = Hardware()
387cb93a386Sopenharmony_ci
388cb93a386Sopenharmony_ci  if FLAGS.resultsfile:
389cb93a386Sopenharmony_ci    with open(FLAGS.resultsfile, mode='a+') as resultsfile:
390cb93a386Sopenharmony_ci      run_benchmarks(configs, srcs, hardware, resultsfile=resultsfile)
391cb93a386Sopenharmony_ci  else:
392cb93a386Sopenharmony_ci    run_benchmarks(configs, srcs, hardware)
393cb93a386Sopenharmony_ci
394cb93a386Sopenharmony_ci
395cb93a386Sopenharmony_ciif __name__ == '__main__':
396cb93a386Sopenharmony_ci  main()
397