diff options
author | Daniel Friesel <daniel.friesel@uos.de> | 2021-04-15 16:10:23 +0200 |
---|---|---|
committer | Daniel Friesel <daniel.friesel@uos.de> | 2021-04-15 16:10:23 +0200 |
commit | ebbd23fc2e1ebfe764350063259a27cc8e1b009e (patch) | |
tree | 663ee964642014343571286ee26189628875845f | |
parent | 6bd652f1c2097ae228d20b14869e06cca439c07a (diff) |
Prepare KRATOS support
-rwxr-xr-x | bin/analyze-archive.py | 25 | ||||
-rwxr-xr-x | bin/generate-dfa-benchmark.py | 58 | ||||
-rw-r--r-- | lib/harness.py | 38 | ||||
-rw-r--r-- | lib/runner.py | 214 |
4 files changed, 267 insertions, 68 deletions
diff --git a/bin/analyze-archive.py b/bin/analyze-archive.py index 0c8306f..6f5fc37 100755 --- a/bin/analyze-archive.py +++ b/bin/analyze-archive.py @@ -325,7 +325,8 @@ def print_html_model_data(raw_data, model, pm, pq, lm, lq, am, ai, aq): print("</table>") -def print_kconfig(model): +def get_kconfig(model): + buf = str() for param_name in model.parameters: unique_values = set() is_relevant = False @@ -344,16 +345,18 @@ def print_kconfig(model): # unused by the model continue - print(f"config {param_name}") - print(f' prompt "{param_name}"') + buf += f"config {param_name}\n" + buf += f' prompt "{param_name}"\n' if unique_values == {0, 1}: - print(" bool") + buf += " bool\n" elif all(map(is_numeric, unique_values)): - print(" int") - print(f" range {min(unique_values)} {max(unique_values)}") + buf += " int\n" + buf += f" range {min(unique_values)} {max(unique_values)}\n" else: - print(" string") - print(f" #!accept [{unique_values}]") + buf += " string\n" + buf += f" #!accept [{unique_values}]\n" + + return buf def plot_traces(preprocessed_data, sot_name): @@ -1205,8 +1208,10 @@ if __name__ == "__main__": + match.group(3) ) json_model_out += line + "\n" - # print(json_model_out) - print_kconfig(model) + with open(f"{args.export_webconf}.json", "w") as f: + f.write(json_model_out) + with open(f"{args.export_webconf}.kconfig", "w") as f: + f.write(get_kconfig(model)) if args.export_energymodel: if not pta: diff --git a/bin/generate-dfa-benchmark.py b/bin/generate-dfa-benchmark.py index d2515e3..71e7924 100755 --- a/bin/generate-dfa-benchmark.py +++ b/bin/generate-dfa-benchmark.py @@ -48,6 +48,8 @@ Options: shunt = 330 (measurement shunt in ohms) voltage = 3.3 (VCC provided to DUT) +--os=kratos|multipass (default: multipass) + --sleep=<ms> (default: 0) How long to sleep between function calls. @@ -120,8 +122,8 @@ def benchmark_from_runs( ) -> io.StringIO: outbuf = io.StringIO() - outbuf.write('#include "arch.h"\n') - outbuf.write('#include "driver/gpio.h"\n') + outbuf.write(target.app_header()) + if dummy: outbuf.write('#include "driver/dummy.h"\n') elif "includes" in pta.codegen: @@ -129,11 +131,7 @@ def benchmark_from_runs( outbuf.write('#include "{}"\n'.format(include)) outbuf.write(harness.global_code()) - outbuf.write("int main(void)\n") - outbuf.write("{\n") - - for driver in ("arch", "gpio", "kout"): - outbuf.write("{}.setup();\n".format(driver)) + outbuf.write(target.app_function_start()) # There is a race condition between flashing the code and starting the UART log. # When starting the log before flashing, output from a previous benchmark may cause bogus data to be added. @@ -147,21 +145,22 @@ def benchmark_from_runs( # decreases pre-sync power consumption if "energytrace" not in opt: if "mimosa" in opt: - outbuf.write("arch.delay_ms(12000);\n") + outbuf.write(target.app_delay(12000)) else: - outbuf.write("arch.delay_ms(2000);\n") + outbuf.write(target.app_delay(2000)) # Output some newlines to ensure the parser can determine the start of the first real output line - outbuf.write("kout << endl << endl;\n") + outbuf.write(target.app_newlines()) if "setup" in pta.codegen: for call in pta.codegen["setup"]: outbuf.write(call) if "energytrace" in opt: - outbuf.write("for (unsigned char i = 0; i < 10; i++) {\n") - outbuf.write("arch.sleep_ms(250);\n}\n") + outbuf.write("for (unsigned char j = 0; j < 10; j++) {\n") + outbuf.write(target.app_sleep(250)) + outbuf.write("}\n") # Output some newlines to ensure the parser can determine the start of the first real output line - outbuf.write("kout << endl << endl;\n") + outbuf.write(target.app_newlines()) if repeat: outbuf.write("unsigned char i = 0;\n") @@ -218,16 +217,16 @@ def benchmark_from_runs( if "delay_after_ms" in transition.codegen: if "energytrace" in opt: outbuf.write( - "arch.sleep_ms({:d}); // {} -- delay mandated by codegen.delay_after_ms\n".format( + target.app_sleep( transition.codegen["delay_after_ms"], - transition.destination.name, + f"{transition.destination.name} -- delay mandated by codegen.delay_after_ms", ) ) else: outbuf.write( - "arch.delay_ms({:d}); // {} -- delay mandated by codegen.delay_after_ms\n".format( + target.app_delay( transition.codegen["delay_after_ms"], - transition.destination.name, + f"{transition.destination.name} -- delay mandated by codegen.delay_after_ms", ) ) elif opt["sleep"]: @@ -236,7 +235,7 @@ def benchmark_from_runs( outbuf.write(target.sleep_ms(opt["sleep"])) else: outbuf.write(f"// -> {transition.destination.name}\n") - outbuf.write("arch.delay_ms({:d});\n".format(opt["sleep"])) + outbuf.write(target.app_delay(opt["sleep"])) outbuf.write(harness.stop_run(num_traces)) if dummy: @@ -251,10 +250,7 @@ def benchmark_from_runs( # Ensure logging can be terminated after the specified number of measurements outbuf.write(harness.start_benchmark()) - - outbuf.write("while(1) { }\n") - outbuf.write("return 0;\n") - outbuf.write("}\n") + outbuf.write(target.app_function_end()) return outbuf @@ -449,6 +445,7 @@ if __name__ == "__main__": "instance= " "log-level= " "mimosa= " + "os= " "repeat= " "run= " "sleep= " @@ -537,21 +534,26 @@ if __name__ == "__main__": map(lambda x: x.split("="), opt["dummy"].split(",")) ) + if "os" not in opt: + opt["os"] = "multipass" + except getopt.GetoptError as err: print(err) sys.exit(2) - if "msp430fr" in opt["arch"]: + if opt["os"] == "kratos": + target = runner.KRATOS() + elif "msp430fr" in opt["arch"]: if len(opt["arch-flags"]) == 0: opt["arch-flags"] = ["cpu_freq=8000000", "uart_freq=9600"] - target = runner.Arch(opt["arch"], opt["arch-flags"]) + target = runner.Multipass(opt["arch"], opt["arch-flags"]) else: - target = runner.Arch(opt["arch"]) + target = runner.Multipass(opt["arch"]) modelfile = args[0] pta = PTA.from_file(modelfile) - run_flags = None + run_flags = list() if "shrink" in opt: pta.shrink_argument_values() @@ -622,7 +624,7 @@ if __name__ == "__main__": with open(modelfile, "r") as f: driver_definition = yaml.safe_load(f) if "codegen" in driver_definition and "flags" in driver_definition["codegen"]: - if run_flags is None: + if not run_flags: run_flags = driver_definition["codegen"]["flags"] if "run" in opt: run_flags.extend(opt["run"].split()) @@ -704,6 +706,8 @@ if __name__ == "__main__": remove_nop_from_timings=False, # kein einfluss auf ungenauigkeiten ) + harness.target = target + if len(args) > 1: results = run_benchmark( args[1], diff --git a/lib/harness.py b/lib/harness.py index f329434..21bcd9e 100644 --- a/lib/harness.py +++ b/lib/harness.py @@ -37,6 +37,7 @@ class TransitionHarness: repeat=0, post_transition_delay_us=0, energytrace_sync=None, + target=None, ): """ Create a new TransitionHarness @@ -58,6 +59,7 @@ class TransitionHarness: self.repeat = repeat self.post_transition_delay_us = post_transition_delay_us self.energytrace_sync = energytrace_sync + self.target = target self.reset() def copy(self): @@ -387,6 +389,7 @@ class OnboardTimerHarness(TransitionHarness): log_return_values=self.log_return_values, repeat=self.repeat, energytrace_sync=self.energytrace_sync, + target=self.target, ) new_harness.traces = self.traces.copy() new_harness.trace_id = self.trace_id @@ -426,41 +429,16 @@ class OnboardTimerHarness(TransitionHarness): ret = "#define PTALOG_TIMING\n" ret += super().global_code() if self.energytrace_sync == "led": - # TODO Make nicer - ret += """\nvoid runLASync(){ - // ======================= LED SYNC ================================ - #ifdef PTALOG_GPIO - gpio.write(PTALOG_GPIO, 1); - #endif - gpio.led_on(0); - gpio.led_on(1); - #ifdef PTALOG_GPIO - gpio.write(PTALOG_GPIO, 0); - #endif - - for (unsigned char i = 0; i < 4; i++) { - arch.sleep_ms(250); - } - - #ifdef PTALOG_GPIO - gpio.write(PTALOG_GPIO, 1); - #endif - gpio.led_off(0); - gpio.led_off(1); - #ifdef PTALOG_GPIO - gpio.write(PTALOG_GPIO, 0); - #endif - // ======================= LED SYNC ================================ -}\n\n""" + ret += self.target.app_lasync_function() return ret def start_benchmark(self, benchmark_id=0): ret = "" if self.energytrace_sync == "led": - ret += "runLASync();\n" + ret += self.target.app_lasync_call() ret += "ptalog.passNop();\n" if self.energytrace_sync == "led": - ret += "arch.sleep_ms(250);\n" + ret += self.target.app_sleep(250) ret += super().start_benchmark(benchmark_id) return ret @@ -468,10 +446,10 @@ class OnboardTimerHarness(TransitionHarness): ret = "" if self.energytrace_sync == "led": ret += "counter.stop();\n" - ret += "runLASync();\n" + ret += self.target.app_lasync_call() ret += super().stop_benchmark() if self.energytrace_sync == "led": - ret += "arch.sleep_ms(250);\n" + ret += self.target.app_sleep(250) return ret def pass_transition( diff --git a/lib/runner.py b/lib/runner.py index f718180..ea3ee0d 100644 --- a/lib/runner.py +++ b/lib/runner.py @@ -352,12 +352,224 @@ class ShellMonitor: pass -class Arch: +class KRATOS: + def __init__(self, opts=list()): + self.opts = opts + + def app_header(self): + ret = ( + '#include "AEMR.h"\n' + '#include "syscall/guarded_buzzer.h"\n' + '#include "drivers/counter.h"\n' + '#include "drivers/gpio.h"\n' + ) + return ret + + def app_function_start(self): + ret = ( + "ImplementThread(EnergyBenchmarkApp, energyBenchmarkApp, 512);\n" + "void EnergyBenchmarkApp::action()\n" + "{\n" + "Guarded_Buzzer buz(500);\n" + ) + + return ret + + def app_function_end(self): + return "}\n" + + def app_delay(self, ms, comment=""): + return self.app_sleep(ms, comment) + + def app_sleep(self, ms, comment=""): + if comment: + comment = f" // {comment}" + return f"buz.sleep({ms});{comment}\n" + + def app_newlines(self): + return "uart << endl << endl;\n" + + def app_lasync_call(self): + return "runLASync(buz);\n" + + def app_lasync_function(self): + ret = """void runLASync(Guarded_Buzzer &buz){ + setOutput(1, 0); + setOutput(1, 1); + pinHigh(1, 0); + pinHigh(1, 1); + + buz.sleep(1000); + + pinLow(1, 0); + pinLow(1, 1); +} +""" + return ret + + def build(self, app, opts=list()): + command = ["make", "clean"] + command.extend(self.opts) + command.extend(opts) + logger.debug(f"Building: {' '.join(command)}") + res = subprocess.run( + command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + ) + if res.returncode != 0: + raise RuntimeError( + "Build failure, executing {}:\n".format(command) + res.stderr + ) + command = ["make"] + command.extend(self.opts) + command.extend(opts) + logger.debug(f"Building: {' '.join(command)}") + res = subprocess.run( + command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + ) + if res.returncode != 0: + raise RuntimeError( + "Build failure, executing {}:\n ".format(command) + res.stderr + ) + return command + + def flash(self, app, opts=list()): + command = ["make", "flash"] + command.extend(self.opts) + command.extend(opts) + logger.debug(f"Flashing: {' '.join(command)}") + 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_monitor(self, **kwargs) -> object: + """ + Return an appropriate monitor for arch, depending on "make info" output. + + Port and Baud rate are taken from "make info". + + :param energytrace: `EnergyTraceMonitor` options. Returns an EnergyTrace monitor if not None. + :param mimosa: `MIMOSAMonitor` options. Returns a MIMOSA monitor if not None. + """ + if "mimosa" in kwargs and kwargs["mimosa"] is not None: + mimosa_kwargs = kwargs.pop("mimosa") + return MIMOSAMonitor("/dev/ttyACM1", "9600", **mimosa_kwargs, **kwargs) + elif "energytrace" in kwargs and kwargs["energytrace"] is not None: + energytrace_kwargs = kwargs.pop("energytrace").copy() + sync_mode = energytrace_kwargs.pop("sync") + if sync_mode == "la": + return EnergyTraceLogicAnalyzerMonitor( + "/dev/ttyACM1", "9600", **energytrace_kwargs, **kwargs + ) + else: + return EnergyTraceMonitor( + "/dev/ttyACM1", "9600", **energytrace_kwargs, **kwargs + ) + else: + kwargs.pop("energytrace", None) + kwargs.pop("mimosa", None) + return SerialMonitor("/dev/ttyACM1", "9600", **kwargs) + + def sleep_ms(self, duration: int, opts=list()) -> str: + max_sleep = 250 + if max_sleep is not None and duration > max_sleep: + sub_sleep_count = duration // max_sleep + tail_sleep = duration % max_sleep + ret = f"for (unsigned char i = 0; i < {sub_sleep_count}; i++) {{ buz.sleep({max_sleep}); }}\n" + if tail_sleep > 0: + ret += f"buz.sleep({tail_sleep});\n" + return ret + return f"buz.sleep({duration});\n" + + def get_counter_limits_us(self, opts=list()) -> tuple: + """Return duration of one counter step and one counter overflow in us.""" + cpu_freq = 16_000_000 + overflow_value = 65536 + max_overflow = 65535 + return ( + 1_000_000 / cpu_freq, + overflow_value * 1_000_000 / cpu_freq, + max_overflow, + ) + + +class Multipass: def __init__(self, name, opts=list()): self.name = name self.opts = opts self.info = self.get_info() + def app_header(self): + ret = '#include "arch.h"\n' '#include "driver/gpio.h"\n' + return ret + + def app_function_start(self): + ret = "int main(void)\n{\n" + + for driver in ("arch", "gpio", "kout"): + ret += f"{driver}.setup();\n" + + return ret + + def app_function_end(self): + return "while (1) { }\nreturn 0;\n}\n" + + def app_delay(self, ms, comment=""): + if comment: + comment = f" // {comment}" + return f"arch.delay_ms({ms});{comment}\n" + + def app_sleep(self, ms, comment=""): + if ms > 250: + # TODO build multiple sleep_ms calls + raise ValueError("msp430 does not support sleep longer than 250ms") + if comment: + comment = f" // {comment}" + return f"arch.sleep_ms({ms});{comment}\n" + + def app_newlines(self): + return "kout << endl << endl;\n" + + def app_lasync_call(self): + return "runLASync();\n" + + def app_lasync_function(self): + ret = """void runLASync(){ + #ifdef PTALOG_GPIO + gpio.write(PTALOG_GPIO, 1); + #endif + gpio.led_on(0); + gpio.led_on(1); + #ifdef PTALOG_GPIO + gpio.write(PTALOG_GPIO, 0); + #endif + + for (unsigned char i = 0; i < 4; i++) { + arch.sleep_ms(250); + } + + #ifdef PTALOG_GPIO + gpio.write(PTALOG_GPIO, 1); + #endif + gpio.led_off(0); + gpio.led_off(1); + #ifdef PTALOG_GPIO + gpio.write(PTALOG_GPIO, 0); + #endif +}\n\n""" + return ret + def build(self, app, opts=list()): command = ["make", "arch={}".format(self.name), "app={}".format(app), "clean"] command.extend(self.opts) |