diff options
author | Daniel Friesel <derf@finalrewind.org> | 2019-03-12 16:44:19 +0100 |
---|---|---|
committer | Daniel Friesel <derf@finalrewind.org> | 2019-03-12 16:44:19 +0100 |
commit | 2d0844c9f4c770c02afea654b902b467b044b970 (patch) | |
tree | 05404cfb9f672e7186612b17f3c713e378d22a69 | |
parent | bc3f8634c5bd821482bd80b904d001e43c191728 (diff) |
generate-dfa-benchmark: Support building, flashing, and (partially) logging
-rwxr-xr-x | bin/generate-dfa-benchmark.py | 29 | ||||
-rw-r--r-- | lib/runner.py | 40 |
2 files changed, 63 insertions, 6 deletions
diff --git a/bin/generate-dfa-benchmark.py b/bin/generate-dfa-benchmark.py index 101ea2a..d4e7996 100755 --- a/bin/generate-dfa-benchmark.py +++ b/bin/generate-dfa-benchmark.py @@ -25,7 +25,9 @@ Options: import getopt import json import re +import runner import sys +import time import io import yaml from automata import PTA @@ -37,8 +39,11 @@ if __name__ == '__main__': try: optspec = ( + 'arch= ' + 'app= ' 'depth= ' 'instance= ' + 'run= ' 'sleep= ' ) raw_opts, args = getopt.getopt(sys.argv[1:], "", optspec.split(' ')) @@ -88,9 +93,11 @@ if __name__ == '__main__': elif 'intance' in pta.codegen: class_prefix = '{}.'.format(pta.codegen['instance']) + num_transitions = 0 for run in pta.dfs(opt['depth'], with_arguments = True): outbuf.write(harness.start_run()) for transition, arguments in run: + num_transitions += 1 outbuf.write('// {} -> {}\n'.format(transition.origin.name, transition.destination.name)) if transition.is_interrupt: outbuf.write('// wait for {} interrupt\n'.format(transition.name)) @@ -123,4 +130,26 @@ if __name__ == '__main__': f.write(outbuf.getvalue()) else: print(outbuf.getvalue()) + + if 'run' in opt: + if 'sleep' in opt: + run_timeout = num_transitions * opt['sleep'] / 1000 + else: + run_timeout = num_transitions * 10 / 1000 + monitor = runner.get_monitor(opt['arch'], peek = True) + runner.build(opt['arch'], opt['app'], opt['run'].split()) + runner.flash(opt['arch'], opt['app'], opt['run'].split()) + try: + slept = 0 + while True: + time.sleep(5) + slept += 5 + if slept < run_timeout: + print('[MON] approx. {:.0f}% done'.format(slept * 100 / run_timeout)) + except KeyboardInterrupt: + pass + lines = monitor.get_lines() + monitor.close() + print(lines) + sys.exit(0) diff --git a/lib/runner.py b/lib/runner.py index cb3486b..e0d51f4 100644 --- a/lib/runner.py +++ b/lib/runner.py @@ -23,8 +23,9 @@ class SerialReader(serial.threaded.Protocol): Reads in new data whenever it becomes available and exposes a line-based interface to applications. """ - def __init__(self): + def __init__(self, peek = False): """Create a new SerialReader object.""" + self.peek = peek self.recv_buf = '' self.lines = [] @@ -41,6 +42,8 @@ class SerialReader(serial.threaded.Protocol): if len(lines) > 1: self.lines.extend(lines[:-1]) self.recv_buf = lines[-1] + if self.peek: + print('\n'.join(lines[:-1])) except UnicodeDecodeError: pass @@ -73,13 +76,14 @@ class SerialReader(serial.threaded.Protocol): class SerialMonitor: """SerialMonitor captures serial output for a specific amount of time.""" - def __init__(self, port: str, baud: int): + def __init__(self, port: str, baud: int, peek = False): """ Create a new SerialMonitor connected to port at the specified baud rate. Communication uses no parity, no flow control, and one stop bit. Data collection starts immediately. """ + self.peek = peek self.ser = serial.serial_for_url(port, do_not_open=True) self.ser.baudrate = baud self.ser.parity = 'N' @@ -92,7 +96,7 @@ class SerialMonitor: sys.stderr.write('Could not open serial port {}: {}\n'.format(self.ser.name, e)) sys.exit(1) - self.reader = SerialReader() + self.reader = SerialReader(peek = peek) self.worker = serial.threaded.ReaderThread(self.ser, self.reader) self.worker.start() @@ -105,6 +109,9 @@ class SerialMonitor: time.sleep(timeout) return self.reader.get_lines() + def get_lines(self) ->list: + return self.reader.get_lines() + def close(self): """Close serial connection.""" self.worker.stop() @@ -131,6 +138,9 @@ class ShellMonitor: universal_newlines = True) return res.stdout.split('\n') + def monitor(self): + raise NotImplementedError + def close(self): """ Do nothing, successfully. @@ -139,6 +149,24 @@ class ShellMonitor: """ pass +def build(arch, app, opts = []): + command = ['make', '-B', 'arch={}'.format(arch), 'app={}'.format(app)] + command.extend(opts) + res = subprocess.run(command, stdout = subprocess.PIPE, stderr = subprocess.PIPE, + universal_newlines = True) + if res.returncode != 0: + raise RuntimeError('Build failure: ' + res.stderr) + return command + +def flash(arch, app, opts = []): + command = ['make', 'arch={}'.format(arch), 'app={}'.format(app), 'program'] + command.extend(opts) + res = subprocess.run(command, stdout = subprocess.PIPE, stderr = subprocess.PIPE, + universal_newlines = True) + if res.returncode != 0: + raise RuntimeError('Flash failure') + return command + def get_info(arch, opts: list = []) -> list: """ Return multipass "make info" output. @@ -153,15 +181,15 @@ def get_info(arch, opts: list = []) -> list: raise RuntimeError('make info Failure') return res.stdout.split('\n') -def get_monitor(arch: str) -> object: +def get_monitor(arch: str, **kwargs) -> object: """Return a SerialMonitor or ShellMonitor.""" for line in get_info(arch): if 'Monitor:' in line: _, port, arg = line.split(' ') if port == 'run': - return ShellMonitor(arg) + return ShellMonitor(arg, **kwargs) else: - return SerialMonitor(port, arg) + return SerialMonitor(port, arg, **kwargs) raise RuntimeError('Monitor failure') def get_counter_limits(arch: str) -> tuple: |