多核Cache False Sharing——变量被莫名篡改的元凶

来源:汽车ECU开发 MCU/MPU 9 次阅读
摘要: 1. 问题背景 开篇老规矩,"小T三问": 你知道什么是Cache False Sharing吗? 你知道False Sharing在多核MCU上不仅仅是性能问题,更会导致变量被莫名篡改吗? 你知道如何在AUTOSAR多核工程中彻底规避这个问题吗? 这篇,我们来一起探索并回答这些问题。 在R5F等双核MCU的AUTOSAR项目中,小T遇到过一个极其诡异的bug:Core

1. 问题背景

开篇老规矩,"小T三问":

  • 你知道什么是Cache False Sharing吗?
  • 你知道False Sharing在多核MCU上不仅仅是性能问题,更会导致变量被莫名篡改吗?
  • 你知道如何在AUTOSAR多核工程中彻底规避这个问题吗?

这篇,我们来一起探索并回答这些问题。

在R5F等双核MCU的AUTOSAR项目中,小T遇到过一个极其诡异的bug:Core0明明没有写Core1的变量,但Core1的变量值却被莫名其妙改掉了。 逻辑查了无数遍,锁也没问题,最终定位到罪魁祸首——Cache False Sharing。

2. 什么是Cache False Sharing?

code

CPU的Cache以Cache Line为最小操作单位(R5F一般为32字节)。当两个核的变量恰好落在同一条Cache Line中时:

  • Core0修改自己的变量 → Core0的Cache Line标记为dirty
  • Core0的Cache Line回写到RAM → 整条32字节全部回写
  • 此时Core1也修改了自己的变量,但还在Cache中未回写
  • Core1的Cache失效后重新从RAM加载 → Core1刚写的值被Core0回写的旧值覆盖!

这不是性能问题,这是数据被篡改!

3. R5F双核实战复现

以TI TDA4/AM263x的R5F双核为例,假设如下代码:

code

故障现象:

  • Core0在10ms任务中递增g_Core0_Counter
  • Core1在5ms任务中更新g_Core1_Status为当前通信状态
  • 实际运行中,Core1发现g_Core1_Status间歇性跳变回旧值
  • 加断点调试反而不复现(因为调试器会刷新Cache)

根本原因: Core0写g_Core0_Counter后Cache Line回写RAM,把Core1还没来得及回写的g_Core1_Status旧值也一并写回,Core1的新值被覆盖。

4. 解决方案

方案一:Cache Line对齐(推荐)

code

方案二:分配到各核私有RAM

在Linker Script中将各核变量隔离到独立内存段:

code

各核使用TCM(紧耦合内存)访问自己的变量,TCM不经过Cache,从根源上消除问题。

方案三:共享变量使用Non-Cacheable区域

对于必须跨核共享的变量,在MPU中将对应内存区域配置为Non-Cacheable:

code

5. 小T心得

  • Cache False Sharing在多核MCU上不只是性能问题,更是数据一致性问题,变量会被莫名篡改,而且极难复现和定位;
  • 凡是多核工程中出现"变量莫名跳变"、"加断点就不复现"的现象,第一时间检查变量的Cache Line对齐情况
  • 养成习惯:多核共享或各核独立的全局变量,定义时就加aligned(32),几个字节的padding换来的是系统稳定性;
  • 能用TCM就用TCM,能配Non-Cacheable就配Non-Cacheable,不要让Cache成为多核协作的隐形杀手

-end-

评论区

登录后即可参与讨论

立即登录