43、Linux系统调优:内核测量、优化与启动时间缩减

Linux系统调优:内核测量、优化与启动时间缩减

在Linux系统的使用和开发中,系统调优是一项至关重要的工作。它能够帮助我们更好地管理资源、提升性能,特别是在嵌入式设备等资源受限的场景中,调优显得尤为关键。本文将深入探讨内核组件代码空间占用的测量方法、使用Bloat - O - Meter工具对比内核大小变化,以及如何减少内核启动时间等方面的内容。

1. 内核组件代码空间占用测量

在编译内核时,每个目录下的文件会先编译成 .o 文件,再链接成 built - in.o 文件。子目录的 built - in.o 文件会进一步聚合,最终与其他支持代码和 initramfs 内容一起链接成最终的内核镜像。

要测量哪些组件占用了最多的代码空间,可通过扫描内核目录并查看 built - in.o 文件的大小来实现。以下是具体操作步骤:
1. 进入内核源代码目录:

$ cd <kernel source directory>
  1. 查找所有 built - in.o 文件并使用 arm - linux - size 工具打印不同部分的大小:
$ find . -name built - in.o - type f | xargs arm - linux - size

执行上述命令后,会得到类似如下的输出:
| text | data | bss | dec | hex | filename |
| ---- | ---- | ---- | ---- | ---- | ---- |
| 512 | 0 | 0 | 512 | 200 | ./usr/built - in.o |
| 6862 | 1796 | 1184 | 71603 | 117b3 | ./block/built - in.o |
| 13223 | 7028 | 368 | 20619 | 508b | ./kernel/irq/built - in.o |
| 241851 | 16196 | 86472 | 344519 | 541c7 | ./kernel/built - in.o |
| 3260 | 72 | 24 | 3356 | d1c | ./kernel/power/built - in.o |

需要注意的是,所有 built - in.o 文件大小之和会远大于最终内核镜像的大小,这是因为父目录的 built - in.o 文件包含了子目录的 built - in.o 文件。要查看最终内核镜像的大小,可在编译完成后,在内核目录的顶层执行以下命令:

$ arm - linux - size vmlinux

输出示例如下:
| text | data | bss | dec | hex | filename |
| ---- | ---- | ---- | ---- | ---- | ---- |
| 5255980 | 224768 | 177412 | 5658160 | 565630 | vmlinux |

了解每个 built - in.o 文件的大小对于缩减内核大小非常重要,因为在所有 built - in.o 文件合并成内核镜像后,找出哪些部分可以轻松减少内存占用就变得更加困难。

下面是对 arm - linux - size 命令输出各列含义的解释:
- text :该部分是程序或目标文件的代码,尽管名称可能会让人误解,但此部分不存储字符串常量。
- data :该部分包含初始化为常量值的变量。
- bss :该部分包含初始设置为零的全局变量,BSS 即 “Block Started by Symbol”,它源于早期的文件布局。
- dec / hex :这两列分别以十进制和十六进制格式显示 text data bss 的总和。

以下代码片段展示了这些部分的具体情况,帮助你更好地理解:

// this string would be in the data section
char g_text[] = “message: %s -> %s”;

// space for this variable would be in the bss section
static long g_lastsize;

// this code would appear in the text section
void print_message(char* str, char* str2) {
        g_lastsize = strlen(str);
        printf(g_text, str, str2);
}

在这些组件中,有几个是操作系统的核心,它们为内核的其他部分提供基础设施。这些元素的大小很难通过调整内核构建参数来改变:
- arch/ / /built - in.o :这些目录特定于你的开发板和处理器,包含内核处理中断和管理内存等操作所需的启用代码。大部分代码是汇编语言,属于非常底层的代码。
- drivers/base/built - in.o :该文件包含内核处理其他驱动程序所需的基础设施代码,即使只加载了几个驱动程序,此代码也是必需的。
- init/built - in.o :这是内核的初始化代码,类似于 C 程序中的 main() 函数。这里的大部分代码负责在启动时收集用户参数并初始化系统。
- kernel/built - in.o :这是操作系统的核心,调度器、中断处理、进程和线程处理等都在此处进行。可以通过移除调试和内核破解功能等操作来减少这部分内核的大小。
- mm/built - in.o :该目录中的代码负责内存管理。如果系统没有分页虚拟内存,移除该功能可以显著减小此组件的大小。

