多核通信中的 Memory Cache 问题

19 October 2016

问题场景:

在异构多核通信中,通过共享内存进行数据通信是很常见的一直方式。这块共享内存不被异构的多个核上运行的系统所管理,其效果就类似于一个外部磁盘,所以各个系统都会对其进行 Cache。这就有了多核之间的数据同步问题。

具体到我所遇到的情况。程序运行的平台为 DM8148,程序做的事情是在 A8 和 DSP 之间传输数据。现象是无论 A8 还是 DSP 对共享内存的数据进行了修改,对方都无法看到更新。

代码实现:

A8 从共享内存分配空间:

status = Vsys_allocBuf(SRID, SIZE, ALIGN, &bufInfo);

使用 link control 接口把共享内存的物理地址发送给 DSP(这里我偷懒直接使用 cmd 参数来发送):

UInt32 cmd = bufInfo.physAddr;
System_linkControl(SYSTEM_DSP_LINK_ID_NULL_0, cmd, NULL, 0, TRUE);

DSP 端拿到 cmd(共享内存的物理地址)后就可以对对应存储空间进行读写了。

解决办法:

从现象看,好像 A8 和 DSP 操作的是不同的两块内存。于是一开始是在排查是不是这个问题。但是最终还是否定了。DSP 拿到的物理地址就是 A8 操作的虚拟地址对应的物理地址,是一致的。 后面想到缓存问题。在 DSP 端找到了 Cache_inv((Ptr)addr, 2, Cache_Type_ALL, TRUE); 等接口。试了之后发现没效果。那是因为 A8 端的读写还是只写缓存,共享内存的数据一直没有更新也没有读取。 然后搜索到这个 drop_caches 的方法来更新缓存:

sync; echo 1 > /proc/sys/vm/drop_caches

但是有一个问题是,这个是全局的,会对 A8 上 Linux 的其他程序造成性能方面的影响。 然后找到 msync 这个接口,但是它只针对 mmap 的缓存进行同步。所以干脆就对共享内存进行一次 mmap 后再进行读写。

所以,关键代码是:

A8 端:

buffer->fd = open("/dev/mem", O_RDWR | O_SYNC);
buffer->map_base = mmap(NULL,  addr + size - off_page, PROT_READ | PROT_WRITE, MAP_SHARED, buffer->fd, off_page);
memset((void*)virtAddr, 256, SIZE);
msync(virtAddr, SIZE, MS_SYNC);

DSP 端:

// Invalidate cache before read, because memory was updated by A8.
Cache_inv((Ptr)addr,  2, Cache_Type_ALL, TRUE);
memset((void*)addr, addr[0] + 3, 1);
// Write back cache to memory after updating data.
Cache_wb((Ptr)addr,  2, Cache_Type_ALL, TRUE);

参考资料:

drop_cache 操作 https://linux-mm.org/Drop_Caches

手工释放 Linux 内存 http://www.linuxfly.org/post/320/

TI 论坛 https://www.deyisupport.com/question_answer/dsp_arm/omap_l1x/f/54/t/29457.aspx

多核 Cache http://processors.wiki.ti.com/index.php/Cache_Management

杰良-2016-10-19

上一篇: 广州-英西峰林骑行