ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

同芯实测8款RTOS:上下文切换、RAM占用与选型

同芯实测8款RTOS:上下文切换、RAM占用与选型 1. 为什么非要让 8 款 RTOS 挤在同一颗 MCU 上跑第一次有人问我FreeRTOS 和 RT-Thread 哪个快的时候我随口回了一句差不多少看场景。后来被追问得多了我干脆把家里几块开发板翻出来做了一件在很多人看来有点轴的事情把 8 款主流 RTOS 挨个烧进同一颗 MCU用同一套测量代码、同一块板子、同一个编译器版本跑了一遍对照实验。之所以要这么做是因为 RTOS 的性能数据大概是嵌入式圈子里被传播得最走样的东西之一。厂商文档里写着上下文切换小于 1 微秒论坛帖子里有人喊某某系统任务切换要好几微秒卡得不行两拨人说的可能都是真的只不过一个是在 168MHz 的 Cortex-M4 上跑空任务另一个是在 72MHz 的 M3 上跑带浮点保存的任务还开着最高优化等级的调试信息。参数一变结论就翻个面。更麻烦的是误判。测 RTOS 这件事特别容易被自己骗测量点放错位置、编译器悄悄把循环优化掉、中断优先级配得不一致、Flash 等待周期没对齐——任何一个环节没控制住你测出来的就不是 RTOS 的性能而是你测试工程的质量。我这次实验最有价值的部分其实不是那张速度排名表而是那些一开始让我得出错误结论、后来被逐条揪出来的坑。这篇内容适合三类人看正在给项目选 RTOS 但被各种评测文章绕晕的工程师想知道自己手头这套系统慢在哪的中级开发者以及准备 RTOS 相关面试、想拿真实数据而不是背书式答案的人。我不会给你一个XX 最快的简单结论因为真实的答案是快慢差距远小于很多人想象而选型失败的原因几乎从来不是速度。真正决定项目成败的是移植成本、内存占用曲线、生态成熟度以及你的团队能不能在两周内把它跑通。下面我会把整套测试台怎么搭、8 款系统各自的实测表现、以及最容易导致误判的几个陷阱一条条拆开讲。你可以直接照着复现也可以只看结论但建议至少把第六部分的测量陷阱看完——那部分我踩过的坑比性能数据本身值钱得多。1.1 网上那些性能排行榜为什么普遍不可信我认真翻过十几份公开的 RTOS 对比文章发现绝大多数存在同样的问题。第一测的 MCU 不一样有的是 F103 有的是 F407主频差一倍多绝对时间数据放在一起没有意义。第二测量方法不透明只写实测上下文切换 XXX 纳秒却不说是用 GPIO 翻转测的、还是用 DWT 周期计数器测的、还是用仿真器 trace 出来的这三种方法的系统误差能差出 30% 以上。第三优化等级和编译参数很少写全-O0 和 -O2 下同一段调度代码可能差出好几倍。还有一个更隐蔽的问题很多人测的是两个任务互相让出 CPU这种最理想的情况而真实项目里上下文切换往往发生在中断里、发生在信号量阻塞唤醒路径上、发生在带浮点上下文的任务之间这些场景的耗时可能比理想情况高一到三倍。拿理想情况的数字去指导实际选型等于拿赛道成绩去买家用车。所以我自己定了个规矩任何不写明硬件型号、主频、优化等级、测量手段、任务配置的性能数字一律当营销材料看待不作为决策依据。1.2 我给自己定下的三条测试纪律为了让这次实验的结果至少对我自己有意义我强制执行了三条纪律。第一条硬件和时钟绝对统一。所有测试都在同一块 STM32F407ZGT6 开发板上完成主频锁死 168MHzFlash 等待周期固定为 5 个 wait state所有测试代码在冻结时钟树之后才允许烧写。后期为了验证移植难度我另用了一块 GD32F103C8T6 做交叉测试但两组数据绝不混在一张表里比较。第二条测量代码只有一份。所有 RTOS 上跑的都是同一套任务函数、同一套测量宏、同一套 GPIO 标记逻辑唯一变化的是 RTOS 自身的 API 调用。任务优先级、栈大小、tick 频率统一 1000Hz全部对齐。这样一来测出来的是RTOS 差异不是我写代码的差异。第三条每组数据至少跑三遍取中位数且保留原始波形。逻辑分析仪抓到的每一段波形我都存了截图测出反常数据时能回看波形判断是真实抖动还是测量故障。这一条后来救了我好几次——有一款系统第一次测出来的延迟明显偏高回看波形才发现是第一次编译时漏配了某个宏导致它默认走了带调试钩子的慢路径。1.3 入选的 8 位选手以及被我淘汰的几位最终上场的 8 款分别是FreeRTOS、RT-Thread Nano、RT-Thread 完整版、LiteOS-M、μC/OS-III、ThreadXAzure RTOS、Zephyr、TencentOS-tiny。选它们的理由是覆盖面足够典型——有极简内核有带完整中间件的有国内生态活跃的有工业界经典款也有近几年集成度很高的新派选手。被淘汰的包括 mbed OS在我这块裸板上的移植体验太依赖在线工具链和本次本地统一工具链的原则冲突、ChibiOS内核确实漂亮但我对它的 HAL 层不够熟怕引入人为误差以及一些厂商私有内核无法在非自家芯片上公平对比。淘汰不等于不好只是不适合这次实验的控制变量要求。这里多说一句选型逻辑我特意把 RT-Thread 的 Nano 版和完整版分开测因为这两个东西在资源占用上完全不是一个量级很多文章把它们混为一谈。如果你的项目只是要点灯、串口、跑几个定时任务Nano 版和完整版对你的意义截然不同这个差别后面第四部分会用数据说明。2. 把测试台搭起来硬件、工具链与统一基线搭测试台这件事看起来是准备工作实际上决定了你后面所有数据的可信度。我见过太多人花两天测数据、花半小时搭台子结果所有数据都带病。这一部分我把台子的每个细节都写清楚你照着做能省掉大量返工。2.1 MCU 选型与时钟树的统一主平台选 STM32F407ZGT6原因很实在168MHz 主频给测量留出足够的时间分辨率1MB Flash 和 192KB RAM 能装下所有 8 款系统而不用担心装不下的情况Cortex-M4 带 DWT数据观察点与跟踪单元可以直接读周期计数器测微秒级事件不用外接设备也能出数据。开发板上的 8MHz 晶振外部时钟源、SWD 调试口、两组空闲 GPIO 全部留作测量用。时钟树配置我锁成了一份固定的SystemClock_ConfigPLL 参数、AHB/APB 分频比、Flash 延迟全部写死在工程里不允许任何一款 RTOS 的移植代码去改动它。这一点必须强调某些 RTOS 的自带 BSP 会顺手改时钟或者开额外的外设时钟如果不同系统用的时钟树不一致测出来的时间数据根本没法比。注意如果你打算复现先把时钟树用示波器或 MCO 引脚输出验证一遍。我吃过一次亏某款系统的例程默认把主频设成了 120MHz而我在测之前完全没察觉直到发现它的 tick 周期对不上才回头查出来。2.2 统一的编译与优化配置工具链用的是 ARM GCC 10.3全部工程统一使用-O2 -g3 -ffunction-sections -fdata-sections链接时开--gc-sections。为什么用-O2而不是-O3因为-O3在这类调度代码上会做一些比较激进的函数内联和循环展开不同 RTOS 的代码结构不同激进优化带来的收益也不同反而会让对比失真-O2是工程实践中更常见的等级更贴近真实项目。另外统一关闭了半主机semihosting和printf重定向所有输出走 GPIO 或者 SWO避免阻塞式输出污染时间测量。堆栈大小每个任务统一 512 字节字对齐系统栈统一 1KB。tick 频率全部设为 1000Hz用的是各系统默认的 SysTick 实现没有人为改成别的定时器。2.3 测量手段从 GPIO 翻转 to DWT 周期计数我同时用了三种测量手段互相校验。第一种是 GPIO 翻转加逻辑分析仪。在任务切换的关键位置拉高/拉低一个空闲引脚用逻辑分析仪抓时间差。方法是把两段代码背靠背放置中间插入taskYIELD之类的让出调用测两次 GPIO 翻转之间的间隔再减去纯 GPIO 操作的固定开销。这种方法直观能看到波形但精度受 GPIO 翻转本身耗时影响得做校准。第二种是 DWT 周期计数器。Cortex-M3/M4 上有DWT-CYCCNT可以在代码里直接读周期数分辨率是单个 CPU 周期非常适合测微秒级事件。用法是在测量段前后各读一次差值就是周期数换算成时间只要除以主频。这个方法的坑是要记得开DEMCR寄存器的 trace 使能位还得在启动后清零计数器我一开始忘了开使能位读出来永远是 0白白浪费了半小时。第三种是 SWO 跟踪。用 SWO 输出标记点配合上位机做时间线分析用来观察调度顺序和唤醒路径。这种手段精度略低但胜在能看全局特别适合分析任务为什么晚醒了这类问题。三种手段的两两误差我控制在 5% 以内超过这个范围的数据一律重测。实测下来GPIO 翻转法对小于 200ns 的事件会有明显的量化误差所以最终的速度数据以 DWT 计数为准GPIO 波形只做交叉验证。2.4 8 款系统的移植路径与真实踩坑记录移植环节的耗时本身就是很有价值的数据我用一张表记录了下来只算从拿到源码到跑通两个任务点灯的时间不含查阅资料。RTOS移植耗时熟手估算主要踩坑点FreeRTOS40 分钟移植包版本多选错 port 文件RT-Thread Nano50 分钟需手动裁剪板级支持要自己写RT-Thread 完整版3 小时配置文件项极多容易配错串口设备LiteOS-M1.5 小时文档中英文混杂配置宏命名不统一μC/OS-III2 小时需要手工填写os_cfg.h大量参数ThreadX1 小时移植层清晰但示例偏少Zephyr5 小时构建体系完全不同学习曲线陡TencentOS-tiny1 小时文档相对新部分接口要翻源码这张表比速度表更能反映真实感受。Zephyr 我花了整整一个下午主要卡在它的构建系统和设备树概念上——它是好东西但如果你团队没有相关经验头一周基本都在和工具链较劲。RT-Thread 完整版本身不难难在配置项太多我因为一个设备名配错串口一直没输出查了一小时。还有一个通用坑几乎所有 RTOS 的SysTick处理函数名都叫SysTick_Handler如果你同时引用了芯片厂商的 HAL 库会和 HAL 自带的版本冲突。解决方法是在 RTOS 的接口里调用HAL_IncTick()或者干脆把 HAL 的 tick 关掉。这个冲突我在 LiteOS-M 上第一次遇到编译过了但一运行就进 HardFault查了半天才定位到重复定义。3. 任务切换与调度延迟谁真正快快在哪这一部分是大多数人最关心的。但先说结论8 款系统在理想情况下的上下文切换耗时差距在 2 倍以内最快的和最慢的之间绝对差值大约 0.7 微秒。这个差距在很多项目里根本不构成选型理由但它背后的原因值得弄明白。3.1 上下文切换时间的实测方法我的测法是这样的建两个同优先级任务任务 A 在一个循环里读 DWT 计数、调用taskYIELD让出、被切回来后再读一次计数差值就是让出到被重新调度回来的总时间。这个总时间减去调度器决策和 PendSV 入口出口的开销才是纯上下文切换时间。为了避免任务本身代码被优化影响测量循环里加了__asm volatile( ::: memory)内存屏障。需要说明的是这个方法测的是同优先级主动让出这个特定场景它的数值偏乐观。如果换成高优先级任务抢占低优先级任务或者中断里唤醒一个阻塞任务耗时会明显增加因为多了优先级判定和就绪链表操作。我在 3.4 节会把这两种情况的差异展开。3.2 8 款 RTOS 的切换耗时对照下表是 DWT 计数器测出的中位数数据单位微秒主频 168MHz-O2空任务栈。所有数据我都标注了它是主观测值意思是换块板子、换个编译参数就会变请只用来判断相对顺序不要当成绝对值引用。RTOS上下文切换任务就绪延迟备注ThreadX0.921.15汇编优化充分路径最短FreeRTOS1.081.32经典实现稳定RT-Thread Nano1.121.40与 FreeRTOS 接近TencentOS-tiny1.201.48内核精简LiteOS-M1.261.55调度逻辑稍重RT-Thread 完整版1.381.72带更多钩子和统计Zephyr1.451.80抽象层带来开销μC/OS-III1.521.95内建功能多路径长看到这张表你大概会有两个反应第一ThreadX 确实快第二这差距好像也没多大。我的判断和你一样。0.6 微秒的差距在 1000Hz tick、任务切换频率每秒几百次的系统里一年也就省下几毫秒。除非你的系统每秒切换几万次比如高速数据采集里的短任务轮转否则这个差距不该成为选型的决定因素。3.3 调度器决策逻辑对延迟的影响速度差距的来源主要在两个地方一是汇编层的上下文保存/恢复代码有多精简二是调度器的选下一个任务这段逻辑有多复杂。ThreadX 快的原因我拆开看过它的 PendSV 汇编保存寄存器的顺序经过精心安排尽量利用 Cortex-M 的多寄存器压栈能力而且它的就绪队列用位图加链表的结构找最高优先级任务是一条指令级别的事。μC/OS-III 慢一些是因为它内建的功能多——就绪表要维护、统计要更新、可选的钩子函数要遍历这些都是为工程便利付出的性能税。RT-Thread 完整版比 Nano 慢道理一样它带了更多运行时统计和调试钩子。这里有个很多人忽略的点上下文切换耗时和任务数量强相关。我上面测的是 2 个任务的情况。当任务数增加到 16 个某些系统的调度决策耗时会上升 30% 以上因为它们用的是线性扫描而不是优先级位图。所以如果你测的是 2 任务场景不能直接外推到几十个任务的复杂系统。3.4 同优先级轮转与 tickless 的差异前面说的方法测的是主动让出。我又补测了两个场景。场景一抢占切换。让一个高优先级任务被定时器唤醒测从唤醒时刻到它真正开始执行的时间。这个数值普遍比主动让出高 40% 到 80%因为它包含了中断入口、中断处理、就绪判定这一整条路径。8 款系统的相对顺序基本没变但绝对差值被放大了。场景二tickless 模式。开启 tickless 之后空闲时系统不再被 tick 中断打断唤醒延迟取决于下一个任务的时间点。这个模式下测出的延迟数据波动非常大因为测量本身就包含了睡眠到唤醒的路径。我建议这一项单独看不要和前面的数字混在一起——我就见过有人把 tickless 唤醒延迟当成上下文切换时间得出某系统切换要几十微秒的错误结论。提示如果你在测 RTOS 延迟时发现数值特别大几百微秒甚至毫秒级先检查是不是测到了 tickless 睡眠唤醒或者是不是测到了任务阻塞超时的时间这两个都是常见的误读源。4. 资源占用Flash 和 RAM 才是嵌入式真正的硬通货在 MCU 上速度和内存的关系有点像汽车的马力和后备箱——大多数时候你更缺的是后备箱。RTOS 的 Flash/RAM 占用直接决定了你能不能用某颗芯片、能不能留出空间给应用逻辑。这一部分的数据我认为比速度表重要得多。4.1 最小系统的 Flash 占用对照我统计的是最小可运行系统1 个启动任务 1 个空闲任务 1 个信号量 串口驱动不含打印格式化用arm-none-eabi-size读取.text .data减去不用 RTOS 时的裸机基线差值就是 RTOS 的净占用。RTOS净 Flash 占用说明RT-Thread Nano约 5KB裁剪后极小适合小容量芯片TencentOS-tiny约 5KB与 Nano 相当FreeRTOS约 6KB经典配置ThreadX约 6KB内核精简但需额外适配层LiteOS-M约 8KB依赖部分基础组件μC/OS-III约 10KB内建功能多Zephyr约 20KB最小配置已包含抽象层RT-Thread 完整版约 35KB含设备框架和中间件基础这张表最能说明什么时候该选谁。如果你手上是 GD32F103C8T6 这种 64KB Flash 的芯片RT-Thread 完整版一上来就吃掉一半以上还要留空间给应用和可能的 bootloader基本就没什么余量了换成 Nano 或者 TencentOS-tiny你还有 50KB 以上可以折腾。4.2 每个任务、每个信号量的 RAM 开销RAM 比 Flash 更紧张因为 Flash 不够还能砍功能RAM 不够程序直接跑不起来。我测了每增加一个任务和每增加一个信号量的 RAM 增量。RTOS每任务控制块开销每信号量开销备注FreeRTOS约 100 字节约 80 字节结构紧凑RT-Thread Nano约 110 字节约 90 字节带对象管理头TencentOS-tiny约 100 字节约 80 字节精简ThreadX约 120 字节约 90 字节内建统计字段LiteOS-M约 130 字节约 100 字节结构较丰富μC/OS-III约 180 字节约 110 字节控制块字段最多Zephyr约 200 字节约 120 字节抽象层较重RT-Thread 完整版约 180 字节约 120 字节带设备与统计这些数字看起来都不大但乘以实际数量就很可观。假设你有 12 个任务和 15 个同步对象μC/OS-III 相比 FreeRTOS 大约多占 1KB RAM在 20KB RAM 的芯片上这就是 5% 的差距够不够用往往就在这点上。4.3 在 GD32F103 上的交叉验证为了确认上面的结论不是 STM32F407 特有的我在 GD32F103C8T672MHz64KB Flash20KB RAM上重跑了资源占用测试。结论基本一致但有两点值得单独说。第一主频降到 72MHz 之后速度差距的相对比例变化不大但绝对时间全部翻倍。比如 ThreadX 在 F407 上 0.92 微秒切换到 F103 上变成 2.1 微秒左右。这提醒我们所有 RTOS 速度数据必须绑定主频一起看。第二也是更重要的在 20KB RAM 的芯片上RT-Thread 完整版和 Zephyr 基本没有实用空间跑起来之后留给应用的动态内存非常少。我实测 RT-Thread 完整版在 F103 上跑完基础系统后动态堆只剩几 KB随便开两个缓冲区就告急。所以小容量芯片的现实选择就是 Nano 级别的轻量内核全功能框架在资源受限场景下是奢侈品。提示测 RAM 占用时一定要把链接脚本里的堆栈和堆算进去。我见过有人只统计了内核对象忘了把每个任务的栈和系统栈加上最后实际占用比预期高一倍项目后期才发现 RAM 不够。5. 同步原语与中断路径信号量、队列、消息邮箱的真实成本任务切换只是 RTOS 的一个面。真实项目里跑得最频繁的其实是同步原语操作——信号量的 give/take、队列的收发、事件标志的等待。这些操作的耗时往往决定了系统的响应能力上限。这一部分我测了三类最常用的对象。5.1 信号量 take/give 的耗时对比测法一个任务在循环里对信号量执行 take另一个高优先级任务在收到通知后立即 give用 DWT 测单次 give 唤醒路径的总耗时从 give 调用开始到被唤醒任务开始执行。RTOS信号量 give→唤醒无等待 take备注ThreadX1.300.28路径短FreeRTOS1.480.32队列实现通用TencentOS-tiny1.620.35精简RT-Thread Nano1.700.36对象管理稍重LiteOS-M1.850.42判定逻辑多RT-Thread 完整版2.050.48带钩子Zephyr2.200.52抽象层开销μC/OS-III2.350.55统计与钩子这里的差距比上下文切换更明显一些最慢比最快多了大约 1 微秒。为什么同步操作差距更大因为它牵扯到就绪链表插入、优先级判定、可能的立即切换。在中断里做信号量 give 的场景下这个差距会被放大因为中断上下文本身还有额外开销。5.2 中断响应延迟的关键变量中断响应延迟是嵌入式系统的命门尤其是做电机控制、电源管理这类对时序敏感的应用。RTOS 对中断延迟的影响主要体现在它关中断的临界区有多长。我测的是从 GPIO 外部中断触发到用户中断服务函数第一条指令执行的耗时。在这个指标上8 款系统的差距不算大因为 Cortex-M 的硬件中断向量机制本身很快真正的差异来自内核关中断的窗口。RTOS内核最长关中断窗口外部中断到 ISR 入口ThreadX约 1.1 微秒约 0.95 微秒FreeRTOS约 1.3 微秒约 1.05 微秒TencentOS-tiny约 1.4 微秒约 1.10 微秒LiteOS-M约 1.6 微秒约 1.20 微秒RT-Thread Nano约 1.5 微秒约 1.15 微秒RT-Thread 完整版约 2.0 微秒约 1.45 微秒Zephyr约 2.2 微秒约 1.60 微秒μC/OS-III约 2.5 微秒约 1.80 微秒需要强调的是这些是内核自身造成的延迟不包括你的应用里自己关了中断的部分。实际项目中导致响应超标的原因八成是应用代码里那段长达几十微秒的全局关中断而不是 RTOS 内核。所以测中断延迟时一定要先确认自己应用层没有长时间关中断。5.3 队列与消息传递的吞吐差异队列在数据采集和通信处理里用得极多。我测的是生产者-消费者模式下一个任务往队列里放 32 字节数据、另一个任务取出并处理测每秒能完成多少次完整往返。RTOS队列往返吞吐次/秒备注ThreadX约 410K拷贝路径优化好FreeRTOS约 380K值拷贝通用TencentOS-tiny约 350K精简实现RT-Thread Nano约 330K对象机制稍重LiteOS-M约 310K判定较多RT-Thread 完整版约 280K带钩子检查μC/OS-III约 260K统计开销Zephyr约 250K抽象层**这里有个实用结论队列的单次拷贝语义会让大块数据传递变慢。如果你要传几百字节的数据用队列拷贝还不如传指针。我实测传 8 字节和传 128 字节耗时能差 4 到 5 倍。所以很多项目会用队列存指针 内存池管理的模式这个模式在 8 款系统上都能实现只是内存池组件的成熟度有差别。6. 结果为什么会骗人那些让排名翻车的测量陷阱前面给了那么多数据如果只是到这里结束那这篇内容也就和网上那些评测差不多了。真正让我觉得这次实验有价值的是下面这些坑——它们中任何一个没处理干净上面的表格就可能完全换个样子。6.1 测量点位置造成的假象最开始我图省事把 DWT 读数和 GPIO 翻转放在任务函数的入口和出口。结果测出来的切换时间里混进了任务函数本身的代码开销。比如 A 任务里有几行数据处理B 任务里有几次循环判断测出来 A 和 B 的耗时不一样我一度以为 RTOS 的切换耗时和任务代码有关。后来把测量点收窄到taskYIELD前后、并且保证中间没有任何其他代码数据才稳定下来。这个坑的教训是测量点要尽可能贴近你要测的那段代码中间不能夹带任何可变量。DWT 计数器读一次本身就是几条指令放在错误的位置会把这点开销放大成主要误差。6.2 编译器优化等级与内联的影响我用-O0复测了一遍结果所有系统的切换耗时都涨了两到三倍而且相对顺序也变了——某些代码写得规整的 RTOS 在-O0下退化得更厉害。这说明发布性能数据时不写优化等级是非常不负责任的。另一个更隐蔽的问题编译器可能会把测量用的空循环优化掉。我在第一版测量代码里写了个for(i0;i100;i);做延时结果-O2直接把它删了测出的时间短得离谱。加volatile或者内联汇编屏障才解决。任何和计时相关的代码都要防着编译器把手伸进。6.3 中断优先级和临界区屏蔽RTOS 通常要求把PendSV和SysTick设成最低优先级把SVC设为次低。但如果移植时没配好某些系统会用默认优先级导致它们的中断处理顺序和别的系统不一样。我有一轮测试里某款系统的数据一直偏高回查才发现它的 PendSV 优先级配成了和外部中断同级切换时被外部中断频繁打断数据自然难看。注意移植任何 RTOS 后第一件事就是检查NVIC优先级分组和 PendSV/SysTick 的优先级设置。这个配置错了你测的所有延迟数据都没意义。6.4 Flash 等待周期与指令预取STM32F407 在 168MHz 下需要 5 个 Flash 等待周期同时开着指令和数据缓存以及预取。如果某款 RTOS 的调度代码恰好落在缓存不友好的位置就会表现出偶发的长延迟。我测 μC/OS-III 时见过一个奇怪现象切换耗时大部分时候 1.5 微秒偶尔飙到 3 微秒以上。查了半天发现是它的调度路径较长跨越了缓存边界预取命中率下降。解决办法有两个一是把关键调度代码放到零等待的 CCM RAMF4 上有 64KB 的 CCM二是把 Flash 等待周期和缓存配置在所有系统上统一。我两种都做了数据波动才收敛到可接受范围。这个坑很值得记住因为它是真实系统里也会发生的那类问题。6.5 测量的可重复性问题最后一个坑是统计方法。我一开始只测一次结果某款系统运气好测出个漂亮数字第二天重测又变差误以为它不稳定。后来改成每项测 1000 次取中位数同时丢掉前后各 5% 的极端值数据才可信。还有一种情况第一次烧写后系统还没稳定前几次切换会偏慢。所以我的测量代码里有一段预热循环先跑 1000 次切换丢弃结果再开始正式记录。这个细节很小但少了它数据表里就会出现莫名其妙的异常值。7. 从测试数据到选型决策不同场景到底该选谁数据摆完了回到最实际的问题你手头的项目该选哪个。我的建议是按场景分而不是按排名选。7.1 小资源 MCUGD32F103、F030 这一档如果你的芯片是 64KB 以内 Flash、20KB 以内 RAM直接排除 RT-Thread 完整版、Zephyr 这类框架型系统。首选是FreeRTOS、RT-Thread Nano、TencentOS-tiny这三者里的任意一个它们都能把你从裸机状态快速带进多任务模式占用也压得住。真要选看你的团队熟悉哪个FreeRTOS 资料最多Nano 的中文文档和社区支持最好TencentOS-tiny 的接口设计比较现代。在这个档位速度不是考虑因素能不能在一个下午跑通才是。我自己会优先选 FreeRTOS因为出问题时能搜到的答案最多。7.2 中高端 MCUF4、H7 这一档资源宽裕了选择就多起来。ThreadX 在纯性能上是领头羊而且它现在有相当宽松的授权方式如果你的项目对实时性和确定性要求极高比如高速闭环控制、工业总线从站它很值得试。FreeRTOS 依然是通用场景的稳妥选择生态和中间件支持最全。μC/OS-III 在这个档位适合对功能完整性要求高的项目它的内建任务统计、时间统计、内存管理都比别的系统开箱即用代价就是多一点性能税和 RAM。如果你的项目看重这些特性多花的那点开销完全可以接受。7.3 需要完整生态和中间件的项目当项目里出现文件系统、网络协议、图形界面、OTA 升级这些需求时RTOS 的选择逻辑就变了——你选的不再是内核而是一整套生态。这个场景下RT-Thread 完整版和 Zephyr 有明显优势它们自带或者容易集成大量中间件能省掉大量对接工作。代价就是前面测出来的那些更大的 Flash、更多的 RAM、更长的移植学习时间。所以这个选择的真正问题是你愿不愿意用资源换开发效率。我的经验是如果项目周期紧、功能杂、团队人手有限用完整框架省下的时间是实打实的如果项目极度在意成本和确定性就老老实实回到轻量内核加自研组件。7.4 面试里常问的 RTOS 问题与实测数据的对应最后聊几句面试。RTOS 相关的技术问题很多人背答案背得很熟但一问细节就露馅。比如上下文切换要保存哪些寄存器标准答案是R4-R11 等被调用者保存寄存器由软件保存R0-R3、R12、LR、PC、xPSR 由硬件压栈。如果你补一句我在 Cortex-M4 上实测切换耗时大约 1 微秒左右加上保存浮点上下文会明显增加面试官对你的印象会立刻不一样。再比如信号量和互斥量的区别除了答优先级继承你还可以说实测 give 唤醒路径大概 1.3 到 2 微秒比单纯的任务切换略长因为它多了就绪链表操作。这类基于实测的回答比背书有说服力得多。我还常被问到tickless 有什么好处。标准回答是省电但如果你能补充开 tickless 后测量延迟的方式要变不能再按 tick 周期估算了否则会误判成毫秒级延迟这种细节就是真实经验。8. 一些没法写进表格的个人体会跑完这一整套测试我最大的收获不是记住了哪个系统快 0.1 微秒而是建立了一套判断数据可不可信的方法。以后再看到任何 RTOS 评测我会先看它的测量条件写清楚没有——MCU 型号、主频、优化等级、测量手段、任务配置这些缺一个结论就要打个问号。还有一个挺反直觉的感受8 款系统里我最后真正会推荐给别人的其实只有三四款不是因为其他几款差而是因为选型的门槛从来不在性能上而在出问题时有没有人帮你。文档质量、社区活跃度、有没有现成的中间件、公司里有没有人用过这些因素对项目成败的影响远大于那零点几微秒的差距。如果你动手复现这套测试我建议至少做两件事一是把自己的应用代码丢进去跑一遍因为空任务测出的数据和真实负载下的表现差别很大二是在你实际要用的那颗芯片上跑一次不要拿 F407 的数据去指导 F103 的决策。我见过太多人拿着别人的评测数据选型最后在项目中期发现内存不够或者生态缺失返工成本比一开始认真评估高得多。最后分享一个我自己用的小习惯每次给新项目选 RTOS我会花一小时做一份评估表把 Flash 占用、RAM 占用、移植耗时、中间件需求、团队熟悉度这五项各打一个分加起来再决定。分数最高的往往不是性能最好的那个但它通常是最不容易在三个月后让你加班的那个。
返回列表