2. 使用Bloat - O - Meter工具

Linux 提供了一个名为 Bloat - O - Meter 的工具,它可以让你查看内核的大小,并与之前的构建版本进行比较,显示两者之间的大小差异。该工具通过显示每个项目占用的内存量,提供了关于内核大小的详细信息,是查看诸如移除 printk 等重大更改如何影响内核二进制文件大小的最佳方式。

使用该工具的步骤如下:
1. 在内核源代码树的顶层目录中复制 vmlinux 文件:

$ cd <kernel source tree>
$ cp vmlinux vmlinux.old
  1. 使用内核配置工具进行更改:
$ make menuconfig ARCH=<your arch>
  1. 重新编译内核:
$ make ARCH=<your arch> CROSS_COMPILE=<your cross compiler>
  1. 使用 Bloat - O - Meter 检查大小差异:
$ ../scripts/bloat - o - meter vmlinux.old vmlinux

以下是一个示例输出:
| 函数名 | 旧大小 | 新大小 | 大小变化 |
| ---- | ---- | ---- | ---- |
| twofish_setkey | - | 7936 | +7936 |
| pktgen_if_write | - | 7728 | +7728 |
| rmd320_transform | - | 7460 | +7460 |
| rmd160_transform | - | 7392 | +7392 |
| ieee80211_invoke_rx_handlers | - | 7140 | +7140 |
| sha512_transform | - | 6732 | +6732 |
| sha256_transform | - | 6348 | +6348 |
| static.__compound_literal | 728 | 6768 | +6040 |
| pktgen_thread_worker | - | 5928 | +5928 |
| sd_revalidate_disk | - | 5864 | +5864 |
| rfcomm_run | - | 5044 | +5044 |
| camellia_encrypt | - | 4856 | +4856 |
| rmd128_transform | - | 4796 | +4796 |
| rmd256_transform | - | 4764 | +4764 |

从输出中可以非常详细地看到每个函数的大小变化,以及由于内核开发或更改内核配置而移除的符号。

3. 减少内核启动时间

减少启动时间可以通过两种方式实现:一是减少启动过程中执行的操作,二是延迟某些活动,使启动时间分散,让系统看起来启动得更快。下面从内核和根文件系统的角度来探讨具体方法。

3.1 选择合适的根文件系统

根文件系统的选择对内核启动时间有很大影响。例如,使用 JFFS2 文件系统挂载 50MB 闪存存储需要长达 6 秒的时间,而使用只读文件系统时,挂载时间可以控制在亚秒级。如果你需要使用大容量的固态驱动器,可以考虑选择具有类似 USB 记忆棒那样的标准块设备形式的闪存硬件。

3.2 使用未压缩的内核镜像

大多数引导加载程序期望内核以压缩格式存在,在启动过程中会对其进行解压缩,这个过程会消耗时间。有时,未压缩的内核启动速度更快,但具体情况需要在目标系统上进行测量,因为解压缩时间因系统而异,没有固定的规则来判断哪种方式更快。

如果你使用的是 U - Boot 引导加载程序,可以使用以下命令创建未压缩的 U - Boot 镜像:

$ mkimage -A <your arch> -O linux \
-C none -T kernel \
-a 20008000 -e 20008000 -n linux - 2.6 \
-d arch/<your arch>/boot/Image uImage

该命令与创建压缩内核镜像文件的命令非常相似,只是使用了未压缩的目标文件 Image 而非压缩文件 zImage 。当然,未压缩的文件会更大,这是一个典型的工程权衡,即牺牲空间换取速度。如果闪存空间不是很紧张,建议在目标系统上测试哪种方式效果更好。

3.3 禁用启动时的控制台输出

在启动过程中,系统会输出各种消息,而生成这些消息会消耗时间,因为系统需要与速度较慢的 I/O 设备交互以输出数据。如果使用的是串行连接,这些消息可能会导致接近一秒的延迟。你可以在目标板上尝试以下命令:

