温馨提示×

如何通过dmesg日志优化启动速度

小樊
45
2025-12-23 18:37:30
栏目: 编程语言

用 dmesg 定位内核启动瓶颈并落地优化

一、快速定位耗时阶段

  • 抓取带时间戳的内核日志,优先使用可读时间格式:dmesg -T > boot.txt。随后在日志中搜索关键锚点,如“Freeing unused kernel memory”,以该行为“内核初始化完成”的参考终点,向前回溯找出时间断层与长耗时区段。为便于量化,可在内核启动参数中加入 printk.time=1 与 initcall_debug,使日志打印每个 initcall 的开始/结束及耗时,便于排序定位最慢的初始化项。必要时在内核配置中开启 CONFIG_PRINTK_TIME、CONFIG_KALLSYMS(以及需要时增大 CONFIG_LOG_BUF_SHIFT),以避免日志截断并提升可读性。对于图形化分析,可将 dmesg 输出通过内核源码中的 scripts/bootgraph.pl 生成 kernel.svg,直观查看各 initcall 的耗时占比与串行瓶颈。

二、常见瓶颈与对应优化

  • 控制台输出过慢:大量串口打印会显著拉长启动时间。可在产品阶段使用内核参数 quiet 降低控制台输出;若需保留日志用于事后分析,仍可用 dmesg 读取。注意:调试阶段不建议过早使用 quiet,以免丢失关键线索。
  • 驱动探测与 initcall 串行:initcall_debug 能精确显示每个初始化函数的耗时,优先优化占用时间最长者。对可模块化的功能,改为模块按需加载;对必须内置的驱动,可在探测逻辑中合理使用 -EPROBE_DEFER 推迟非关键设备的初始化,减少首轮阻塞,缩短串行阶段。
  • 文件系统挂载与检查:dmesg 中挂载点之间出现明显“时间断层”常见于 fsck/f2fs resize 等耗时操作。可将这些耗时任务改为异步执行或按需执行,避免阻塞主线程;若调整过分区/UUID,需同步更新 initramfs 的 resume/swap 配置并重建,防止因寻找旧分区而长时间等待。
  • 延迟循环校准(lpj):内核启动早期会校准延迟循环(BogoMIPS/lpj)。在日志中找到形如“lpj=xxxxxxx”的行后,将其作为内核参数 lpj=xxxxxxx 预设,可跳过校准以节省数百毫秒到数秒,具体收益取决于平台。

三、从日志到行动的闭环流程

  1. 采集与锚点:dmesg -T > boot.txt;在日志中定位“Freeing unused kernel memory”作为终点锚点。
  2. 打开计时:在 bootargs 增加 printk.time=1 与 initcall_debug,复测一次以获取每个 initcall 的耗时分布。
  3. 图形化:将 dmesg 输出导入 scripts/bootgraph.pl 生成 kernel.svg,识别最耗时的 initcall 与长串行段。
  4. 针对性优化:对长耗时项执行“模块化/异步化/推迟探测/删减不必要功能”的组合策略;必要时调整内核配置(如关闭不需要的调试/文件系统等)。
  5. 消除校准开销:从日志提取 lpj 值并加入 bootargs 的 lpj= 预设。
  6. 收敛验证:再次采集 dmesg,确认关键断层的消除与总耗时的下降;保留一到两次“关闭 quiet”的对照测试,确保优化未引入功能退化。

四、关键命令清单

  • 抓取可读时间日志:dmesg -T > boot.txt
  • 启用 initcall 级计时:在 bootargs 增加 printk.time=1 initcall_debug
  • 生成启动图:cat boot.log | perl scripts/bootgraph.pl > kernel.svg
  • 查看系统启动总时长:cat /proc/uptime(首字段为系统运行时间)
  • 调整控制台日志级别(谨慎):echo 1 4 1 7 > /proc/sys/kernel/printk(降低输出量以提速,调试阶段不建议)
  • 重建 initramfs(分区/UUID 变更后):update-initramfs -u(Debian 系)

0