1. 为什么多核DSP需要关注CACHE一致性我第一次用TMS320C6678开发多核应用时遇到过这样一个诡异现象核0明明已经修改了共享内存中的数据但核1读取时却还是旧值。折腾了一整天最后发现问题出在CACHE一致性上。这就像办公室里几个人共用一份文件A同事修改了文件但没通知其他人B同事还在看旧版本工作自然就乱套了。在TMS320C6678这样的多核DSP中每个核都有自己的L1和L2缓存。当核0从DDR读取数据时会先在L2缓存中保存副本再加载到L1D缓存。后续操作都直接在缓存中进行不会立即同步到DDR。这就导致了其他核读取DDR时可能拿到过期数据。我实测过一个案例核0将变量从11改为56后核1在10万次读取中仍有约3%概率读到旧值11。更麻烦的是缓存层级带来的复杂性。6678的缓存结构包括L1D Cache32KB直接映射L1P Cache32KB直接映射L2 Cache512KB4路组相联MSM4MB可配置为缓存2. CACHE一致性操作的三大法宝2.1 Invalidate操作强制刷新缓存Invalidate就像给缓存数据贴作废标签。执行后CPU再次访问该数据时会重新从DDR加载。我在图像处理项目中就遇到过这种情况核0处理完一帧图像后需要核1接着处理。如果不做Invalidate核1可能继续使用缓存中的上一帧数据。具体操作示例// 无效化指定地址范围的L1D缓存 Cache_invL1d((void*)shared_addr, data_size, Cache_Type_ALL, TRUE); // 无效化整个L2缓存 Cache_invL2((void*)0, Cache_Size_512KB, Cache_Type_ALL, TRUE);但要注意两个坑Invalidate不会将数据写回DDR如果数据被修改过会丢失对Prefetch Buffer无效后面会详细讲2.2 Writeback操作确保数据持久化Writeback是把缓存中的脏数据写回DDR。在核间通信时我习惯在数据准备好后立即Writeback。比如核0计算完矩阵乘法结果后// 写回L1D缓存数据 Cache_wbL1d((void*)result_addr, matrix_size, Cache_Type_ALL, TRUE); // 写回L2缓存数据 Cache_wbL2((void*)result_addr, matrix_size, Cache_Type_ALL, TRUE);实测发现不执行Writeback时核1读取错误率高达12%执行后降为0%。但Writeback后缓存数据仍然有效CPU会继续使用缓存副本。2.3 Writeback-Invalidate二合一操作这个组合操作是我的最爱它先Writeback再Invalidate既保证数据持久化又强制刷新。在信号处理流水线中我这样使用// 核0完成数据处理后 Cache_wbInvL1d((void*)pipeline_buf, BUF_SIZE, Cache_Type_ALL, TRUE); Cache_wbInvL2((void*)pipeline_buf, BUF_SIZE, Cache_Type_ALL, TRUE); // 核1开始处理前 Cache_invL1d((void*)pipeline_buf, BUF_SIZE, Cache_Type_ALL, TRUE);3. 那些年我踩过的Prefetch坑6678的预取功能本意是提高性能但却给我带来过严重bug。DSP在读取数据时会额外预取128字节而Invalidate操作对这部分数据无效。有次做音频处理时核0更新了音频块核1却总读到混音数据最后发现是预取导致的。解决方案有两种在共享数据前后留128字节空隙操作XPFCMD寄存器// 无效化预取缓冲区 CSL_XMC_invalidatePrefetchBuffer(hXmc);我建议两种方法结合使用。在视频编解码项目中我给每个视频帧缓冲区前后都保留了128字节保护带再配合寄存器操作彻底解决了这个问题。4. CACHE操作的安全姿势官方文档中有几个关键警告Advisory必须注意操作缓存时要关中断Uint32 int_flag Hwi_disable(); // 执行缓存操作 for(int i0; i16; i) asm( NOP); // 16个NOP Hwi_restore(int_flag);内存屏障要双写asm( MFENCE); asm( MFENCE); // 必须写两次我曾在实时控制系统里忽略这点导致每百万次操作就会出现1-2次数据不同步。加入双MFENCE后问题消失。5. MAR寄存器的妙用Memory Attribute RegisterMAR是解决一致性问题的终极武器。6678有256个MAR寄存器每个控制16MB地址空间。通过禁用特定地址空间的缓存可以彻底避免一致性问题。我在网络报文处理中这样配置// 禁用报文缓冲区的缓存 Uint32 mar_num CACHE_getMARFromAddr(pkt_buf); CACHE_disableCaching(mar_num);实测发现对频繁核间交换的小数据如控制标志禁用缓存后虽然访问延迟增加约15%但彻底杜绝了一致性问题。建议对关键共享数据使用MAR其他数据仍用缓存手动维护。6. 实战优化策略经过多个项目积累我总结出一套优化方案数据分类管理频繁核间共享数据禁用缓存或使用Writeback-Invalidate核内私有数据充分利用缓存只读共享数据启用缓存单次Invalidate批量操作原则// 不好的做法频繁小数据量操作 for(int i0; i100; i) { Cache_wbInvL1d(data[i], sizeof(int), ...); } // 好的做法批量操作 Cache_wbInvL1d(data, 100*sizeof(int), ...);批量操作能减少开销实测处理1MB数据时批量操作比循环快37倍。延迟更新技巧 在视频处理流水线中我让每个核维护自己的缓存副本只在关键同步点做一致性操作。这样将操作次数从每帧100次降到2-3次吞吐量提升5倍。