• 优化嵌入式Linux的启动时间之内核


    导读:嵌入式Linux在应用中往往希望系统能在尽量短的时间内启动,以提高用户体验。而且在有的应用场合,对启动时间具有严格的时间要求,尤其在工业或者医疗器械应用领域。此时如何加快Linux的启动,将成为一个挑战,对于大多数应用开发人员而言,由于Linux系统的复杂性,对于如何提高启动速度,往往无从下手。那么读完优化嵌入式Linux的启动时间系列文章,将获得清晰完整的解决思路。本文将从内核的角度探讨如何优化进而缩短启动时间。
    在这里插入图片描述
    1.有用的调试手段
    1.1 内核初始化度量函数
    要找出最长执行时间的内核初始化函数,请在内核命令行中添加initcall_debug。将内核日志中得到如下日志:在这里插入图片描述
    如使用initcall_debug可能需要在内核配置中使用CONFIG_LOG_BUF_SHIFT增加日志缓冲区的大小。还可能需要使能CONFIG_PRINTK_TIME和CONFIG_KALLSYMS。

    1.2 使用内核启动图进行有目的的优化
    使用initcall_debug可以生成启动图,从而轻松查看哪些内核初始化函数需要最多时间来执行。

    • 复制dmesg命令的输出并将其粘贴到文件中(我们将其称为启动日志boot.log)
    • 在开发工作站上,在内核源代码中运行scripts / bootgraph.pl脚本:scripts / bootgraph.pl boot.log> boot.svg
    • 现在可以使用矢量图形编辑器(例如inkscape)打开启动图:在这里插入图片描述
      首先从花费最长时间的功能开始尝试优化。对于每个功能:
    • 在内核源代码中查找其定义。
    • 可以使用Elixir
    • 注意:某些函数名称可能不存在,名称与modulename_init相对应。然后,在相应的模块中查找初始化代码。
    • 删除不必要的功能:
    • 通过查看相应源目录中的Makefile,找到哪个内核配置参数可编译代码。
    • 延后加载处理:
      查找功能所属的模块(如果有)。如果可能,请稍后加载此模块。
    • 优化必要的功能:
      • 查找可以用于减少探测时间的参数,并查找module_param宏。
      • 查找延迟循环和对名称中包含delay的函数的调用, 可以减少此类延迟,并查看代码是否仍然有效。

    1.3 减小内核尺寸
    首先,我们专注于在不删除功能的情况下缩小尺寸

    • 主要机制是使用内核模块
    • 将启动时不需要的所有内容编译为模块
    • 有两个好处:内核更小且加载速度更快,初始化代码更少
    • 删除用户空间不需要的功能:
      CONFIG_KALLSYMS,CONFIG_DEBUG_FS,CONFIG_BUG
    • 用专为嵌入式系统设计的功能:CONFIG_SLOB,CONFIG_EMBEDDED

    然后考虑内核压缩的方式:
    根据存储读取速度和CPU解压缩内核之间的平衡,需要对不同的压缩算法进行测试。还建议在内核优化过程结束时尝试压缩选项,因为结果可能会因内核大小而异。
    在这里插入图片描述
    在基于TI AM335x (ARM), 1 GHz, Linux 5.1测试:
    在这里插入图片描述
    Lzo和Gzip似乎是最好的解决方案。 但这结果取决于存储和CPU性能,故在决定方案是务必进行测试。
    另外内核的编译选项也有可以优化的可能:

    • CONFIG_CC_OPTIMIZE_FOR_SIZE:可以使用gcc -Os而不是gcc -O2编译内核。
    • 这样的优化会优先考虑代码大小,但会牺牲代码速度。
    • 结果:初始引导时间更好(较小的启动时间),但是较慢的内核代码可能会使性能降低。系统运行速度会变慢!

    1.4 延迟驱动程序和初始化调用
    如果有点功能无法编译为模块(例如,网络或模块子系统),可以尝试推迟执行。内核不会缩小,但某些初始化将被推迟,所以启动变快。通常,您可以修改probe()函数以返回-EPROBE_DEFER,直到它们准备好运行为止。
    有关支持此功能的详细信息,请参见
    https://lwn.net/Articles/485194/。

    1.5 关闭控制台输出
    控制台输出实际上要花费很多时间(非常慢的设备)。 产品中可能不需要。通过在内核命令行中传递quiet参数来禁用它。但仍然可以使用dmesg获取内核消息。这一步一般建议等最后一步再做,否则将损失控制台进行调试。

    1.6 预置jiffy
    每次引导时,Linux内核都会校准延迟循环(用于udelay()函数)。这将测量每个jiff y(lpj)值的循环次数。只需要测量一次!在内核启动消息中找到 lpj值:
    Calibrating delay loop… 996.14 BogoMIPS (lpj=4980736)
    然后将lpj = 添加到内核命令行:
    Calibrating delay loop (skipped) preset value… 996.14 BogoMIPS (lpj=4980736)

    1.7 多处理器
    SMP初始化很慢,即使您只有一个核心CPU,通常也会在默认配置中启用它(默认配置应支持多个系统)。因此,如果只有一个CPU内核,请确保将其禁用。BeagleBone Black上的结果:压缩内核大小:-188 KB
    要节省最后的毫秒数,您可能需要删除不必要的功能:

    • CONFIG_PRINTK = n与quiet命令行参数具有相同的效果,但是您无权访问内核消息。但是,您将拥有一个非常小的内核。
    • 在Thumb2模式下编译内核:CONFIG_THUMB2_KERNEL(任何ARM工具链都可以做到)。
    • 模块装卸
    • 块层(Block layer)
    • 网络堆栈
    • USB堆栈
    • 电源管理功能
    • CONFIG_SYSFS_DEPRECATED
    • 输入:键盘/鼠标/触摸屏
    • 减少CONFIG_LEGACY_PTY_COUNT的值或设置pty.legacy_count内核参数

    后续会发布:
    优化嵌入式Linux的启动时间之bootloader
    敬请关注!

    码字不易若您觉得文章不错,不妨转发分享,点点在看,亦或者小小打赏,都将激励我们持续更新。
    关注公众号扫左下二维码,关注公众号内容更丰富
    回复“领取资源”可领取liunx、安卓视频教程、人工智能视频等学习资料。

    ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200303220245653.png?在这里插入图片描述
    在这里插入图片描述

    为节约时间,文章同步自公众号(首发) 如需学习资料,请用微信关注文中公众号二维码,后台发送"领取",可免费获取海量学习资料,涵盖单片机技术,信号处理,人工智能,嵌入式linux,C/C++编程,数据结构与算法
  • 相关阅读:
    linux device drivers ch02
    linux device drivers ch01
    【推荐系统】Learning to Rank(还在编辑)
    【Python】垃圾回收机制
    【ML】数据清洗
    【ML】从Titannic说起一个完整机器学习的7步骤
    【MF】SVD
    【Java】toString
    【Java】Runtime
    【Java】内存
  • 原文地址:https://www.cnblogs.com/embInn/p/14038155.html
Copyright © 2020-2023  润新知