我一直在寻找一种方法来分配硬件可以写入的DMA缓冲区,但是可以缓存以便从CPU读取。我开始使用Linux命令行选项mem = 896为DMA缓冲区保留最后128 MB的RAM(是的,这是过多的)。然后在我写的驱动程序中,我执行以下操作:
void *srcBuf = NULL;
void *dstBuf = NULL;
dma_declare_coherent_memory(&gDev, BUFFER_ADDR, BUFFER_ADDR, 128*1024*1024, DMA_MEMORY_MAP);
srcBuf = dma_alloc_coherent(&gDev, 10*1024*1024, &dmaSrcAddr, GFP_DMA);
dstBuf = dma_alloc_coherent(&gDev, 10*1024*1024, &dmaDstAddr, GFP_DMA);
这在BUFFER_ADDR(物理RAM的末尾)正确分配128 MB,然后从该区域获得两个10 MB缓冲区。然后我做了一些简单的memset,memcpy代码来测试带宽:
start = ktime_get();
memset(srcBuf, 0x55, BUFFER_SIZE);
stop = ktime_get();
printPerformance(start.tv64, stop.tv64, "Write performance to memory");
start = ktime_get();
memcpy(dstBuf, srcBuf, BUFFER_SIZE);
stop = ktime_get();
printPerformance(start.tv64, stop.tv64, "Copy performance from src to dst");
这为memset产生了可怕的919 MB /秒,对于memcpy产生了125 MB /秒。这种设计对于Zedboard很简单,我有两个16位533 MHz DDR3L部件。我应该有(533 * 2 * 4)4264 MB /秒的带宽。
然后我从用户空间做同样的事情,但使用posix_memalign。这为memset提供了2461 MB /秒,对memcpy提供了298 MB /秒。更好,但仍然很糟糕。
最后我写了一个裸机应用来做同样的事情。虽然我没有分配内存,但我没有运行MMU,所以我只选了两个地址并执行了memset / memcpy测试。我还启用了裸机测试,启用了L1和L2缓存,启用了L1缓存,但L @禁用,并且两个缓存都被禁用。这导致以下结果: 两者都启用了 memset - 5296 MB /秒 memcpy - 637 MB /秒 L2禁用 memset - 1426 MB /秒 memcpy - 834 MB /秒 都是残疾人 memset - 426 MB /秒 memcpy - 276 MB /秒
用户空间代码的性能与禁用的两个缓存相同。内核代码的性能只有一半。有人有什么想法吗?
以下是我一直在关注的一些信息: https://lwn.net/Articles/440221/ https://aelseb.wordpress.com/2015/04/11/contiguous-memory-on-arm-and-cache-coherency/ https://lkml.org/lkml/2015/5/20/715 http://lists.infradead.org/pipermail/linux-arm-kernel/2013-September/197780.html