From 29942475c5ce4c9f1d7a76273912777445f7d429 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sun, 10 Jul 2022 13:46:17 +1000 Subject: [PATCH] scripts: gen_handles: output dependency graph Output the final dependency graph as a `.dot` file, which when rendered by graphviz can be easier to comprehend than the text descriptions. This output is optional in that it will not be generated if `graphviz` is not installed. Signed-off-by: Jordan Yates --- CMakeLists.txt | 1 + scripts/build/elf_parser.py | 22 ++++++++++++++++++++++ scripts/build/gen_handles.py | 11 +++++++++++ scripts/requirements-extras.txt | 3 +++ 4 files changed, 37 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 71c6a67e12d435..7bb81098f12350 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -872,6 +872,7 @@ if(CONFIG_HAS_DTS) ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/gen_handles.py --output-source dev_handles.c + --output-graphviz dev_graph.dot --num-dynamic-devices ${number_of_dynamic_devices} --kernel $ --zephyr-base ${ZEPHYR_BASE} diff --git a/scripts/build/elf_parser.py b/scripts/build/elf_parser.py index f6311af7130d24..d73b68f6dd1f8e 100644 --- a/scripts/build/elf_parser.py +++ b/scripts/build/elf_parser.py @@ -254,3 +254,25 @@ def _on_device(sym): # Link injected devices to each other self._link_injected(devices_by_ord) + + def device_dependency_graph(self, title, comment): + """ + Construct a graphviz Digraph of the relationships between devices. + """ + import graphviz + dot = graphviz.Digraph(title, comment=comment) + # Split iteration so nodes and edges are grouped in source + for dev in self.devices: + if dev.ordinal == DeviceOrdinals.DEVICE_HANDLE_NULL: + text = '{:s}\\nHandle: {:d}'.format(dev.sym.name, dev.handle) + else: + n = self.edt.dep_ord2node[dev.ordinal] + label = n.labels[0] if n.labels else n.label + text = '{:s}\\nOrdinal: {:d} | Handle: {:d}\\n{:s}'.format( + label, dev.ordinal, dev.handle, n.path + ) + dot.node(str(dev.ordinal), text) + for dev in self.devices: + for sup in dev.devs_supports: + dot.edge(str(dev.ordinal), str(sup.ordinal)) + return dot diff --git a/scripts/build/gen_handles.py b/scripts/build/gen_handles.py index 6434bbe11f288c..37d7ab159c0910 100755 --- a/scripts/build/gen_handles.py +++ b/scripts/build/gen_handles.py @@ -51,6 +51,8 @@ def parse_args(): type=int, help="Input number of dynamic devices allowed") parser.add_argument("-o", "--output-source", required=True, help="Output source file") + parser.add_argument("-g", "--output-graphviz", + help="Output file for graphviz dependency graph") parser.add_argument("-z", "--zephyr-base", help="Path to current Zephyr base. If this argument \ is not provided the environment will be checked for \ @@ -116,6 +118,15 @@ def main(): parsed_elf = ZephyrElf(args.kernel, edt, args.start_symbol) + if args.output_graphviz: + # Try and output the dependency tree + try: + dot = parsed_elf.device_dependency_graph('Device dependency graph', args.kernel) + with open(args.output_graphviz, 'w') as f: + f.write(dot.source) + except ImportError: + pass + with open(args.output_source, "w") as fp: fp.write('#include \n') fp.write('#include \n') diff --git a/scripts/requirements-extras.txt b/scripts/requirements-extras.txt index e2beebc6be1b34..a43ec214a0f2fb 100644 --- a/scripts/requirements-extras.txt +++ b/scripts/requirements-extras.txt @@ -26,3 +26,6 @@ grpcio-tools # used by scripts/release/bug_bash.py for generating top ten bug squashers PyGithub + +# used to generate devicetree dependency graphs +graphviz