linux_learn/docs/05-实时性与系统优化.md

158 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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, &param);
// 发送线程 → 次高
param.sched_priority = 70;
pthread_setschedparam(tx_thread, SCHED_FIFO, &param);
// 协议处理线程 → 普通实时
param.sched_priority = 60;
pthread_setschedparam(proc_thread, SCHED_FIFO, &param);
```
**优先级原则**
```
收 (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 表现为"整个系统死掉",难以调试。