Skip to content

Commit d60518a

Browse files
committed
tools: tplgtool2: handle graph-only feature topology nodes
Feature topologies may contain graph endpoints that do not map to a DAPM widget (for example, mixout.21.1). Make tplgtool2 robust to these graph-only nodes instead of raising KeyError while building graph metadata. Keep the issue visible by emitting a warning and by rendering graph-only nodes with a distinct style and label in graph output. This keeps parsing and rendering usable for feature topologies while still surfacing broken/incomplete graph<->widget mappings. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
1 parent d1f04bf commit d60518a

1 file changed

Lines changed: 45 additions & 5 deletions

File tree

tools/tplgtool2.py

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,11 @@ def _build_nodes_names_in_graph(graph_list: "list[Container]", nodes_dict: "dict
787787
names = {}
788788
for edge in graph_list:
789789
for ename in [edge["source"], edge["sink"]]:
790-
node = nodes_dict[ename]
790+
node = nodes_dict.get(ename)
791+
if node is None:
792+
# Some feature topologies reference graph endpoints not present in
793+
# DAPM widgets. Keep these endpoints as-is instead of failing.
794+
continue
791795
for name in [node["widget"]["name"], node["widget"]["sname"]]:
792796
if name != ename:
793797
names[name] = ename
@@ -811,6 +815,17 @@ def _build_edges(graph_list: "list[Container]") -> "tuple[dict[str, list[str]],
811815
backward_edge[edge["sink"]].append(edge["source"])
812816
return forward_edge, backward_edge
813817

818+
@staticmethod
819+
def _build_unknown_nodes(graph_list: "list[Container]", nodes_dict: "dict[str, Container]") -> "set[str]":
820+
"Collect graph nodes that do not map to any widget name/sname."
821+
unknown = set()
822+
for edge in graph_list:
823+
if edge["source"] not in nodes_dict:
824+
unknown.add(edge["source"])
825+
if edge["sink"] not in nodes_dict:
826+
unknown.add(edge["sink"])
827+
return unknown
828+
814829
@staticmethod
815830
def _build_leaves(node_names: "list[str]", forward_edges: "dict[str, list[str]]", backward_edges: "dict[str, list[str]]") -> "tuple[set[str], set[str], set[str]]":
816831
r"""Build leaves.
@@ -845,6 +860,10 @@ def __init__(self, grouped_tplg: GroupedTplg):
845860
self._nodes_dict = TplgGraph._build_nodes_dict(grouped_tplg.widget_list)
846861
self._nodes_names_in_graph = TplgGraph._build_nodes_names_in_graph(grouped_tplg.graph_list, self._nodes_dict)
847862
self._forward_edges, self._backward_edges = TplgGraph._build_edges(grouped_tplg.graph_list)
863+
self._unknown_nodes = TplgGraph._build_unknown_nodes(grouped_tplg.graph_list, self._nodes_dict)
864+
if self._unknown_nodes:
865+
unknown_nodes = ", ".join(sorted(self._unknown_nodes))
866+
print(f"WARNING: graph-only node(s) without matching widget: {unknown_nodes}", file=sys.stderr)
848867
self._isolated, self._heads, self._tails = TplgGraph._build_leaves(map(self.node_name_in_graph, grouped_tplg.widget_list), self._forward_edges, self._backward_edges)
849868

850869
def _node_name_in_graph_from_name(self, name: str) -> str:
@@ -949,12 +968,31 @@ def _display_node_attrs(self, name: str, widget: Container):
949968

950969
def _display_edge_attr(self, edge: Container):
951970
attr = {}
952-
if GroupedTplg.is_virtual_widget(self._nodes_dict[edge["source"]])\
953-
or GroupedTplg.is_virtual_widget(self._nodes_dict[edge["sink"]]):
971+
source_widget = self._nodes_dict.get(edge["source"])
972+
sink_widget = self._nodes_dict.get(edge["sink"])
973+
if source_widget is None or sink_widget is None:
974+
return attr
975+
if GroupedTplg.is_virtual_widget(source_widget) \
976+
or GroupedTplg.is_virtual_widget(sink_widget):
954977
attr['style'] = "dotted"
955978
attr['color'] = 'blue'
956979
return attr
957980

981+
def _display_unknown_node_attrs(self, name: str):
982+
"Style graph-only nodes so missing widgets are visible in rendered graph."
983+
attr = {
984+
'shape': 'box',
985+
'style': 'dashed',
986+
'color': 'orangered3',
987+
'fontcolor': 'orangered3',
988+
}
989+
if self._forward_edges[name] and self._backward_edges[name]:
990+
kind = 'graph-only junction'
991+
else:
992+
kind = 'graph-only endpoint'
993+
attr['label'] = f'<{name}<BR ALIGN="CENTER"/><SUB>{kind}</SUB>>'
994+
return attr
995+
958996
def draw(self, outfile: str, outdir: str = '.', file_format: str = "png", live_view: bool = False):
959997
r"""Draw graph and write it to file.
960998
@@ -978,6 +1016,8 @@ def draw(self, outfile: str, outdir: str = '.', file_format: str = "png", live_v
9781016
from tempfile import gettempdir
9791017

9801018
graph = Digraph("Topology Graph", format=file_format)
1019+
for name in self._unknown_nodes:
1020+
graph.node(name, **self._display_unknown_node_attrs(name))
9811021
for node in self._tplg.widget_list:
9821022
name = self.node_name_in_graph(node)
9831023
if name not in self._isolated: # skip isolated nodes.
@@ -1088,7 +1128,7 @@ def _find_connected_comp(self, node_name: str, name_predicate) -> "list[Containe
10881128
acc = set()
10891129
self._find_connected_node_recursively(self._forward_edges, node_name, name_predicate, acc)
10901130
self._find_connected_node_recursively(self._backward_edges, node_name, name_predicate, acc)
1091-
return [self._nodes_dict[name] for name in acc]
1131+
return [self._nodes_dict[name] for name in acc if name in self._nodes_dict]
10921132

10931133
def find_connected_comp(self, ref_node: Container, predicate) -> "list[Container]":
10941134
r"""Find specified components connected to `ref_node`.
@@ -1127,7 +1167,7 @@ def find_connected_comp(self, ref_node: Container, predicate) -> "list[Container
11271167
"""
11281168
return self._find_connected_comp(
11291169
self.node_name_in_graph(ref_node),
1130-
lambda name: predicate(self._nodes_dict[name]))
1170+
lambda name: name in self._nodes_dict and predicate(self._nodes_dict[name]))
11311171

11321172
def find_comp_for_pcm(self, pcm: Container, prefix: str) -> "list[list[Container]]":
11331173
r"""Find specified components for PCM.

0 commit comments

Comments
 (0)