summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/analyze-archive.py4
-rwxr-xr-xbin/generate-dfa-benchmark.py33
-rw-r--r--lib/loader.py2
-rw-r--r--lib/runner.py259
4 files changed, 163 insertions, 135 deletions
diff --git a/bin/analyze-archive.py b/bin/analyze-archive.py
index 8311f5c..aa266ed 100755
--- a/bin/analyze-archive.py
+++ b/bin/analyze-archive.py
@@ -150,8 +150,8 @@ def model_quality_table(result_lists, info_list):
"key",
"attribute",
"static".center(19),
- "LUT".center(19),
"parameterized".center(19),
+ "LUT".center(19),
)
)
for state_or_tran in result_lists[0]["by_name"].keys():
@@ -434,7 +434,7 @@ if __name__ == "__main__":
)
sys.exit(2)
- if len(traces) > 20:
+ if len(traces) > 40:
print(f"""Truncating plot to 40 of {len(traces)} traces (random sample)""")
traces = random.sample(traces, 40)
diff --git a/bin/generate-dfa-benchmark.py b/bin/generate-dfa-benchmark.py
index 2c53d9f..e6c3001 100755
--- a/bin/generate-dfa-benchmark.py
+++ b/bin/generate-dfa-benchmark.py
@@ -224,7 +224,7 @@ def benchmark_from_runs(
elif opt["sleep"]:
if "energytrace" in opt:
outbuf.write(f"// -> {transition.destination.name}\n")
- outbuf.write(runner.sleep_ms(opt["sleep"], opt["arch"]))
+ 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"]))
@@ -283,7 +283,7 @@ def run_benchmark(
needs_split = True
else:
try:
- runner.build(arch, app, run_args)
+ target.build(app, run_args)
except RuntimeError:
if len(runs) > 50:
# Application is too large -> split up runs
@@ -336,14 +336,14 @@ def run_benchmark(
i = 0
while i < opt["repeat"]:
print(f"""[RUN] flashing benchmark {i+1}/{opt["repeat"]}""")
- runner.flash(arch, app, run_args)
+ target.flash(app, run_args)
if "mimosa" in opt:
- monitor = runner.get_monitor(
- arch, callback=harness.parser_cb, mimosa=opt["mimosa"]
+ monitor = target.get_monitor(
+ callback=harness.parser_cb, mimosa=opt["mimosa"]
)
elif "energytrace" in opt:
- monitor = runner.get_monitor(
- arch, callback=harness.parser_cb, energytrace=opt["energytrace"]
+ monitor = target.get_monitor(
+ callback=harness.parser_cb, energytrace=opt["energytrace"]
)
sync_error = False
@@ -394,8 +394,8 @@ def run_benchmark(
return [(runs, harness, monitor, files)]
else:
- runner.flash(arch, app, run_args)
- monitor = runner.get_monitor(arch, callback=harness.parser_cb)
+ target.flash(app, run_args)
+ monitor = target.get_monitor(callback=harness.parser_cb)
if arch == "posix":
print("[RUN] Will run benchmark for {:.0f} seconds".format(run_timeout))
@@ -512,6 +512,11 @@ if __name__ == "__main__":
print(err)
sys.exit(2)
+ if "msp430fr" in opt["arch"]:
+ target = runner.Arch(opt["arch"], ["cpu_freq=8000000"])
+ else:
+ target = runner.Arch(opt["arch"])
+
modelfile = args[0]
pta = PTA.from_file(modelfile)
@@ -588,11 +593,7 @@ if __name__ == "__main__":
if "codegen" in driver_definition and "flags" in driver_definition["codegen"]:
if run_flags is None:
run_flags = driver_definition["codegen"]["flags"]
- if run_flags is None:
- run_flags = opt["run"].split()
-
- if "msp430fr" in opt["arch"]:
- run_flags.append("cpu_freq=8000000")
+ run_flags.extend(opt["run"].split())
runs = list(
pta.dfs(
@@ -639,7 +640,7 @@ if __name__ == "__main__":
gpio_pin=timer_pin,
gpio_mode=gpio_mode,
pta=pta,
- counter_limits=runner.get_counter_limits_us(opt["arch"]),
+ counter_limits=target.get_counter_limits_us(run_flags),
log_return_values=need_return_values,
repeat=1,
)
@@ -647,7 +648,7 @@ if __name__ == "__main__":
harness = OnboardTimerHarness(
gpio_pin=timer_pin,
pta=pta,
- counter_limits=runner.get_counter_limits_us(opt["arch"]),
+ counter_limits=target.get_counter_limits_us(run_flags),
log_return_values=need_return_values,
repeat=opt["repeat"],
)
diff --git a/lib/loader.py b/lib/loader.py
index 4e07c92..57b3d30 100644
--- a/lib/loader.py
+++ b/lib/loader.py
@@ -481,7 +481,7 @@ class RawData:
if sorted(online_trace_part["parameter"].keys()) != self._parameter_names:
processed_data[
"error"
- ] = "Offline #{off_idx:d} (online {on_name:s} @ {on_idx:d}/{on_sub:d}) has inconsistent parameter set: should be {param_want:s}, is {param_is:s}".format(
+ ] = "Offline #{off_idx:d} (online {on_name:s} @ {on_idx:d}/{on_sub:d}) has inconsistent parameter set: should be {param_want}, is {param_is}".format(
off_idx=offline_idx,
on_idx=online_run_idx,
on_sub=online_trace_part_idx,
diff --git a/lib/runner.py b/lib/runner.py
index 77b7c68..71ca799 100644
--- a/lib/runner.py
+++ b/lib/runner.py
@@ -311,130 +311,157 @@ class ShellMonitor:
pass
-def build(arch, app, opts=[]):
- command = ["make", "arch={}".format(arch), "app={}".format(app), "clean"]
- command.extend(opts)
- 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
+class Arch:
+ def __init__(self, name, opts=list()):
+ self.name = name
+ self.opts = opts
+ self.info = self.get_info()
+
+ def build(self, app, opts=list()):
+ command = ["make", "arch={}".format(self.name), "app={}".format(app), "clean"]
+ command.extend(self.opts)
+ command.extend(opts)
+ res = subprocess.run(
+ command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
)
- 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, executing {}:\n ".format(command) + res.stderr
+ if res.returncode != 0:
+ raise RuntimeError(
+ "Build failure, executing {}:\n".format(command) + res.stderr
+ )
+ command = ["make", "-B", "arch={}".format(self.name), "app={}".format(app)]
+ command.extend(self.opts)
+ command.extend(opts)
+ res = subprocess.run(
+ command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
)
- 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
+ if res.returncode != 0:
+ raise RuntimeError(
+ "Build failure, executing {}:\n ".format(command) + res.stderr
+ )
+ return command
+ def flash(self, app, opts=list()):
+ command = ["make", "arch={}".format(self.name), "app={}".format(app), "program"]
+ command.extend(self.opts)
+ 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.
+ def get_info(self, opts=list()) -> list:
+ """
+ Return multipass "make info" output.
- Returns a list.
- """
- command = ["make", "arch={}".format(arch), "info"]
- command.extend(opts)
- res = subprocess.run(
- command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
- )
- if res.returncode != 0:
- raise RuntimeError("make info Failure")
- return res.stdout.split("\n")
+ Returns a list.
+ """
+ command = ["make", "arch={}".format(self.name), "info"]
+ command.extend(self.opts)
+ command.extend(opts)
+ res = subprocess.run(
+ command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
+ )
+ if res.returncode != 0:
+ raise RuntimeError("make info Failure")
+ return res.stdout.split("\n")
+ def _cached_info(self, opts=list()) -> list:
+ if len(opts):
+ return self.get_info(opts)
+ return self.info
-def get_monitor(arch: str, **kwargs) -> object:
- """
- Return an appropriate monitor for arch, depending on "make info" output.
+ 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".
+ Port and Baud rate are taken from "make info".
- :param arch: architecture name, e.g. 'msp430fr5994lp' or 'posix'
- :param energytrace: `EnergyTraceMonitor` options. Returns an EnergyTrace monitor if not None.
- :param mimosa: `MIMOSAMonitor` options. Returns a MIMOSA monitor if not None.
- """
- for line in get_info(arch):
- if "Monitor:" in line:
- _, port, arg = line.split(" ")
- if port == "run":
- return ShellMonitor(arg, **kwargs)
- elif "mimosa" in kwargs and kwargs["mimosa"] is not None:
- mimosa_kwargs = kwargs.pop("mimosa")
- return MIMOSAMonitor(port, arg, **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(
- port, arg, **energytrace_kwargs, **kwargs
- )
+ :param energytrace: `EnergyTraceMonitor` options. Returns an EnergyTrace monitor if not None.
+ :param mimosa: `MIMOSAMonitor` options. Returns a MIMOSA monitor if not None.
+ """
+ for line in self.info:
+ if "Monitor:" in line:
+ _, port, arg = line.split(" ")
+ if port == "run":
+ return ShellMonitor(arg, **kwargs)
+ elif "mimosa" in kwargs and kwargs["mimosa"] is not None:
+ mimosa_kwargs = kwargs.pop("mimosa")
+ return MIMOSAMonitor(port, arg, **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(
+ port, arg, **energytrace_kwargs, **kwargs
+ )
+ else:
+ return EnergyTraceMonitor(
+ port, arg, **energytrace_kwargs, **kwargs
+ )
else:
- return EnergyTraceMonitor(port, arg, **energytrace_kwargs, **kwargs)
+ kwargs.pop("energytrace", None)
+ kwargs.pop("mimosa", None)
+ return SerialMonitor(port, arg, **kwargs)
+ raise RuntimeError("Monitor failure")
+
+ def get_counter_limits(self, opts=list()) -> tuple:
+ """Return multipass max counter and max overflow value for arch."""
+ for line in self._cached_info(opts):
+ match = re.match("Counter Overflow: ([^/]*)/(.*)", line)
+ if match:
+ overflow_value = int(match.group(1))
+ max_overflow = int(match.group(2))
+ return overflow_value, max_overflow
+ raise RuntimeError("Did not find Counter Overflow limits")
+
+ def sleep_ms(self, duration: int, opts=list()) -> str:
+ max_sleep = None
+ if "msp430fr" in self.name:
+ cpu_freq = None
+ for line in self._cached_info(opts):
+ match = re.match(r"CPU\s+Freq:\s+(.*)\s+Hz", line)
+ if match:
+ cpu_freq = int(match.group(1))
+ if cpu_freq is not None and cpu_freq > 8000000:
+ max_sleep = 250
else:
- kwargs.pop("energytrace", None)
- kwargs.pop("mimosa", None)
- return SerialMonitor(port, arg, **kwargs)
- raise RuntimeError("Monitor failure")
-
-
-def get_counter_limits(arch: str) -> tuple:
- """Return multipass max counter and max overflow value for arch."""
- for line in get_info(arch):
- match = re.match("Counter Overflow: ([^/]*)/(.*)", line)
- if match:
- overflow_value = int(match.group(1))
- max_overflow = int(match.group(2))
- return overflow_value, max_overflow
- raise RuntimeError("Did not find Counter Overflow limits")
-
-
-def sleep_ms(duration: int, arch: str, cpu_freq: int = None) -> str:
- max_sleep = None
- if "msp430fr" in arch:
- if cpu_freq is not None and cpu_freq > 8000000:
- max_sleep = 250
- else:
- max_sleep = 500
- 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++) {{ arch.sleep_ms({max_sleep}); }}\n"
- if tail_sleep > 0:
- ret += f"arch.sleep_ms({tail_sleep});\n"
- return ret
- return "arch.sleep_ms({duration});\n"
-
-
-def get_counter_limits_us(arch: str) -> tuple:
- """Return duration of one counter step and one counter overflow in us."""
- cpu_freq = 0
- overflow_value = 0
- max_overflow = 0
- for line in get_info(arch):
- match = re.match(r"CPU\s+Freq:\s+(.*)\s+Hz", line)
- if match:
- cpu_freq = int(match.group(1))
- match = re.match(r"Counter Overflow:\s+([^/]*)/(.*)", line)
- if match:
- overflow_value = int(match.group(1))
- max_overflow = int(match.group(2))
- if cpu_freq and overflow_value:
- return 1000000 / cpu_freq, overflow_value * 1000000 / cpu_freq, max_overflow
- raise RuntimeError("Did not find Counter Overflow limits")
+ max_sleep = 500
+ 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++) {{ arch.sleep_ms({max_sleep}); }}\n"
+ if tail_sleep > 0:
+ ret += f"arch.sleep_ms({tail_sleep});\n"
+ return ret
+ return f"arch.sleep_ms({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 = 0
+ overflow_value = 0
+ max_overflow = 0
+ for line in self._cached_info(opts):
+ match = re.match(r"CPU\s+Freq:\s+(.*)\s+Hz", line)
+ if match:
+ cpu_freq = int(match.group(1))
+ match = re.match(r"Counter Overflow:\s+([^/]*)/(.*)", line)
+ if match:
+ overflow_value = int(match.group(1))
+ max_overflow = int(match.group(2))
+ if cpu_freq and overflow_value:
+ return 1000000 / cpu_freq, overflow_value * 1000000 / cpu_freq, max_overflow
+ raise RuntimeError("Did not find Counter Overflow limits")