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