summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/analyze-archive.py7
-rwxr-xr-xbin/analyze-kconfig.py3
-rw-r--r--lib/cli.py15
-rw-r--r--lib/functions.py23
-rw-r--r--lib/parameters.py63
5 files changed, 109 insertions, 2 deletions
diff --git a/bin/analyze-archive.py b/bin/analyze-archive.py
index 7fb5719..e9e5171 100755
--- a/bin/analyze-archive.py
+++ b/bin/analyze-archive.py
@@ -465,7 +465,7 @@ if __name__ == "__main__":
help="Load DFA hardware model from JSON or YAML FILE",
)
parser.add_argument(
- "--export-dot",
+ "--export-pta-dot",
metavar="FILE",
type=str,
help="Export PTA representation suitable for Graphviz dot to FILE",
@@ -1067,12 +1067,15 @@ if __name__ == "__main__":
json.dump(json_model, f, indent=2, sort_keys=True, cls=NpEncoder)
if args.export_dot:
+ dfatool.cli.export_dot(model, args.export_dot)
+
+ if args.export_pta_dot:
if not pta:
print(
"Note: v0 measurements do not embed the PTA used for benchmark generation. Estimating PTA from recorded observations."
)
json_model = model.to_json()
- with open(args.export_dot, "w") as f:
+ with open(args.export_pta_dot, "w") as f:
f.write(model.to_dot())
sys.exit(0)
diff --git a/bin/analyze-kconfig.py b/bin/analyze-kconfig.py
index db6cf40..565203b 100755
--- a/bin/analyze-kconfig.py
+++ b/bin/analyze-kconfig.py
@@ -319,6 +319,9 @@ def main():
else:
static_quality = model.assess(static_model)
+ if args.export_dot:
+ dfatool.cli.export_dot(model, args.export_dot)
+
if args.export_dref:
dref.update(
model.to_dref(
diff --git a/lib/cli.py b/lib/cli.py
index 3e7865b..0de5505 100644
--- a/lib/cli.py
+++ b/lib/cli.py
@@ -155,8 +155,23 @@ def export_dataref(dref_file, dref):
print(f"{prefix}/{k}" + "}{" + str(v[0]) + "}", file=f)
+def export_dot(model, dot_prefix):
+ for name in model.names:
+ for attribute in model.attributes(name):
+ dot_model = model.attr_by_name[name][attribute].to_dot()
+ if not dot_model is None:
+ with open(f"{dot_prefix}{name}-{attribute}.dot", "w") as f:
+ print(dot_model, file=f)
+
+
def add_standard_arguments(parser):
parser.add_argument(
+ "--export-dot",
+ metavar="PREFIX",
+ type=str,
+ help="Export model and model quality to LaTeX {PREFIX}{name}-{attribute}.dot",
+ )
+ parser.add_argument(
"--export-dref",
metavar="FILE",
type=str,
diff --git a/lib/functions.py b/lib/functions.py
index b934e79..8e25ad3 100644
--- a/lib/functions.py
+++ b/lib/functions.py
@@ -276,6 +276,9 @@ class StaticFunction(ModelFunction):
ret.update({"type": "static", "value": self.value})
return ret
+ def to_dot(self, pydot, graph, feature_names, parent=None):
+ graph.add_node(pydot.Node(str(id(self)), label=self.value, shape="rectangle"))
+
@classmethod
def from_json(cls, data):
assert data["type"] == "static"
@@ -352,6 +355,16 @@ class SplitFunction(ModelFunction):
ret.append(v.get_max_depth())
return 1 + max(ret)
+ def to_dot(self, pydot, graph, feature_names, parent=None):
+ try:
+ label = feature_names[self.param_index]
+ except IndexError:
+ label = f"param{self.param_index}"
+ graph.add_node(pydot.Node(str(id(self)), label=label))
+ for key, child in self.child.items():
+ child.to_dot(pydot, graph, feature_names, str(id(self)))
+ graph.add_edge(pydot.Edge(str(id(self)), str(id(child)), label=key))
+
@classmethod
def from_json(cls, data):
assert data["type"] == "split"
@@ -737,6 +750,16 @@ class AnalyticFunction(ModelFunction):
)
return ret
+ def to_dot(self, pydot, graph, feature_names, parent=None):
+ model_function = self.model_function
+ for i, arg in enumerate(self.model_args):
+ model_function = model_function.replace(
+ f"regression_arg({i})", f"{arg:.2f}"
+ )
+ graph.add_node(
+ pydot.Node(str(id(self)), label=model_function, shape="rectangle")
+ )
+
@classmethod
def from_json(cls, data):
assert data["type"] == "analytic"
diff --git a/lib/parameters.py b/lib/parameters.py
index 50a7ae8..45db489 100644
--- a/lib/parameters.py
+++ b/lib/parameters.py
@@ -645,6 +645,69 @@ class ModelAttribute:
return ret
+ def to_dot(self):
+ if type(self.model_function) == df.SplitFunction:
+ import pydot
+
+ graph = pydot.Dot("Regression Model Tree", graph_type="graph")
+ self.model_function.to_dot(pydot, graph, self.param_names)
+ return graph
+ if type(self.model_function) == df.CARTFunction:
+ import sklearn.tree
+
+ feature_names = list(
+ map(
+ lambda i: self.param_names[i],
+ filter(
+ lambda i: not self.model_function.ignore_index[i],
+ range(len(self.param_names)),
+ ),
+ )
+ )
+ feature_names += list(
+ map(
+ lambda i: f"arg{i-len(self.param_names)}",
+ filter(
+ lambda i: not self.model_function.ignore_index[i],
+ range(
+ len(self.param_names),
+ len(self.param_names) + self.arg_count,
+ ),
+ ),
+ )
+ )
+ return sklearn.tree.export_graphviz(
+ self.model_function.regressor,
+ out_file=None,
+ feature_names=feature_names,
+ )
+ if type(self.model_function) == df.LMTFunction:
+ feature_names = list(
+ map(
+ lambda i: self.param_names[i],
+ filter(
+ lambda i: not self.model_function.ignore_index[i],
+ range(len(self.param_names)),
+ ),
+ )
+ )
+ feature_names += list(
+ map(
+ lambda i: f"arg{i-len(self.param_names)}",
+ filter(
+ lambda i: not self.model_function.ignore_index[i],
+ range(
+ len(self.param_names),
+ len(self.param_names) + self.arg_count,
+ ),
+ ),
+ )
+ )
+ return self.model_function.regressor.model_to_dot(
+ feature_names=feature_names
+ )
+ return None
+
def webconf_function_map(self):
return self.model_function.webconf_function_map()