在异构多核通信中,通过共享内存进行数据通信是很常见的一直方式。这块共享内存不被异构的多个核上运行的系统所管理,其效果就类似于一个外部磁盘,所以各个系统都会对其进行 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 后再进行读写。
所以,关键代码是:
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);
// 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