用户空间是否有可用的linux DMA mem-to-mem复制机制?
我有一个Linux应用程序,通常(每秒50-100次)必须记忆几个megs(10+)的数据。通常它不是问题,但我们已经开始看到证据表明它可能消耗了太多的CPU带宽。目前的测量结果表明我们正在以1Gbytes / s的速度移动。
我知道内核中的dma功能,我看到一些文档讨论为大内存副本构建自定义驱动程序,原因就在这个原因。但似乎有人会构建一个通用的API为此,现在。我错了吗? DMA是仅内核功能吗?
我应该澄清一下,这是针对英特尔X86架构,而不是嵌入式。
答案 0 :(得分:8)
Linux的DMA API不允许内存到内存传输。它仅用于设备和内存之间的通信。查看Documentation/DMA-API.txt
了解更多详情。
在硬件级别,x86 DMA控制器不允许内存进行内存传输。这里已经讨论过:DMA transfer RAM-to-RAM
鉴于内存总线通常比CPU慢,启动内核驱动的内存副本有什么好处?您仍然需要等待传输完成,其持续时间仍然取决于内存带宽,与CPU驱动的副本完全相同。
如果程序的性能完全取决于内存到内存复制性能,则意味着可以通过尽可能避免复制或通过实现更智能的过程(如写入时复制)来大幅提高性能。 / p>
答案 1 :(得分:2)
听起来你真正想要的是写时复制语义。这意味着默认情况下根本不会创建任何副本,但是如果任何给定的线程需要更改部分数据,那么只有该页面的副本才会在使用时透明。
如果您的数据足够大,以致这些memcpy
来电受到影响,写保留即可为您节省许多费用:
DMA不是解决方案,它主要用于设备主机或设备设备通信,而不是以可用的方式暴露给普通用户空间进程。
相反,您可以使用POSIX共享内存来获取此行为:
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
int main() {
// Once:
int fd = shm_open("/cowalloc", O_RDWR|O_CREAT, 0600);
shm_unlink("/cowalloc");
ftruncate(fd, 1024); // This is the size of the COW regiona
char *master = mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
strcpy(master, "hello world, this is a demonstration of COW behaviour in Linux");
// Per thread:
char *thread = mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_NORESERVE, fd, 0);
// Demo
printf("Master: %s\nThread: %s\n", master, thread);
printf("\nChanging in thread:\n");
strcpy(thread, "This is a private change");
printf("Master: %s\nThread: %s\n", master, thread);
return 0;
}
这里的基本思想是,一旦使用MAP_SHARED,您就可以完成数据的所有全局设置(可能是从磁盘/网络或计算中加载)。然后,您可以使用相同的文件描述符再次调用mmap
,以便为您认为可能需要写入本地副本的每个线程进行其他私有映射。
此处使用MAP_NORESERVE标志是可选的 - 如果您只在每个线程中更改一个页面中的一个页面,那么使用它可能是有意义的,以避免不必要地抓取大量交换。
(请注意,如果您从磁盘加载,只需在文件上使用mmap
即可进一步优化。
当然,在对象级别执行COW行为可能更干净,更便携,例如使用COW智能指针类型。