$ dmesg | wc -c

或者将 dmesg 命令的内容复制到开发主机上,使用 wc 命令。 wc - c 用于统计文件中的字符数,将这个数字除以串口的波特率,就可以估算出将这些输出写入控制台所需的时间(以秒为单位)。例如,如果 wc - c 返回 18530,而串口的波特率为 115200,那么内核大约会花费五分之一秒的时间等待输出写入串口;当波特率为 9600 时,延迟将近两秒。虽然 VGA 控制台的速度大约是 115200 波特率串口的两倍,但这仍然是浪费的时间。

要移除这些消息,可以在内核命令行中添加 quiet 参数。与禁用 printk 不同,使用 quiet 参数时,消息仍然会生成,但在启动时不会显示在控制台上。使用 quiet 而不是从内核中移除 printk 的好处是,你可以轻松地通过更改引导加载程序传递给内核的参数,恢复到更详细的输出模式,而无需重新编译内核。

3.4 延迟初始化

延迟初始化的原理是延迟已编译到内核中的内核模块的初始化代码执行。在内核启动后,向 /proc/deferred_initcalls 写入数据,剩余的初始化代码就会运行。当某些外设在大多数情况下不会立即使用时,这种方法非常有用。例如,对于一个定期收集数据并通过网络报告批量数据的设备,可以延迟网络设备的初始化,使设备能够尽快开始收集数据。需要注意的是,总的时间消耗不变,但部分代码会在不太关键的时间执行。

使用该功能需要对你的内核应用一个补丁,这个补丁通常是针对比主线内核版本落后几个发布版本的内核进行测试的。可以通过以下命令下载补丁:

$ wget http://elinux.org/images/1/18/Deferred_initcalls.patch

应用补丁后,需要修改你想要延迟初始化的模块的源文件。例如,如果设备的网卡(SMC91x)可以稍后初始化,将驱动程序中的代码:

module_init(smc_init);

修改为:

module_deferred_init(smc_init)

module_deferred_init 函数会将初始化调用排队,直到你请求执行它们。可以通过以下命令触发执行:

echo 1 >/proc/deferred_initcalls

需要注意的是,这个操作只能执行一次,后续向 /proc/deferred_initcalls 写入数据会产生错误消息,提示该操作已经执行过。要知道, proc 文件系统并不存在于磁盘上,它是内核数据结构的一种视图, /proc/deferred_initcalls 并不是传统意义上的文件,向其写入数据的结果是执行初始化调用,而不是将数据存储在某个地方。

由于驱动程序的初始化需要与硬件进行交互,这是一个耗时的过程,因此能够先启动目标设备的必需设备可以节省大量时间。但这种方法的最大缺点是,它需要对整个内核进行修改,并且需要了解设备的使用方式,以便正确地延迟一组驱动程序的初始化。

综上所述,通过合理测量内核组件代码空间占用、使用 Bloat - O - Meter 工具对比内核大小变化以及采用上述减少内核启动时间的方法,可以有效地对 Linux 系统进行调优,提升系统性能和响应速度。

Linux系统调优:内核测量、优化与启动时间缩减

4. 优化效果评估与总结

在完成上述各项调优操作后,需要对优化效果进行评估,以确定这些操作是否达到了预期的目标。以下是一些评估的方法和要点。

4.1 代码空间占用评估

通过再次使用之前介绍的测量方法,查看 built - in.o 文件的大小以及最终内核镜像的大小,对比优化前后的数据,确定是否成功减少了代码空间占用。可以将优化前后的 arm - linux - size 命令输出结果整理成表格,直观地观察各部分的变化。

优化前 text data bss dec hex filename
5255980 224768 177412 5658160 565630 vmlinux
优化后 text data bss dec hex filename
[优化后数值] [优化后数值] [优化后数值] [优化后数值] [优化后数值] vmlinux

通过对比表格中的数据,可以清晰地看到哪些部分的代码空间得到了缩减,哪些部分没有明显变化甚至有所增加。

4.2 内核大小变化评估

