Skip to content

Commit

Permalink
scripts: gen_handles: output dependency graph
Browse files Browse the repository at this point in the history
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 <jordan.yates@data61.csiro.au>
  • Loading branch information
Jordan Yates authored and galak committed Jul 30, 2022
1 parent 8d17e85 commit 2994247
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 $<TARGET_FILE:${ZEPHYR_LINK_STAGE_EXECUTABLE}>
--zephyr-base ${ZEPHYR_BASE}
Expand Down
22 changes: 22 additions & 0 deletions scripts/build/elf_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
11 changes: 11 additions & 0 deletions scripts/build/gen_handles.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down Expand Up @@ -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 <zephyr/device.h>\n')
fp.write('#include <zephyr/toolchain.h>\n')
Expand Down
3 changes: 3 additions & 0 deletions scripts/requirements-extras.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 2994247

Please sign in to comment.