systemd-analyze
is your friend.
For example systemd-analyze critical-chain
outputs blocking tree of daemons.
Mine for example:
graphical.target @20.211s
└─multi-user.target @20.211s
└─nginx.service @19.348s +862ms
└─network.target @19.347s
└─NetworkManager.service @10.315s +9.031s
└─basic.target @10.312s
└─timers.target @10.311s
└─systemd-tmpfiles-clean.timer @10.311s
└─sysinit.target @10.295s
└─systemd-update-utmp.service @10.167s +127ms
└─systemd-tmpfiles-setup.service @10.124s +41ms
└─local-fs.target @10.097s
└─home-entd-Downloads.mount @10.093s +2ms
└─home.mount @9.326s +672ms
└─[email protected] @8.472s +696ms
└─dev-sda6.device @8.471s
NetworkManager in example basically holding entire bootup.
If you want to have more detailed view you can render entire execution chain in a svg file.
systemd-analyze plot > something.svg
outputs entire chain (120+ modules) as progress bars to high-res svg file which show states, that are blocked and another problems.
Finally you have systemd-analyze dot
tool which outputs dot file which outputs entire hierarchy:
systemd-analyze dot | dot -Tpng -o stuff.png
with dot tool you can output it as ps and svg files too.
All of above tools are built-in in systemd-analyze tool which comes by default with systemd in archlinux at least. I think there is some 3rd party projects dealing with it too.