diff options
-rwxr-xr-x | bin/analyze-archive.py | 7 | ||||
-rwxr-xr-x | bin/analyze-kconfig.py | 3 | ||||
-rw-r--r-- | lib/cli.py | 15 | ||||
-rw-r--r-- | lib/functions.py | 23 | ||||
-rw-r--r-- | lib/parameters.py | 63 |
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( @@ -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() |