4. 实时性测量方法论

在 Sitara(AM335x/AM57xx 等)目标板上做实时性优化,第一步不是改内核参数,而是建立一套可复现的测量环境。实时性问题往往表现为偶发的毫秒级抖动,如果测量方法本身不稳定,后续所有调优都失去意义。本节围绕六类工具展开:cyclictest 负责统计调度延迟分布,ftrace 负责内核内部时序追踪,perf 负责采样热点与上下文切换,LTTng 负责全系统低开销事件记录,示波器与 GPIO 打点负责把软件时间轴对齐到硬件物理时间轴。

一、测量对象与指标定义

实时性测量的核心指标是调度延迟(scheduling latency),即从事件就绪(如定时器到期、中断触发)到目标线程真正获得 CPU 执行之间的时间。它由三部分构成:中断关闭时间、中断处理与软中断时间、调度器唤醒与抢占延迟。cyclictest 测的是"定时器到期→线程被唤醒执行"的端到端延迟,而 ftrace 的 irqsoff/preemptoff tracer 可以进一步拆解出中断关闭与抢占关闭的最大区间。

测量前必须固定以下条件,否则数据不可比:CPU 隔离(isolcpus 或 cpuset 把测试线程绑到独占核)、CPU 调频策略固定为 performance、关闭无关后台服务、统一内核版本与配置、记录环境温度。建议在启动参数中加入 isolcpus=1 nohz_full=1 rcu_nocbs=1,并用 taskset -c 1 绑定测试进程。

二、cyclictest:延迟分布统计

cyclictest 是 rt-tests 套件中的核心工具,通过高精度定时器循环测量唤醒延迟。典型命令如下:

cyclictest -m -p 80 -t 1 -a 1 -i 1000 -d 0 -D 300 -h 400 -q
# -m 锁定内存  -p 80 优先级  -t 1 单线程  -a 1 绑定CPU1
# -i 1000 周期1000us  -D 300 运行300秒  -h 400 直方图到400us

输出中 Min/Act/Avg/Max 四列最关键,Max 是判断实时性的第一依据。但只看 Max 容易误判:偶发一次 800us 尖峰可能来自一次不可屏蔽中断或 SMI,需要结合直方图看分布形态。若 99.9% 落在 60us 以内、仅个别点超过 200us,说明系统整体可控,问题集中在特定事件;若分布整体右移,则说明基础配置(调频、隔离、内核抢占模型)有问题。建议同时运行 -h 直方图与 -q 静默模式,把结果重定向到文件做多轮对比。

三、ftrace:内核内部时序追踪

当 cyclictest 报出尖峰后,需要定位尖峰发生在内核的哪个阶段。ftrace 通过 function_graph、irqsoff、preemptoff、wakeup_rt 等 tracer 提供函数级时序。常用流程:

cd /sys/kernel/debug/tracing
echo 0 > tracing_on
echo irqsoff > current_tracer
echo 1 > options/function-trace
echo 1 > tracing_on
# 运行负载后
echo 0 > tracing_on
cat trace | head -50

irqsoff tracer 会记录中断被关闭的最长区间及其调用栈,直接指出"谁关中断太久"。wakeup_rt tracer 则记录实时线程从被唤醒到实际运行的延迟,与 cyclictest 的 Max 相互印证。注意 ftrace 本身有开销,长时间开启会改变系统行为,应短时抓取、抓完即关。

四、perf 与 LTTng:采样与全系统事件

perf 适合回答"CPU 时间花在哪里"。用 perf top -e cycles 看热点函数,用 perf sched latency 看各任务的调度延迟统计,用 perf record -e sched:sched_switch -a sleep 10 抓取上下文切换序列。perf 的采样特性决定了它擅长发现统计规律,但不擅长还原单次偶发事件的完整因果链。

LTTng 弥补这一点:它以极低开销记录内核与用户空间事件,通过 babeltrace 或 Trace Compass 还原时间线。典型用法是 lttng create、lttng enable-event -k sched_switch,sched_wakeup,irq_handler_entry、lttng start,运行负载后 stop 并分析。LTTng 的价值在于把中断、软中断、调度、用户态打点放在同一条时间轴上,适合分析"一次抖动前后 1ms 内到底发生了什么"。

五、GPIO 打点与示波器:软硬件时间对齐

纯软件工具无法回答"软件认为的 100us 延迟,在物理世界是否真是 100us"。做法是在关键路径上用 GPIO 翻转打点:在中断入口拉高 GPIO,在线程开始执行时拉低,用示波器测量脉冲宽度,即为物理延迟。Sitara 上可通过 /sys/class/gpio 或直接寄存器操作实现,但用户空间 GPIO 写有几十微秒开销,精确打点应写在内核模块或使用 gpiod_set_value。更严格的做法是用示波器同时抓 PWM 输出与 GPIO 打点,验证定时器精度与调度延迟的叠加效果。

Sitara 实时性测量工具链与信号链 硬件事件源 定时器 / 中断 / PWM GPIO 打点 中断入口↑ 线程执行↓ 示波器 物理时间轴基准 Linux 内核 ftrace irqsoff / preemptoff / wakeup_rt perf 采样热点 / sched latency LTTng sched_switch / irq 事件时间线 事件 用户空间 cyclictest Min/Act/Avg/Max + 直方图 trace 结果判读 Max 尖峰 → ftrace 定位 分布右移 → 基础配置问题 软硬偏差 → 示波器验证 物理延迟验证

六、建立可复现测量环境的检查清单

项目要求验证方式
CPU 隔离isolcpus/nohz_full/rcu_nocbs 绑定独占核cat /proc/cmdline;taskset 确认亲和性
调频策略governor=performance,关闭 C-statecpupower frequency-info
内核配置PREEMPT_RT 或 PREEMPT,开启 ftrace/LTTnguname -a;/sys/kernel/debug/tracing 存在
测试负载cyclictest 固定参数,多轮取统计保存每轮 Max 与直方图
硬件打点GPIO 脉冲宽度与软件延迟对照示波器截图存档
建议每轮测量记录:内核版本、启动参数、cyclictest 参数、环境温度、Max/Avg 值、是否出现尖峰及对应 ftrace 片段。只有条件一致,多轮数据才具备可比性。
ftrace 与 LTTng 长时间开启会引入额外开销并改变调度行为,抓取窗口应控制在秒级;GPIO 用户空间写延迟较大,精确打点需在内核态完成,否则测得的"延迟"包含打点本身的开销。

六类工具并非互相替代,而是分层配合:cyclictest 给出延迟分布与 Max 尖峰,ftrace 定位尖峰发生在内核的哪个临界区,perf 与 LTTng 还原事件因果链与热点,GPIO 打点与示波器把软件时间轴锚定到物理时间轴。只有这四层数据相互印证,才能判断一次抖动是配置问题、驱动问题还是硬件问题,也才能让后续的实时性优化有据可依。