How to Visualize systemd’s Execution Dependency Tree for Debugging


2 views

When debugging systemd boot failures or service startup issues, understanding the actual execution order of units is crucial. While systemd-analyze provides basic timing information, it doesn't show the resolved dependency tree that actually executed during operation.

The closest built-in solution is systemd-analyze dot, which generates a Graphviz-compatible dependency graph:

systemd-analyze dot --from-pattern='*.target' --to-pattern='*.service' | dot -Tsvg > deps.svg

However, this shows potential dependencies rather than the actual execution path.

To see the actual execution order, we need to examine systemd's journal and cgroup information:

journalctl -b -o short-monotonic | grep -E 'Starting|Started'

For a more structured approach, inspect unit dependencies:

systemctl list-dependencies --all your-unit.service

The systemd-bootchart tool provides a visual timeline of the boot process:

bootctl status
systemd-analyze plot > bootplot.svg

Here's a Python script to generate an execution tree from journal logs:

#!/usr/bin/env python3
import systemd.journal
import networkx as nx

def build_execution_tree():
    j = systemd.journal.Reader()
    j.seek_realtime(datetime.now() - timedelta(minutes=5))
    
    G = nx.DiGraph()
    current_parent = None
    
    for entry in j:
        if 'MESSAGE' in entry:
            if 'Starting' in entry['MESSAGE']:
                unit = entry['MESSAGE'].split(' ')[-1]
                G.add_node(unit)
                if current_parent:
                    G.add_edge(current_parent, unit)
                current_parent = unit
            elif 'Started' in entry['MESSAGE']:
                current_parent = None
                
    return G

When debugging a failed multi-user.target:

systemd-analyze critical-chain multi-user.target
systemctl list-dependencies --after multi-user.target
journalctl -u failed-service.service -b

For complex cases, consider:

  • Enabling systemd debug logging with systemd.log_level=debug
  • Using systemd-analyze dump for low-level state inspection
  • Building custom visualization with systemd's D-Bus API

When troubleshooting systemd boot issues, seeing the actual execution order of units after dependency resolution can be invaluable. While systemctl list-dependencies shows static relationships, we need dynamic execution tracing.

Systemd provides several built-in tools for execution analysis:


# Show time-critical chain
systemd-analyze critical-chain

# Generate SVG of boot process
systemd-analyze plot > boot.svg

# Detailed timing breakdown
systemd-analyze blame

For the complete dependency-resolved execution tree, combine these techniques:


# 1. Get the full unit list with states
journalctl --list-boots
systemctl list-units --all --state=failed

# 2. Extract the execution graph
systemd-analyze dot | dot -Tsvg > execution_graph.svg

# 3. Filter for specific units (e.g., network.target)
systemd-analyze dot network.target | dot -Tpng > network_deps.png

When a service fails to start during boot:


# Find which units were active when failure occurred
journalctl -b -1 --unit=my-failed-service.service

# See what was supposed to start next
systemd-analyize verify my-failed-service.service

# Check ordering requirements
systemctl show my-failed-service.service -p After -p Before

For visual timeline analysis:


sudo apt install bootchart
sudo systemctl enable systemd-bootchart

Reboot and check /var/log/bootchart/ for process trees and timing diagrams.

For advanced users, systemd's internal state can be inspected:


# Dump complete state (warning: verbose)
busctl introspect org.freedesktop.systemd1 /org/freedesktop/systemd1

# Monitor job queue in real-time
busctl monitor org.freedesktop.systemd1

Combine these techniques to build a complete picture of your system's initialization sequence and pinpoint exactly where failures occur in the dependency tree.