Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(137)

Unified Diff: tools/skpbench/skpbench.py

Issue 2360473002: Add hardware monitoring to skpbench (Closed)
Patch Set: Add hardware monitoring to skpbench Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/skpbench/skpbench.cpp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/skpbench/skpbench.py
diff --git a/tools/skpbench/skpbench.py b/tools/skpbench/skpbench.py
index 94d68b28e401129a1608a3bae1b5b9645a2153e6..b84b0703a00ebc584c7b00f6ce20a27e992c1948 100755
--- a/tools/skpbench/skpbench.py
+++ b/tools/skpbench/skpbench.py
@@ -6,57 +6,60 @@
# found in the LICENSE file.
from __future__ import print_function
+from _adb import Adb
from _benchresult import BenchResult
+from _hardware import HardwareException, Hardware
from argparse import ArgumentParser
from queue import Queue
-from threading import Thread
+from threading import Thread, Timer
import collections
import glob
import math
import re
import subprocess
import sys
+import time
-__argparse = ArgumentParser(description="""
+__argparse = ArgumentParser(description='''
Executes the skpbench binary with various configs and skps.
Also monitors the output in order to filter out and re-run results that have an
unacceptable stddev.
-""")
+''')
__argparse.add_argument('--adb',
- action='store_true', help='execute skpbench over adb')
+ action='store_true', help="execute skpbench over adb")
__argparse.add_argument('-s', '--device-serial',
- help='if using adb, id of the specific device to target')
+ help="if using adb, id of the specific device to target")
__argparse.add_argument('-p', '--path',
- help='directory to execute ./skpbench from')
+ help="directory to execute ./skpbench from")
__argparse.add_argument('-m', '--max-stddev',
type=float, default=4,
- help='initial max allowable relative standard deviation')
+ help="initial max allowable relative standard deviation")
__argparse.add_argument('-x', '--suffix',
- help='suffix to append on config (e.g. "_before", "_after")')
+ help="suffix to append on config (e.g. '_before', '_after')")
__argparse.add_argument('-w','--write-path',
- help='directory to save .png proofs to disk.')
+ help="directory to save .png proofs to disk.")
__argparse.add_argument('-v','--verbosity',
- type=int, default=0, help='level of verbosity (0=none to 5=debug)')
+ type=int, default=1, help="level of verbosity (0=none to 5=debug)")
__argparse.add_argument('-n', '--samples',
- type=int, help='number of samples to collect for each bench')
+ type=int, help="number of samples to collect for each bench")
__argparse.add_argument('-d', '--sample-ms',
- type=int, help='duration of each sample')
+ type=int, help="duration of each sample")
__argparse.add_argument('--fps',
- action='store_true', help='use fps instead of ms')
+ action='store_true', help="use fps instead of ms")
__argparse.add_argument('-c', '--config',
- default='gpu', help='comma- or space-separated list of GPU configs')
+ default='gpu', help="comma- or space-separated list of GPU configs")
__argparse.add_argument('skps',
nargs='+',
- help='.skp files or directories to expand for .skp files')
+ help=".skp files or directories to expand for .skp files")
FLAGS = __argparse.parse_args()
if FLAGS.adb:
import _adb_path as _path
- _path.set_device_serial(FLAGS.device_serial)
+ _path.init(FLAGS.device_serial)
else:
import _os_path as _path
@@ -66,12 +69,25 @@ class StddevException(Exception):
class Message:
READLINE = 0,
- EXIT = 1
+ POLL_HARDWARE = 1,
+ EXIT = 2
def __init__(self, message, value=None):
self.message = message
self.value = value
-class SKPBench(Thread):
+class SubprocessMonitor(Thread):
+ def __init__(self, queue, proc):
+ self._queue = queue
+ self._proc = proc
+ Thread.__init__(self)
+
+ def run(self):
+ '''Runs on the background thread.'''
+ for line in iter(self._proc.stdout.readline, b''):
+ self._queue.put(Message(Message.READLINE, line.decode('utf-8').rstrip()))
+ self._queue.put(Message(Message.EXIT))
+
+class SKPBench:
ARGV = ['skpbench', '--verbosity', str(FLAGS.verbosity)]
if FLAGS.samples:
ARGV.extend(['--samples', str(FLAGS.samples)])
@@ -97,86 +113,152 @@ class SKPBench(Thread):
self.max_stddev = max_stddev
self.best_result = best_result
self._queue = Queue()
- Thread.__init__(self)
+ self._proc = None
+ self._monitor = None
+ self._hw_poll_timer = None
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exception_type, exception_value, traceback):
+ if self._proc:
+ self.terminate()
+ if self._hw_poll_timer:
+ self._hw_poll_timer.cancel()
+
+ def execute(self, hardware):
+ hardware.sanity_check()
+ self._schedule_hardware_poll()
+
+ commandline = self.ARGV + ['--config', self.config,
+ '--skp', self.skp,
+ '--suppressHeader', 'true']
+ if FLAGS.write_path:
+ pngfile = _path.join(FLAGS.write_path, self.config,
+ _path.basename(self.skp) + '.png')
+ commandline.extend(['--png', pngfile])
+ if (FLAGS.verbosity >= 4):
+ quoted = ['\'%s\'' % re.sub(r'([\\\'])', r'\\\1', x) for x in commandline]
+ print(' '.join(quoted), file=sys.stderr)
+ self._proc = subprocess.Popen(commandline, stdout=subprocess.PIPE)
+ self._monitor = SubprocessMonitor(self._queue, self._proc)
+ self._monitor.start()
- def execute(self):
- self.start()
while True:
message = self._queue.get()
if message.message == Message.READLINE:
result = BenchResult.match(message.value)
if result:
- self.__process_result(result)
+ hardware.sanity_check()
+ self._process_result(result)
else:
print(message.value)
sys.stdout.flush()
continue
+ if message.message == Message.POLL_HARDWARE:
+ hardware.sanity_check()
+ self._schedule_hardware_poll()
+ continue
if message.message == Message.EXIT:
- self.join()
+ self._monitor.join()
+ self._proc.wait()
+ if self._proc.returncode != 0:
+ raise Exception("skpbench exited with nonzero exit code %i" %
+ self._proc.returncode)
+ self._proc = None
break
- def __process_result(self, result):
+ def _schedule_hardware_poll(self):
+ if self._hw_poll_timer:
+ self._hw_poll_timer.cancel()
+ self._hw_poll_timer = \
+ Timer(1, lambda: self._queue.put(Message(Message.POLL_HARDWARE)))
+ self._hw_poll_timer.start()
+
+ def _process_result(self, result):
if not self.best_result or result.stddev <= self.best_result.stddev:
self.best_result = result
- elif FLAGS.verbosity >= 1:
- print('NOTE: reusing previous result for %s/%s with lower stddev '
- '(%s%% instead of %s%%).' %
+ elif FLAGS.verbosity >= 2:
+ print("reusing previous result for %s/%s with lower stddev "
+ "(%s%% instead of %s%%)." %
(result.config, result.bench, self.best_result.stddev,
result.stddev), file=sys.stderr)
if self.max_stddev and self.best_result.stddev > self.max_stddev:
raise StddevException()
- self.best_result.print_values(config_suffix=FLAGS.suffix)
- def run(self):
- """Called on the background thread.
-
- Launches and reads output from an skpbench process.
-
- """
- commandline = self.ARGV + ['--config', self.config,
- '--skp', self.skp,
- '--suppressHeader', 'true']
- if (FLAGS.write_path):
- pngfile = _path.join(FLAGS.write_path, self.config,
- _path.basename(self.skp) + '.png')
- commandline.extend(['--png', pngfile])
- if (FLAGS.verbosity >= 3):
- print(' '.join(commandline), file=sys.stderr)
- proc = subprocess.Popen(commandline, stdout=subprocess.PIPE)
- for line in iter(proc.stdout.readline, b''):
- self._queue.put(Message(Message.READLINE, line.decode('utf-8').rstrip()))
- proc.wait()
- self._queue.put(Message(Message.EXIT, proc.returncode))
+ def terminate(self):
+ if self._proc:
+ self._proc.kill()
+ self._monitor.join()
+ self._proc.wait()
+ self._proc = None
-def main():
+def run_benchmarks(configs, skps, hardware):
SKPBench.print_header()
- # Delimiter is "," or " ", skip if nested inside parens (e.g. gpu(a=b,c=d)).
- DELIMITER = r'[, ](?!(?:[^(]*\([^)]*\))*[^()]*\))'
- configs = re.split(DELIMITER, FLAGS.config)
- skps = _path.find_skps(FLAGS.skps)
-
benches = collections.deque([(skp, config, FLAGS.max_stddev)
for skp in skps
for config in configs])
while benches:
benchargs = benches.popleft()
- skpbench = SKPBench(*benchargs)
- try:
- skpbench.execute()
-
- except StddevException:
- retry_max_stddev = skpbench.max_stddev * math.sqrt(2)
- if FLAGS.verbosity >= 1:
- print('NOTE: stddev too high for %s/%s (%s%%; max=%.2f%%). '
- 'Re-queuing with max=%.2f%%.' %
- (skpbench.best_result.config, skpbench.best_result.bench,
- skpbench.best_result.stddev, skpbench.max_stddev,
- retry_max_stddev),
- file=sys.stderr)
- benches.append((skpbench.skp, skpbench.config, retry_max_stddev,
- skpbench.best_result))
+ with SKPBench(*benchargs) as skpbench:
+ try:
+ skpbench.execute(hardware)
+ if skpbench.best_result:
+ skpbench.best_result.print_values(config_suffix=FLAGS.suffix)
+ else:
+ print("WARNING: no result for %s with config %s" %
+ (skpbench.skp, skpbench.config), file=sys.stderr)
+
+ except StddevException:
+ retry_max_stddev = skpbench.max_stddev * math.sqrt(2)
+ if FLAGS.verbosity >= 2:
+ print("stddev is too high for %s/%s (%s%%, max=%.2f%%), "
+ "re-queuing with max=%.2f%%." %
+ (skpbench.best_result.config, skpbench.best_result.bench,
+ skpbench.best_result.stddev, skpbench.max_stddev,
+ retry_max_stddev),
+ file=sys.stderr)
+ benches.append((skpbench.skp, skpbench.config, retry_max_stddev,
+ skpbench.best_result))
+
+ except HardwareException as exception:
+ skpbench.terminate()
+ naptime = max(hardware.kick_in_time, exception.sleeptime)
+ if FLAGS.verbosity >= 1:
+ print("%s; taking a %i second nap..." %
+ (exception.message, naptime), file=sys.stderr)
+ benches.appendleft(benchargs) # retry the same bench next time.
+ hardware.sleep(naptime - hardware.kick_in_time)
+ time.sleep(hardware.kick_in_time)
+
+
+def main():
+ # Delimiter is ',' or ' ', skip if nested inside parens (e.g. gpu(a=b,c=d)).
+ DELIMITER = r'[, ](?!(?:[^(]*\([^)]*\))*[^()]*\))'
+ configs = re.split(DELIMITER, FLAGS.config)
+ skps = _path.find_skps(FLAGS.skps)
+
+ if FLAGS.adb:
+ adb = Adb(FLAGS.device_serial)
+ model = adb.get_device_model()
+ if False:
+ pass # TODO: unique subclasses tailored to individual platforms.
+ else:
+ from _hardware_android import HardwareAndroid
+ print("WARNING: %s: don't know how to monitor this hardware; results "
+ "may be unreliable." % model, file=sys.stderr)
+ hardware = HardwareAndroid(adb)
+ else:
+ hardware = Hardware()
+
+ with hardware:
+ if hardware.kick_in_time:
+ print("sleeping %i seconds to allow hardware settings to kick in..." %
+ hardware.kick_in_time, file=sys.stderr)
+ time.sleep(hardware.kick_in_time)
+ run_benchmarks(configs, skps, hardware)
if __name__ == '__main__':
« no previous file with comments | « tools/skpbench/skpbench.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698