How to Visualize systemd’s Execution Dependency Tree for Debugging


11 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.