核心是用dmesg配合printk.time=y和initcall_debug分析内核阶段硬件probe与initcall耗时,而非systemd-analyze;需通过时间戳差值或“returned after x ms”定位具体驱动初始化延迟。

Linux 系统中分析启动日志里的硬件初始化耗时,核心是聚焦内核阶段的设备探测、驱动 probe 和 initcall 执行过程。这部分不归 systemd 管理,所以不能靠 systemd-analyze blame,而要依赖内核日志(dmesg)配合时间戳和调试机制。
用 dmesg + 时间戳看硬件 probe 耗时
内核在初始化过程中会打印设备识别、驱动绑定、probe 完成等关键信息,每条日志默认不含精确时间,需启用 printk.time=y:
- 重启时在 GRUB 编辑界面按 e,找到
linux行末尾添加printk.time=y - 启动后执行:
dmesg | grep -i "probe\|registered\|initialized\|nvme\|igb\|ahci\|usb" - 观察输出中的时间戳(格式如
[ 1.234567]),计算两个相关事件之间的时间差,例如:
[ 1.012345] nvme 0000:01:00.0: enabling device (0000 -> 0002)
[ 1.876543] nvme0n1: p1 p2
说明 NVMe 设备从使能到分区识别耗时约 864ms
用 initcall_debug 定位驱动初始化函数耗时
很多硬件驱动的“慢”不在加载(.ko 文件读入),而在 xxx_init() 函数执行——比如等待 PCIe link up、重置控制器、校验固件。这时需要 initcall_debug:
- GRUB 启动参数追加:
initcall_debug printk.time=y(两者需同时开启) - 系统起来后运行:
dmesg | grep "initcall.*returned" - 重点关注形如:
initcall nvme_core_init+0x0/0x1234 returned 0 after 423 msecs
initcall drm_kms_helper_init+0x0/0x567 returned 0 after 1120 msecs
这些就是具体子系统或驱动模块的初始化函数真实耗时 - 注意:
initcall_debug会显著拖慢启动(尤其服务器多网卡/显卡场景),仅用于临时诊断,勿长期启用
结合 systemd-analyze time 判断是否属于内核瓶颈
先快速确认问题是否出在内核阶段:
- 运行
systemd-analyze time,看kernel阶段是否异常高(通常应 - 如果 kernel 时间高,但
dmesg日志里没有明显卡顿点,可能是早期动作(如 ACPI 表解析、SMAP/SMEP 初始化、Secure Boot 验证)导致,此时可加acpi.debug_layer=0xffffffff acpi.debug_layer=0x2进一步细分 - 若 kernel 时间正常(
检查硬件枚举是否被阻塞
有些硬件初始化不报错,但会静默等待超时,比如 USB 主机控制器未响应、PCIe AER 错误重试、SATA Link training 失败:
- 运行
dmesg | grep -i "timeout\|fail\|error\|unable\|waiting" - 特别关注:
usb 1-1: device not accepting address
ata1: softreset failed (device not ready)
nvme 0000:01:00.0: Device not ready; aborting initialisation - 这类日志往往自带时间戳,连续出现多个“waiting for…”且间隔固定(如 3s、5s),说明内核在轮询等待硬件就绪,实际就是硬件初始化卡住











