diff options
-rwxr-xr-x | bin/generate-dfa-benchmark.py | 47 | ||||
-rw-r--r-- | lib/harness.py | 44 | ||||
-rw-r--r-- | lib/runner.py | 20 |
3 files changed, 75 insertions, 36 deletions
diff --git a/bin/generate-dfa-benchmark.py b/bin/generate-dfa-benchmark.py index 3019a2e..95fbbb3 100755 --- a/bin/generate-dfa-benchmark.py +++ b/bin/generate-dfa-benchmark.py @@ -45,6 +45,7 @@ if __name__ == '__main__': 'instance= ' 'run= ' 'sleep= ' + 'timer-pin= ' ) raw_opts, args = getopt.getopt(sys.argv[1:], "", optspec.split(' ')) @@ -72,7 +73,12 @@ if __name__ == '__main__': else: pta = PTA.from_yaml(yaml.safe_load(f)) - harness = OnboardTimerHarness('GPIO::p1_0') + if 'timer-pin' in opt: + timer_pin = opt['timer-pin'] + else: + timer_pin = 'GPIO::p1_0' + + harness = OnboardTimerHarness(timer_pin) outbuf = io.StringIO() @@ -90,21 +96,27 @@ if __name__ == '__main__': class_prefix = '' if 'instance' in opt: class_prefix = '{}.'.format(opt['instance']) - elif 'intance' in pta.codegen: + elif 'instance' in pta.codegen: class_prefix = '{}.'.format(pta.codegen['instance']) num_transitions = 0 for run in pta.dfs(opt['depth'], with_arguments = True, with_parameters = True): outbuf.write(harness.start_run()) + harness.start_trace() + param = pta.get_initial_param_dict() for transition, arguments, parameter in run: num_transitions += 1 + harness.append_state(transition.origin.name, param) + harness.append_transition(transition.name, param) outbuf.write('// {} -> {}\n'.format(transition.origin.name, transition.destination.name)) if transition.is_interrupt: outbuf.write('// wait for {} interrupt\n'.format(transition.name)) transition_code = '// TODO add startTransition / stopTransition calls to interrupt routine' else: transition_code = '{}{}({});'.format(class_prefix, transition.name, ', '.join(map(str, arguments))) - outbuf.write(harness.pass_transition(pta.get_transition_id(transition), transition_code, parameter)) + outbuf.write(harness.pass_transition(pta.get_transition_id(transition), transition_code, transition = transition, parameter = parameter)) + + param = parameter if 'sleep' in opt: outbuf.write('arch.delay_ms({:d});\n'.format(opt['sleep'])) @@ -113,6 +125,7 @@ if __name__ == '__main__': outbuf.write('\n') outbuf.write(harness.stop_benchmark()) + print(harness.traces) outbuf.write('}\n') outbuf.write('int main(void)\n') outbuf.write('{\n') @@ -136,20 +149,24 @@ if __name__ == '__main__': run_timeout = num_transitions * opt['sleep'] / 1000 else: run_timeout = num_transitions * 10 / 1000 - monitor = runner.get_monitor(opt['arch'], peek = True) + monitor = runner.get_monitor(opt['arch'], callback = harness.parser_cb) 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() + if opt['arch'] != 'posix': + 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() + else: + print('[MON] Will run benchmark for {:.0f} seconds'.format(2 * run_timeout)) + lines = monitor.run(int(2 * run_timeout)) print(lines) sys.exit(0) diff --git a/lib/harness.py b/lib/harness.py index 2705193..ade42d6 100644 --- a/lib/harness.py +++ b/lib/harness.py @@ -3,6 +3,7 @@ Harnesses for various types of benchmark logs. tbd """ +import re # TODO prepare benchmark log JSON with parameters etc. # Should be independent of PTA class, as benchmarks may also be @@ -32,24 +33,28 @@ class TransitionHarness: def start_trace(self): self.traces.append({ 'id' : self.trace_id, - 'trace' : [{ - 'name' : 'UNINITIALIZED', - 'isa' : 'state', - 'parameter' : dict(), - 'offline_aggregates' : list(), - }] + 'trace' : list(), }) self.trace_id += 1 - #def append_state(self): + def append_state(self, state_name, param): + self.traces[-1]['trace'].append({ + 'name': state_name, + 'isa': 'state', + 'parameter': param, + }) - #def append_transition(self, ): + def append_transition(self, transition_name, param): + self.traces[-1]['trace'].append({ + 'name': transition_name, + 'isa': 'transition', + 'parameter': param, + }) def start_run(self): - self.start_trace() return 'ptalog.reset();\n' - def pass_transition(self, transition_id, transition_code, parameter = dict()): + def pass_transition(self, transition_id, transition_code, transition: object = None, parameter: dict = dict()): ret = 'ptalog.passTransition({:d});\n'.format(transition_id) ret += 'ptalog.startTransition();\n' ret += '{}\n'.format(transition_code) @@ -62,6 +67,23 @@ class TransitionHarness: def stop_benchmark(self): return '' + def parse_log(self, lines): + sync = False + for line in lines: + print(line) + res = re.fullmatch('\[PTA\] (.*=.*)', line) + if re.fullmatch('\[PTA\] benchmark start, id=(.*)', line): + print('> got sync') + sync = True + elif not sync: + continue + elif re.fullmatch('\[PTA\] trace, count=(.*)', line): + print('> got transition') + pass + elif res: + print(dict(map(lambda x: x.split('='), res.group(1).split()))) + pass + class OnboardTimerHarness(TransitionHarness): def __init__(self, gpio_pin = None): super().__init__(gpio_pin = gpio_pin) @@ -79,7 +101,7 @@ class OnboardTimerHarness(TransitionHarness): ret += super().start_benchmark() return ret - def pass_transition(self, transition_id, transition_code, parameter = dict()): + def pass_transition(self, transition_id, transition_code, transition: object = None, parameter: dict = dict()): ret = 'ptalog.passTransition({:d});\n'.format(transition_id) ret += 'ptalog.startTransition();\n' ret += 'counter.start();\n' diff --git a/lib/runner.py b/lib/runner.py index 9b95e6b..c9179c2 100644 --- a/lib/runner.py +++ b/lib/runner.py @@ -24,9 +24,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, peek = False): + def __init__(self, callback = None): """Create a new SerialReader object.""" - self.peek = peek + self.callback = callback self.recv_buf = '' self.lines = [] @@ -48,8 +48,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])) + if self.callback: + self.callback(lines[:-1]) except UnicodeDecodeError: pass @@ -82,7 +82,7 @@ class SerialReader(serial.threaded.Protocol): class SerialMonitor: """SerialMonitor captures serial output for a specific amount of time.""" - def __init__(self, port: str, baud: int, peek = False): + def __init__(self, port: str, baud: int, callback = None): """ Create a new SerialMonitor connected to port at the specified baud rate. @@ -101,7 +101,7 @@ class SerialMonitor: sys.stderr.write('Could not open serial port {}: {}\n'.format(self.ser.name, e)) sys.exit(1) - self.reader = SerialReader(peek = peek) + self.reader = SerialReader(callback = callback) self.worker = serial.threaded.ReaderThread(self.ser, self.reader) self.worker.start() @@ -124,14 +124,14 @@ class SerialMonitor: class ShellMonitor: """SerialMonitor runs a program and captures its output for a specific amount of time.""" - def __init__(self, script: str, peek = None): + def __init__(self, script: str, callback = None): """ Create a new ShellMonitor object. Does not start execution and monitoring yet. """ self.script = script - self.peek = peek + self.callback = callback def run(self, timeout: int = 4) -> list: """ @@ -144,8 +144,8 @@ class ShellMonitor: res = subprocess.run(['timeout', '{:d}s'.format(timeout), self.script], stdout = subprocess.PIPE, stderr = subprocess.PIPE, universal_newlines = True) - if self.peek: - print(res.stdout) + if self.callback: + self.callback(res.stdout.split('\n')) return res.stdout.split('\n') def monitor(self): |