8from __future__
import print_function
10from _benchresult
import BenchResult
11from _hardware
import HardwareException, Hardware
12from argparse
import ArgumentParser
13from multiprocessing
import Queue
14from threading
import Thread, Timer
23__argparse = ArgumentParser(description=
"""
25Executes the skpbench binary with various configs and skps.
27Also monitors the output in order to filter out and re-run results that have an
32__argparse.add_argument(
'skpbench',
33 help=
"path to the skpbench binary")
34__argparse.add_argument(
'--adb',
35 action=
'store_true', help=
"execute skpbench over adb")
36__argparse.add_argument(
'--adb_binary', default=
'adb',
37 help=
"The name of the adb binary to use.")
38__argparse.add_argument(
'-s',
'--device-serial',
39 help=
"if using adb, ID of the specific device to target "
40 "(only required if more than 1 device is attached)")
41__argparse.add_argument(
'-m',
'--max-stddev',
42 type=float, default=4,
43 help=
"initial max allowable relative standard deviation")
44__argparse.add_argument(
'-x',
'--suffix',
45 help=
"suffix to append on config (e.g. '_before', '_after')")
46__argparse.add_argument(
'-w',
'--write-path',
47 help=
"directory to save .png proofs to disk.")
48__argparse.add_argument(
'-v',
'--verbosity',
49 type=int, default=1, help=
"level of verbosity (0=none to 5=debug)")
50__argparse.add_argument(
'-d',
'--duration',
51 type=int, help=
"number of milliseconds to run each benchmark")
52__argparse.add_argument(
'-l',
'--sample-ms',
53 type=int, help=
"duration of a sample (minimum)")
54__argparse.add_argument(
'--gpu',
56 help=
"perform timing on the gpu clock instead of cpu (gpu work only)")
57__argparse.add_argument(
'--fps',
58 action=
'store_true', help=
"use fps instead of ms")
59__argparse.add_argument(
'--pr',
60 help=
"comma- or space-separated list of GPU path renderers, including: "
61 "[[~]all [~]default [~]dashline [~]msaa [~]aaconvex "
62 "[~]aalinearizing [~]small [~]tess]")
63__argparse.add_argument(
'--cc',
64 action=
'store_true', help=
"allow coverage counting shortcuts to render paths")
65__argparse.add_argument(
'--nocache',
66 action=
'store_true', help=
"disable caching of path mask textures")
67__argparse.add_argument(
'--allPathsVolatile',
69 help=
"Causes all GPU paths to be processed as if 'setIsVolatile' had been called.")
70__argparse.add_argument(
'-c',
'--config',
71 default=
'gl', help=
"comma- or space-separated list of GPU configs")
72__argparse.add_argument(
'-a',
'--resultsfile',
73 help=
"optional file to append results into")
74__argparse.add_argument(
'--ddl',
75 action=
'store_true', help=
"record the skp into DDLs before rendering")
76__argparse.add_argument(
'--lock-clocks',
77 action=
'store_true', help=
"Put device in benchmarking mode (locked clocks, no other processes)")
78__argparse.add_argument(
'--clock-speed',
79 type=float, default=66.0, help=
"A number between 0 and 100 indicating how fast to lock the CPU and GPU clock."
80 "Valid speeds are chosen from their respective available frequencies list.")
81__argparse.add_argument(
'--ddlNumRecordingThreads',
83 help=
"number of DDL recording threads (0=num_cores)")
84__argparse.add_argument(
'--ddlTilingWidthHeight',
85 type=int, default=0, help=
"number of tiles along one edge when in DDL mode")
86__argparse.add_argument(
'--dontReduceOpsTaskSplitting',
87 action=
'store_true', help=
"don't reorder GPU tasks to reduce render target swaps")
88__argparse.add_argument(
'--gpuThreads',
90 help=
"Create this many extra threads to assist with GPU work, including"
91 " software path rendering. Defaults to two.")
92__argparse.add_argument(
'--internalSamples',
94 help=
"Number of samples for internal draws that use MSAA.")
95__argparse.add_argument(
'srcs',
97 help=
".skp files or directories to expand for .skp files, and/or .svg files")
98__argparse.add_argument(
'--gpuResourceCacheLimit',
100 help=
"Maximum number of bytes to use for budgeted GPU resources.")
102FLAGS = __argparse.parse_args()
104 import _adb_path
as _path
105 _path.init(FLAGS.device_serial, FLAGS.adb_binary)
107 import _os_path
as _path
110 if FLAGS.verbosity >= 5:
111 quoted = [
'\'%s\'' % re.sub(
r'([\\\'])',
r'\\\1', x)
for x
in commandline]
130 Thread.__init__(self)
133 """Runs on the background thread."""
134 for line
in iter(self.
_proc.stdout.readline, b
''):
135 self.
_queue.put(
Message(Message.READLINE, line.decode(
'utf-8').rstrip()))
139 ARGV = [FLAGS.skpbench,
'--verbosity', str(FLAGS.verbosity)]
141 ARGV.extend([
'--duration', str(FLAGS.duration)])
143 ARGV.extend([
'--sampleMs', str(FLAGS.sample_ms)])
145 ARGV.extend([
'--gpuClock',
'true'])
147 ARGV.extend([
'--fps',
'true'])
149 ARGV.extend([
'--pr'] + re.split(
r'[ ,]', FLAGS.pr))
151 ARGV.extend([
'--cc',
'true'])
153 ARGV.extend([
'--cachePathMasks',
'false'])
154 if FLAGS.allPathsVolatile:
155 ARGV.extend([
'--allPathsVolatile',
'true'])
156 if FLAGS.gpuThreads != -1:
157 ARGV.extend([
'--gpuThreads', str(FLAGS.gpuThreads)])
158 if FLAGS.internalSamples != -1:
159 ARGV.extend([
'--internalSamples', str(FLAGS.internalSamples)])
163 ARGV.extend([
'--ddl',
'true'])
164 if FLAGS.ddlNumRecordingThreads:
165 ARGV.extend([
'--ddlNumRecordingThreads',
166 str(FLAGS.ddlNumRecordingThreads)])
167 if FLAGS.ddlTilingWidthHeight:
168 ARGV.extend([
'--ddlTilingWidthHeight', str(FLAGS.ddlTilingWidthHeight)])
170 if FLAGS.dontReduceOpsTaskSplitting:
171 ARGV.extend([
'--dontReduceOpsTaskSplitting'])
173 if FLAGS.gpuResourceCacheLimit:
174 ARGV.extend([
'--gpuResourceCacheLimit', str(FLAGS.gpuResourceCacheLimit)])
177 if FLAGS.device_serial
is None:
178 ARGV[:0] = [FLAGS.adb_binary,
'shell']
180 ARGV[:0] = [FLAGS.adb_binary,
'-s', FLAGS.device_serial,
'shell']
184 commandline = cls.
ARGV + [
'--duration',
'0']
186 out = subprocess.check_output(commandline, stderr=subprocess.STDOUT, encoding=
'utf-8')
193 print(
'running %i second warmup...' % warmup_time, file=sys.stderr)
194 commandline = cls.
ARGV + [
'--duration', str(warmup_time * 1000),
198 output = subprocess.check_output(commandline, stderr=subprocess.STDOUT, encoding=
'utf-8')
201 for line
in output.split(
'\n'):
202 match = BenchResult.match(line.rstrip())
203 if match
and match.bench ==
'warmup':
205 raise Exception(
'Invalid warmup output:\n%s' % output)
207 def __init__(self, src, config, max_stddev, best_result=None):
220 def __exit__(self, exception_type, exception_value, traceback):
227 hardware.sanity_check()
230 commandline = self.
ARGV + [
'--config', self.
config,
232 '--suppressHeader',
'true']
234 pngfile = _path.join(FLAGS.write_path, self.
config,
235 _path.basename(self.
src) +
'.png')
236 commandline.extend([
'--png', pngfile])
238 self.
_proc = subprocess.Popen(commandline, stdout=subprocess.PIPE,
239 stderr=subprocess.STDOUT)
245 if message.message == Message.READLINE:
246 result = BenchResult.match(message.value)
248 hardware.sanity_check()
250 elif hardware.filter_line(message.value):
251 print(message.value, file=sys.stderr)
253 if message.message == Message.POLL_HARDWARE:
254 hardware.sanity_check()
257 if message.message == Message.EXIT:
260 if self.
_proc.returncode != 0:
261 raise Exception(
"skpbench exited with nonzero exit code %i" %
262 self.
_proc.returncode)
266 def _schedule_hardware_poll(self):
270 Timer(1,
lambda: self.
_queue.put(
Message(Message.POLL_HARDWARE)))
273 def _process_result(self, result):
276 elif FLAGS.verbosity >= 2:
277 print(
"reusing previous result for %s/%s with lower stddev "
278 "(%s%% instead of %s%%)." %
279 (result.config, result.bench, self.
best_result.stddev,
280 result.stddev), file=sys.stderr)
295 print(line, file=resultsfile)
300 benches = collections.deque([(src, config, FLAGS.max_stddev)
302 for config
in configs])
306 SKPBench.run_warmup(hardware.warmup_time, configs[0])
311 benchargs = benches.popleft()
312 with SKPBench(*benchargs)
as skpbench:
314 skpbench.execute(hardware)
315 if skpbench.best_result:
316 emit_result(skpbench.best_result.format(FLAGS.suffix),
319 print(
"WARNING: no result for %s with config %s" %
320 (skpbench.src, skpbench.config), file=sys.stderr)
322 except StddevException:
323 retry_max_stddev = skpbench.max_stddev * math.sqrt(2)
324 if FLAGS.verbosity >= 1:
325 print(
"stddev is too high for %s/%s (%s%%, max=%.2f%%), "
326 "re-queuing with max=%.2f%%." %
327 (skpbench.best_result.config, skpbench.best_result.bench,
328 skpbench.best_result.stddev, skpbench.max_stddev,
331 benches.append((skpbench.src, skpbench.config, retry_max_stddev,
332 skpbench.best_result))
334 except HardwareException
as exception:
336 if FLAGS.verbosity >= 4:
337 hardware.print_debug_diagnostics()
338 if FLAGS.verbosity >= 1:
339 print(
"%s; rebooting and taking a %i second nap..." %
340 (exception.message, exception.sleeptime), file=sys.stderr)
341 benches.appendleft(benchargs)
344 except HardwareException
as exception:
345 time.sleep(exception.sleeptime)
349 DELIMITER =
r'[, ](?!(?:[^(]*\([^)]*\))*[^()]*\))'
350 configs = re.split(DELIMITER, FLAGS.config)
351 srcs = _path.find_skps(FLAGS.srcs)
356 adb =
Adb(FLAGS.device_serial, FLAGS.adb_binary,
357 echo=(FLAGS.verbosity >= 5))
358 from _hardware_android
import HardwareAndroid
360 model = adb.check(
'getprop ro.product.model').strip()
361 if model ==
'Pixel C':
362 from _hardware_pixel_c
import HardwarePixelC
363 hardware = HardwarePixelC(adb)
364 elif model ==
'Pixel' or model ==
"Pixel XL":
365 from _hardware_pixel
import HardwarePixel
366 hardware = HardwarePixel(adb)
367 elif model ==
'Pixel 2':
368 from _hardware_pixel2
import HardwarePixel2
369 hardware = HardwarePixel2(adb)
370 elif model ==
'Nexus 6P':
371 from _hardware_nexus_6p
import HardwareNexus6P
372 hardware = HardwareNexus6P(adb)
374 print(
"WARNING: %s: don't know how to monitor this hardware; results "
375 "may be unreliable." % model, file=sys.stderr)
376 hardware = HardwareAndroid(adb)
378 if FLAGS.lock_clocks:
380 print(
"Entered benchmarking mode, not running benchmarks. Reboot to restore.");
383 if FLAGS.clock_speed:
384 hardware.setDesiredClock(FLAGS.clock_speed)
388 if FLAGS.resultsfile:
389 with open(FLAGS.resultsfile, mode=
'a+')
as resultsfile:
395if __name__ ==
'__main__':
const myers::Point & get(const myers::Segment &)
def print(*args, **kwargs)
static SkString join(const CommandLineFlags::StringArray &)