起因

调度篇把话说出去了:硬实时层的确定性来自中断优先级和 ISR 的有界执行。话说出去要拿数据兑——客户验收、产线抽检、自己晚上睡得着,靠的都是一份测出来的延迟分布,不是"应该没问题"。测量这行的老家伙是示波器和逻辑分析仪——中断响应多少微秒,示波器一触发一目了然,就是费机器费人;软件自打点(TSC 加直方图)是嵌入式圈的长期实践,便宜、能长期挂着跑,代价是要自己证明打点本身不扰动系统。“平均值会说谎"这句话,服务器圈是 Google 2013 年那篇尾延迟论文点破的,工控圈不用论文点——废一个件就懂了。基础篇最后这篇就干这一件事:把"实时"两个字变成一页纸的数字。

一、测什么

四个指标,各有各的意义:

指标 定义 说明
中断响应延迟 事件发生 → ISR 第一条指令 APIC 投递 + IST 切换的底噪
ISR 执行时间 ISR 进入 → EOI 决定周期上限
周期抖动 相邻两次触发间隔的分布 插补/放电节拍的稳定性,核心指标
端到端延迟 命令下发 → FPGA 回执 操作工视角的真实延迟

平均值在这里没有意义:一万次 2µs 加一次 2ms,平均数很好看,机床废一件。要看的是最大值、99.99% 分位和直方图的形状。

二、怎么测:软件打点,硬件对账

软件侧用 TSC 打点(invariant TSC,APIC 篇验过的)。打点位置有讲究:在汇编 stub 第一条指令处 rdtsc 才是真正的响应延迟,进了 Rust 分发函数再打,量到的是"很接近但不完整”。_rdtsc() 就一条指令的开销,ISR 里放心用。

1
2
3
4
5
// ISR 入口/出口各打一点
let t_in = unsafe { _rdtsc() };
... 原有逻辑 ...
let t_out = unsafe { _rdtsc() };
hist.record(t_out - t_in);

直方图用对数桶(1µs 一档到 100µs,尾部合并),每个向量一组 [u32; 64] + max + count + sum,几十 KB 常驻内存。

软件自测有个天花板:SMI 发生的那几十微秒软件完全看不见,只会在直方图上留一个"莫名的大延迟"。所以必须有硬件对账:

  • FPGA 卡用自己的时钟给每条运动指令盖时间戳,回执里带回来——软件时间线和硬件时间线对齐比对,差异超阈值就是平台级干扰
  • 示波器/逻辑分析仪挂 FPGA 脉冲输出口,量实际脉冲间隔分布——这是第三方裁判,客户验收就用这个

三、测出问题查这里

干扰源就这几类,逐项排查:

干扰源 症状 对策
SMI 解释不了的偶发大延迟 BIOS 关 legacy USB / 周期 SMI,改前改后各测一轮对比
C-state 进出 延迟底噪整体抬升 固定频率、限制 C-state(平台管理篇的电源策略)
温度降频 长时间烤机后延迟缓涨 盯 IA32_THERM_STATUS 的 log 位,散热整改
双核 cache/总线争用 Core1 满载时 Core0 抖动变大 双核固定分工本身就是对策(多核篇),烤机必须带 Core1 满载场景
隐性分配 周期性尖刺 这系统没有 GC,要防的是 ISR 里的隐蔽 alloc(内存篇归属表违规)
设备 DMA 小幅底噪 DMA 池集中 + 批量传输,避免高频小包

四、烤机准则

时长 72h 起步(覆盖周末无人值守场景),验收前跑 168h。负载不是空转:满速插补 + 图形满刷新 + U 盘拷文件 + 网络满流量 + 风扇全速,同时来。判定三条:

  • 周期抖动 max 不超阈值(例:100µs 插补周期 max 抖动 ≤ 10µs;具体数值是机型工艺参数,做成参数表可调项)
  • 0 丢拍:ISR 计数和 HPET 推算计数比对
  • 直方图单峰。出现双峰说明存在一条系统性的干扰路径,哪怕 max 达标也要查——双峰是"还有一类没归因的事件"的信号

产出是一页纸报告:指标表 + 直方图 + 硬件对账差异,归档进日志系统,这台机器的"体检报告"就年年可比了。

五、跟 cyclictest 比一下

Linux 圈用 cyclictest 验实时性,因为它有调度器要对抗。这套系统没有调度器干扰——ISR 优先级即真相。所以测量更简单也更严格:简单在不需要高精度定时器线程那套搭建,严格在没有"调度抖动"可以归因,一切尖刺都是平台或自己代码的问题,没地方藏。

总结

实战清单:四指标定义表;stub 级 TSC 打点;对数桶直方图;FPGA 时间戳对账 + 示波器第三方裁判;干扰源六项排查表;72h 满负载烤机 + 单峰判定;一页纸报告归档。跑通标志:72h 烤机插补周期 max 抖动 ≤ 阈值且直方图单峰;0 丢拍;软件时间线与 FPGA 时间线差异 < 设定阈值;关 SMI 前后的对比数据入库。

基础篇到这里收官——25 篇,从 UEFI 接手一路写到实时性验证。接下来两条线:把文章变成真代码(QEMU 里先跑通 UEFI→串口→画像素这条链,文章和代码互相验证着推进);应用篇从运动控制卡驱动开始(等硬件手册到位)。MES 对接和视觉定位的接口篇,也在应用篇的队列里。

参考链接