# 05-实时性与系统优化 > 资料源: [`Demo/linux-rt-demos/`](../TL3568-EVM(Buildroot-2018.02)_V1.8/Demo/linux-rt-demos/) + [`3-用户手册/2-3-Linux-RT系统测试手册.pdf`](../TL3568-EVM(Buildroot-2018.02)_V1.8/3-%E7%94%A8%E6%88%B7%E6%89%8B%E5%86%8C/2-3-Linux-RT%E7%B3%BB%E7%BB%9F%E6%B5%8B%E8%AF%95%E6%89%8B%E5%86%8C.pdf) --- ## 一、为什么嵌入式开发需要关注实时性? 你的 CAN 协议栈对实时性的需求: | 场景 | 延迟要求 | 不达标后果 | |------|:---:|------| | CAN 帧收发中断响应 | < 100μs | 丢帧、总线错误 | | 急停/安全帧 | < 1ms | 安全隐患 | | 100Hz 周期发布 | < 10ms jitter | 数据抖动 | | 文件传输 ACK 超时 | < 500ms | 重传风暴 | 标准 Linux 的 `sleep(10)` 实际可能睡 12-15ms——**调度器不保证实时性**。 --- ## 二、Linux 实时化方案 ### 2.1 Preempt-RT 补丁 ``` 标准 Linux: CONFIG_PREEMPT=n → 内核态不可抢占 低延迟 Linux: CONFIG_PREEMPT=voluntary → 检查点可抢占 实时 Linux: CONFIG_PREEMPT_RT=y → 几乎全部内核态可抢占 ``` **创龙已提供**:RT 版本的内核镜像在 [`Linux/Kernel/image/`](../TL3568-EVM(Buildroot-2018.02)_V1.8/Linux/Kernel/image/) 下。 ### 2.2 验证工具:Cyclictest ``` 路径: [`Demo/linux-rt-demos/Cyclictest/`](../TL3568-EVM(Buildroot-2018.02)_V1.8/Demo/linux-rt-demos/Cyclictest/) # 测试调度延迟 cyclictest -t 4 -p 99 -i 1000 -l 100000 -h 200 -q # 4线程 RT99 1ms周期 10万次 直方图 # 预期结果: # 标准内核: max latency 200+ μs (偶发) # RT内核: max latency < 20 μs (稳定) ``` **关键指标**: - **Average latency** → 平均延迟,< 5μs 正常 - **Max latency** → 最大抖动,RT 内核 < 20μs - **直方图** → 看分布,有没有长尾 ### 2.3 RT Demo 代码 | Demo | 路径 | 内容 | |------|------|------| | Cyclictest | [`linux-rt-demos/Cyclictest/`](../TL3568-EVM(Buildroot-2018.02)_V1.8/Demo/linux-rt-demos/Cyclictest/) | 延迟基准测试 | | rt_gpio_ctrl | [`linux-rt-demos/rt_gpio_ctrl/`](../TL3568-EVM(Buildroot-2018.02)_V1.8/Demo/linux-rt-demos/rt_gpio_ctrl/) | `SCHED_FIFO` 线程控制 GPIO | | rt_input | [`linux-rt-demos/rt_input/`](../TL3568-EVM(Buildroot-2018.02)_V1.8/Demo/linux-rt-demos/rt_input/) | 实时采集输入信号 | | rt_spi_rw | [`linux-rt-demos/rt_spi_rw/`](../TL3568-EVM(Buildroot-2018.02)_V1.8/Demo/linux-rt-demos/rt_spi_rw/) | 实时 SPI 通信 | --- ## 三、CAN 协议栈的实时化策略 ### 3.1 线程优先级 ```c // 接收线程 → 最高实时优先级 struct sched_param param = { .sched_priority = 80 }; pthread_setschedparam(rx_thread, SCHED_FIFO, ¶m); // 发送线程 → 次高 param.sched_priority = 70; pthread_setschedparam(tx_thread, SCHED_FIFO, ¶m); // 协议处理线程 → 普通实时 param.sched_priority = 60; pthread_setschedparam(proc_thread, SCHED_FIFO, ¶m); ``` **优先级原则**: ``` 收 (80) > 发 (70) > 协议处理 (60) > 日志/MQTT (普通) ↑ 丢了就再收不到 ↑ 可以定时补发 ↑ 可推迟 ``` ### 3.2 CPU 绑核 把 CAN 协议栈绑到独立 Core,避免和其他系统任务(网络中断、调度器)竞争: ```c cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(3, &cpuset); // 绑定到 Core 3 pthread_setaffinity_np(rx_thread, sizeof(cpuset), &cpuset); ``` 配合内核参数隔离 Core 3: ```bash # 内核启动参数中加: isolcpus=3 cat /proc/cmdline # 确认生效 ``` ### 3.3 内存锁定(防 Swap) ```c mlockall(MCL_CURRENT | MCL_FUTURE); // 锁所有内存页,禁止 swap ``` CAN 收发循环中的内存如果被换出到存储,延迟可能飙到 10ms+。 --- ## 四、PTP 时钟同步 ``` 手册: [`3-用户手册/2-17-基于PTP的时钟同步测试手册.pdf`](../TL3568-EVM(Buildroot-2018.02)_V1.8/3-%E7%94%A8%E6%88%B7%E6%89%8B%E5%86%8C/2-17-%E5%9F%BA%E4%BA%8EPTP%E7%9A%84%E6%97%B6%E9%92%9F%E5%90%8C%E6%AD%A5%E6%B5%8B%E8%AF%95%E6%89%8B%E5%86%8C.pdf) ``` 如果多个 RK3568 节点需要微秒级时间戳对齐 CAN 报文(比如事故分析),需要 PTP (IEEE 1588): ```bash # RK3568 GMAC 支持硬件时间戳 ethtool -T eth0 # 确认支持 # 启动 ptp4l ptp4l -i eth0 -m # 自动选主从,同步时钟 ``` --- ## 五、性能调优工具 | 工具 | 用途 | 命令示例 | |------|------|------| | `perf` | CPU 热点分析 | `perf top -p ` | | `strace` | 系统调用跟踪 | `strace -c -p ` | | `ftrace` | 内核函数跟踪 | `echo function > /sys/kernel/debug/tracing/current_tracer` | | `/proc/interrupts` | 中断统计 | `watch -n1 cat /proc/interrupts \| grep can` | --- ## 六、学习建议 CAP CAN 协议栈时按这个顺序做实时优化: ``` 1. 先跑通功能(标准内核 + 普通线程) ← 保证逻辑正确 2. 用 cyclictest 测基线延迟 ← 了解系统"抖动底限" 3. 给收发线程加 SCHED_FIFO ← 最直接的提升 4. 绑核 (CPU affinity) ← 避免和网络中断竞争 5. mlockall 锁内存 ← 消灭不可控延迟源 6. 压测中 perf top 分析热点 ← 只优化真正慢的地方 7. 如有余力,切 Preempt-RT 内核 ← 把最坏延迟压到 20μs ``` > ⚠️ 不要在第一步就切 RT 内核。RT 内核的优先级反转、锁依赖会让普通的 bug 表现为"整个系统死掉",难以调试。