summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Friesel <derf@finalrewind.org>2019-03-12 16:44:19 +0100
committerDaniel Friesel <derf@finalrewind.org>2019-03-12 16:44:19 +0100
commit2d0844c9f4c770c02afea654b902b467b044b970 (patch)
tree05404cfb9f672e7186612b17f3c713e378d22a69
parentbc3f8634c5bd821482bd80b904d001e43c191728 (diff)
generate-dfa-benchmark: Support building, flashing, and (partially) logging
-rwxr-xr-xbin/generate-dfa-benchmark.py29
-rw-r--r--lib/runner.py40
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: