158 lines
5.3 KiB
Markdown
158 lines
5.3 KiB
Markdown
# 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 <pid>` |
|
||
| `strace` | 系统调用跟踪 | `strace -c -p <pid>` |
|
||
| `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 表现为"整个系统死掉",难以调试。
|