嵌入式 Linux 实时性能优化与相关技术解析
1. Linux 实时性能问题与中断抽象方法
1.1 Linux 内核实时性能的不足
主线内核虽有显著改进,但仍无法实现确定性的实时性能。默认调度器追求“公平性”,块 I/O 系统为最大化吞吐量会对 I/O 请求进行重新排序和合并,这些都影响了实时性能。不过,在很多应用中,只有小部分系统真正需要硬实时确定性,如高速 PID 循环控制或机器人手臂移动;而记录 PID 循环试图维持的温度,或图形化显示机器人手臂的当前位置,通常并非实时需求。
1.2 中断抽象方法概述
为实现 Linux 的实时性能,可采用中断抽象方法。该方法将 Linux 作为小实时内核下的最低优先级任务(空闲任务)运行,实时功能由该内核下的高优先级任务处理,非实时任务(如图形、文件管理和网络)则由 Linux 处理。
实时内核接管 Linux 的中断处理,当 Linux 尝试禁用中断时,实时内核只是清除内部软件中断使能标志,实际仍保持中断启用。硬件中断发生时,实时内核会判断中断指向对象:
-
RT 任务
:调度该任务。
-
Linux
:检查软件中断标志。若启用,调用相应的 Linux 中断处理程序;若禁用,记录中断发生,待 Linux 重新启用中断时再传递。
1.3 实时任务运行方式与通信机制
实时任务可作为内核空间可加载模块或用户空间进程运行。用户空间 RT 任务通过内核空间的“伙伴任务”与 RT 内核通信;内核空间 RT 任务通常需要与用户空间进程进行文件访问、网络通信或用户界面等方面的通信,RT 内核提供了 FIFO 和共享内存等机制支持与用户空间进程的通信。
1.4 中断抽象方法的优势与实现
实时操作系统体积小且简单,便于进行执行时间分析,能提供可靠的延迟上限。该方法虽也需修改内核,但修改程度远小于抢占改进方法。中断抽象 RTOS 引入了自己的 API,不过随着时间推移,两种主要实现方式都为 POSIX 线程的原生 API 开发了“包装器”,一定程度上缓解了纯粹主义者的反对。
中断抽象方法有两种主要实现:
-
RTLinux
:最初的中断抽象实现,由新墨西哥矿业与技术学院的 Victor Yodaiken 开发。虽最初为开源,但 Victor 获得了在一个操作系统上运行另一个操作系统的专利,并成立公司商业化其专有版本,后售予 Wind River,开源版本网站现重定向至 Wind River。
-
RTAI
:由米兰理工大学航空工程系的 Paolo Mantegazza 教授指导开发,是 RT Linux 的增强版本,是一个活跃的开源项目,有众多贡献者。
1.5 中断抽象流程
graph TD
A[硬件中断发生] --> B{判断指向对象}
B -->|RT 任务| C[调度任务]
B -->|Linux| D{检查软件中断标志}
D -->|启用| E[调用 Linux 中断处理程序]
D -->|禁用| F[记录中断,待 Linux 重新启用时传递]
2. Xenomai:另一种中断抽象方法
2.1 Xenomai 简介
Xenomai 曾是 RTAI 项目的一部分,后独立成项目。其所有实时任务都在用户空间运行,实时核心实现的原生 API 与 RTAI 相似,还提供了针对流行操作系统(如 Posix、VxWorks 和 µITRON 等)的 API“皮肤”。RTAI 专注于最小化延迟,而 Xenomai 旨在实现简洁设计、可扩展性和可维护性,这可能是两者分裂的原因。
2.2 Xenomai 的两种实现方式
Xenomai 基于实时驱动模型(RTDM)实现了两种不同的中断抽象方法:
-
传统双内核方法
:实时内核为 Cobalt Core,在用户空间由 libcobalt 表示。使用 Posix 线程 API 的应用直接与 libcobalt 通信,使用其他 RTOS API 的应用与各自的“皮肤”通信,“皮肤”再与 copperplate 接口通信。
-
单内核方法
:省去第二个内核,glibc 直接与原生 RTDM 规范通信,所有调度由标准 Linux 内核完成。该方法性能不如双内核方法,但更简单。多数情况下,建议在内核中安装 PREEMPT_RT 补丁,单内核或双内核操作在构建时选择。
2.3 Xenomai 架构对比
| 实现方式 | 内核情况 | 通信方式 | 性能 | 复杂度 |
|---|---|---|---|---|
| 传统双内核方法 | 有实时内核(Cobalt Core) | 应用通过 libcobalt 或“皮肤”与内核通信 | 较好 | 较高 |
| 单内核方法 | 无第二个内核 | glibc 直接与 RTDM 规范通信 | 较差 | 较低 |
3. 使用 PREEMPT_RT 补丁
3.1 补丁获取与选择
PREEMPT_RT 补丁托管在 kernel.org,路径为 kernel.org//pub/linux/kernel/projects/rt/。补丁有两种形式:
-
patch…
:所有补丁打包成一个大文件。
-
patches…
:单个补丁的集合。
两种形式都有 .gz 或 .xz 格式,.xz 压缩算法更高效,但 CentOS 7 的 tar 命令不识别 .xz 格式,KDE Ark 程序可解压。
3.2 补丁应用尝试
尝试为 BeagleBoard 内核打 3.8.13 内核的 RT 补丁,在 3.8/ 子文件夹中,因页面上的补丁适用于 3.8.13.14 版本,故进入 older/ 子文件夹选择了 -rt9 补丁。应用补丁时,365 个文件中有 6 个未正确打补丁,推测是之前对上游 3.8.13 内核的补丁操作导致冲突。其中 5 个文件较易修复,drivers/net/ethernet/ti/cpsw.c 文件的 45 个“块”中有 8 个失败,导致内核 make 命令出错,难以解决。
3.3 构建工作站内核补丁
选择为工作站内核(如 3.18.48 版本)构建 PREEMPT_RT 补丁,该补丁可顺利应用。构建新内核时,建议使用已知良好的 .config 文件,可将运行桌面内核的配置文件从 /boot 目录复制到内核源代码树的 .config 中,然后运行 make oldconfig 逐步设置新选项。
运行 make xconfig,PREEMPT_RT 会引入新选项,在“处理器类型和特性”下,选择“完全可抢占内核”。保存配置后执行以下步骤:
make
su
make modules_install
make install
3.4 构建结果与测试
最后一步会将内核可执行文件 vmlinuz 复制到 /boot 目录,创建初始 RAM 磁盘映像并复制到 /boot 目录,还会在 Grub 配置文件中为新内核创建条目。重启并在 Grub 菜单中选择新构建的内核,在轻负载系统上,最大延迟升至 34.5 毫秒,平均延迟降至 284 微秒;启动 load50 20 并运行 cyclictest 测试,结果为 Min: 1 Avg: 348 Max: 37086,虽比原始内核的负载结果好,但仍不理想。
4. U-boot 命令介绍
4.1 命令基本规则
U-boot 支持广泛的命令集,所有命令期望以十六进制输入数字,可带或不带前导 0x。参数用 <…> 括起来,可选参数用 […] 进一步括起来,命令名通常可缩写为最短唯一字符串。
4.2 信息命令
| 命令 | 缩写 | 功能 |
|---|---|---|
| bdinfo | bdi | 显示目标板的信息,如内存大小和位置、时钟频率、MAC 地址等,供 Linux 内核使用。 |
| coninfo | conin | 显示可用控制台 I/O 设备的信息,包括设备名称、标志和当前使用情况。 |
| iminfo | imi | 显示图像(如 Linux 内核或 ramdisks)的头信息,列出图像名称、类型和大小,并验证 CRC32 校验和,行为受 verify 环境变量影响。 |
|
help [
| 无参数时打印所有命令的简短描述,有命令名参数时提供更详细的帮助。 |
4.3 内存命令
默认内存命令操作 32 位整数,可通过在命令名后附加 “.w”(16 位)、“.b”(8 位)或 “.l”(32 位)来改变操作位数。
| 命令 | 缩写 | 功能 |
| ---- | ---- | ---- |
| base [
] | ba | 获取或设置基地址,用于其他内存命令的偏移。无参数时显示当前基地址(默认 0),有数值参数时设置为新基地址。 |
| crc32
[
] | crc | 计算并显示从
开始的
字节的 32 位校验和,可选的第三个参数指定存储校验和的位置。 |
| cmp
| | 比较两个内存区域,
是数据项数量,与指定大小(字节、字或长整型)无关。 |
| cp
| md
[
] | | 以十六进制和 ASCII 格式显示内存范围,可选的
参数默认 64 项,记住最近的
和
,无地址参数时从上次位置继续。 |
| mm
| | 自动递增修改内存,显示地址和当前内容,提示用户输入,输入有效十六进制值替换当前值并显示下一项,输入非十六进制值终止。 |
| mtest
[
| mw
[
] | | 从
开始的内存范围写入
,可选的
默认 1。 |
| nm
| | 在固定地址修改内存(无自动递增),交互式地向同一地址写入有效十六进制数据,用于访问 I/O 设备寄存器,输入非十六进制数据终止。 |
| loop
| | 紧密循环读取内存,用于调试,该命令不会终止,只能通过重置板卡退出。 |
4.4 NAND 闪存内存命令
NAND 闪存被组织成任意大小的命名分区,所有 NAND 命令以关键字 nand 开头。BeagleBone Black 的 u-boot 实现了 NAND 命令,即使未安装 NAND 设备。
嵌入式 Linux 是一个广泛的领域,本文介绍了实现实时性能的方法、使用 PREEMPT_RT 补丁的过程以及 U-boot 命令等内容,希望能为你在嵌入式 Linux 开发中提供帮助。在实际应用中,可根据具体需求选择合适的方法和工具。
5. 实时性能优化方法总结
5.1 不同方法对比
在追求嵌入式 Linux 实时性能的过程中,我们探讨了多种方法,每种方法都有其独特的优势和适用场景。以下是对这些方法的对比总结:
| 方法 | 实现方式 | 优势 | 劣势 | 适用场景 |
| ---- | ---- | ---- | ---- | ---- |
| 中断抽象(RTLinux、RTAI) | 将 Linux 作为最低优先级任务,实时内核接管中断处理 | 可实现较高的实时性,便于进行执行时间分析,修改内核程度相对较小 | 引入新的 API,可能不被纯粹主义者认可 | 对实时性要求较高,且部分功能可分离为实时和非实时任务的应用场景 |
| Xenomai | 有传统双内核和单内核两种方式 | 提供多种 API 皮肤,设计简洁、可扩展和可维护 | 单内核方式性能相对较差,双内核方式复杂度较高 | 需要支持多种操作系统 API,且对设计和维护有一定要求的场景 |
| PREEMPT_RT 补丁 | 对 Linux 内核进行打补丁操作 | 相对直接,可在一定程度上提升实时性能 | 补丁应用可能会遇到冲突问题,性能提升效果有限 | 希望在现有 Linux 内核基础上提升实时性能,且对内核修改程度可接受的场景 |
5.2 选择建议
- 实时性要求极高的场景 :如高速 PID 循环控制、机器人手臂精确控制等,可优先考虑中断抽象方法,如 RTLinux 或 RTAI。这些方法能更好地保证实时任务的确定性和低延迟。
- 需要支持多种操作系统 API 的场景 :Xenomai 是一个不错的选择。其提供的 API 皮肤能让开发者方便地使用不同操作系统的 API,提高开发效率。
- 希望在现有内核基础上简单提升实时性能的场景 :可以尝试使用 PREEMPT_RT 补丁。不过要注意可能会遇到的补丁冲突问题。
6. 开发过程中的挑战与应对策略
6.1 补丁应用问题
在使用 PREEMPT_RT 补丁时,可能会遇到补丁无法正确应用的情况,如部分文件打补丁失败。这通常是由于之前对内核进行的其他修改导致的冲突。应对策略如下:
-
仔细检查冲突文件
:分析冲突文件的具体修改内容,找出与 PREEMPT_RT 补丁冲突的部分,手动进行调整。
-
选择合适的内核版本和补丁
:尽量选择兼容性好的内核版本和补丁,避免因版本不匹配导致的冲突。
-
备份原始内核
:在进行补丁操作前,备份好原始内核,以便在出现问题时可以恢复。
6.2 实时性能测试与调优
即使应用了实时性能优化方法,也可能无法达到预期的实时性能。此时需要进行性能测试和调优,具体步骤如下:
-
选择合适的测试工具
:如 cyclictest 工具,可用于测量系统的延迟情况。
-
分析测试结果
:根据测试结果找出性能瓶颈,如最大延迟过高、平均延迟不稳定等问题。
-
调整系统参数
:根据分析结果调整系统参数,如内核调度策略、内存分配等,以优化实时性能。
6.3 开发环境配置
在开发过程中,正确配置开发环境至关重要。以下是一些配置开发环境的要点:
-
选择合适的开发工具
:如 Eclipse 等开源 IDE,可提供便捷的开发和调试功能。
-
配置交叉开发环境
:为目标板(如 BeagleBone Black)配置交叉开发环境,确保可以在开发主机上编译和运行适用于目标板的程序。
-
管理内核配置文件
:在构建内核时,使用已知良好的 .config 文件,并根据需要调整配置选项,以满足不同的开发需求。
7. 未来发展趋势
7.1 实时性能的进一步提升
随着嵌入式系统对实时性能的要求越来越高,未来的研究和发展将继续聚焦于如何进一步提升 Linux 的实时性能。可能的方向包括更高效的调度算法、更精细的中断管理机制等。
7.2 与新兴技术的融合
嵌入式 Linux 可能会与新兴技术如人工智能、物联网等深度融合。例如,在物联网应用中,需要实时处理大量的传感器数据,嵌入式 Linux 的实时性能优化将为这些应用提供更好的支持。
7.3 开源社区的发展
开源社区在嵌入式 Linux 的发展中发挥着重要作用。未来,开源社区将继续推动嵌入式 Linux 技术的发展,提供更多的工具和资源,促进开发者之间的交流和合作。
总结
嵌入式 Linux 开发是一个充满挑战和机遇的领域。通过本文介绍的中断抽象方法、Xenomai 技术、PREEMPT_RT 补丁以及 U-boot 命令等内容,我们可以看到实现嵌入式 Linux 实时性能优化有多种途径。在实际开发过程中,我们需要根据具体的应用需求和场景选择合适的方法和工具,同时要注意开发过程中可能遇到的挑战,并采取相应的应对策略。随着技术的不断发展,嵌入式 Linux 将在更多领域发挥重要作用,为我们带来更多的创新和发展机会。希望本文能为你在嵌入式 Linux 开发的道路上提供一些有益的参考和指导。
graph LR
A[选择实时性能优化方法] --> B{实时性要求极高?}
B -->|是| C[中断抽象方法(RTLinux、RTAI)]
B -->|否| D{需要支持多种 API?}
D -->|是| E[Xenomai]
D -->|否| F{简单提升现有内核性能?}
F -->|是| G[PREEMPT_RT 补丁]
F -->|否| H[其他方法或综合考虑]
以上流程图展示了在选择实时性能优化方法时的决策流程,可根据具体需求进行选择。在开发过程中,不断探索和实践,才能更好地掌握嵌入式 Linux 技术,开发出高质量的嵌入式系统。
超级会员免费看
201

被折叠的 条评论
为什么被折叠?