使用 Bloat - O - Meter 工具再次进行测量,对比不同版本内核的大小差异。观察函数大小的变化以及符号的增减情况,分析哪些优化操作对内核大小产生了显著影响。例如,如果移除了某些调试功能,应该能够看到相关函数的大小减少或者符号被移除。

4.3 启动时间评估

使用计时工具,如 time 命令,多次测量优化前后的内核启动时间,取平均值以获得更准确的结果。可以在启动脚本中添加计时代码,或者在启动过程中手动记录时间。以下是一个简单的使用 time 命令测量启动时间的示例:

$ time (reboot; sleep 10; # 等待系统重启并稳定一段时间
# 这里可以添加一些检查系统是否完全启动的命令
)

将优化前后的启动时间数据整理成表格:

优化前 优化后
[优化前平均启动时间] [优化后平均启动时间]

通过对比启动时间,可以直观地看到优化措施是否有效。如果启动时间明显减少,说明优化操作达到了预期效果;如果没有明显变化,需要重新审视优化策略,检查是否有遗漏或者错误的操作。

5. 调优过程中的注意事项

在进行 Linux 系统调优的过程中,有一些注意事项需要特别关注,以避免出现问题。

5.1 备份重要数据

在进行任何内核配置更改、应用补丁或者重新编译内核之前,务必备份重要的数据和文件。因为这些操作可能会导致系统出现故障或者数据丢失,备份可以确保在出现问题时能够恢复到之前的状态。

5.2 测试环境的选择

建议在测试环境中进行调优操作,而不是直接在生产环境中进行。测试环境可以模拟生产环境的配置和负载,在测试环境中验证优化措施的有效性和稳定性后,再将其应用到生产环境中,以避免对生产系统造成影响。

5.3 逐步实施优化

不要一次性进行大量的优化操作,而是应该逐步实施。每次只进行一项或少数几项优化,然后进行测试和评估,观察系统的性能变化。这样可以更容易确定哪些优化操作产生了积极的效果,哪些操作可能带来了问题。

5.4 了解硬件和软件的兼容性

在进行调优时,需要了解硬件和软件的兼容性。例如,某些硬件可能不支持某些内核功能,或者某些软件可能依赖于特定版本的内核。在进行优化之前,查阅相关的文档和资料,确保优化操作不会导致硬件和软件之间出现兼容性问题。

6. 总结与展望

通过对内核组件代码空间占用的测量、使用 Bloat - O - Meter 工具对比内核大小变化以及采取减少内核启动时间的一系列措施,我们可以有效地对 Linux 系统进行调优。在实际应用中,需要根据具体的需求和系统环境,选择合适的优化方法。

未来,随着硬件技术的不断发展和软件功能的日益复杂,Linux 系统调优将面临新的挑战和机遇。一方面,新的硬件架构和设备可能需要更精细的调优策略来充分发挥其性能;另一方面,自动化调优工具和技术的发展将使得调优过程更加高效和便捷。我们可以期待更多智能化、自适应的调优方法出现,为 Linux 系统的性能提升提供更强大的支持。

同时,开源社区的发展也为系统调优提供了丰富的资源和经验。开发者们可以通过参与开源项目,分享自己的调优经验和成果,共同推动 Linux 系统的发展和优化。

总之,Linux 系统调优是一个不断探索和实践的过程,通过不断学习和尝试新的方法,我们可以让 Linux 系统在各种场景下都能发挥出最佳性能。

总结流程图

graph LR
    A[开始调优] --> B[测量内核组件代码空间占用]
    B --> C[使用 Bloat - O - Meter 工具对比内核大小]
    C --> D[减少内核启动时间]
    D --> E[评估优化效果]
    E --> F{效果是否达标}
    F -- 是 --> G[总结经验并应用到生产环境]
    F -- 否 --> H[重新审视优化策略并调整]
    H --> B
    G --> I[持续关注系统性能并适时优化]

注意事项列表

  1. 备份重要数据
  2. 在测试环境中进行调优
  3. 逐步实施优化
  4. 了解硬件和软件的兼容性

通过以上的调优过程和注意事项,我们可以更加科学、有效地对 Linux 系统进行优化,提升系统的性能和稳定性,满足不同场景下的需求。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值