PCIe端点BAR映射异常:memcpy段错误与数据传输性能问询
问题
我将PCIe端点设备连接至主机,把它的512MB BAR做mmap后用memcpy传输数据,耗时约2.5s;但仅映射BAR的100字节却执行512MB memcpy时,0.5s内就触发了段错误。之前误以为段错误后BAR末端数据和完整映射时一致,实际并非如此。想问为什么会出现这种数据写入情况,且速度远快于正常方式?
完整映射BAR的代码(耗时2.5s)
fd = open(filename, O_RDWR | O_SYNC) map_base = mmap(NULL, 536870912, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); int rand_fd = open(infile, O_RDONLY); rand_base = mmap(0, 536870912, PROT_READ, MAP_SHARED, rand_fd, 0); memcpy(map_base, rand_base, 536870912); if(munmap(map_base, map_size) == -1) { PRINT_ERROR; } close(fd);
仅映射100字节的代码(耗时0.5s)
fd = open(filename, O_RDWR | O_SYNC) map_base = mmap(NULL, 100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); int rand_fd = open(infile, O_RDONLY); rand_base = mmap(0, 536870912, PROT_READ, MAP_SHARED, rand_fd, 0); memcpy(map_base, rand_base, 536870912); if(munmap(map_base, map_size) == -1) { PRINT_ERROR; } close(fd);
补充说明:我使用pcimem工具校验写入数据。
分析与解答
1. 数据写入与段错误的本质
当仅映射BAR的100字节时,memcpy会从map_base开始尝试连续写入512MB数据,这完全超出了内核分配的虚拟内存映射范围:
- 映射范围内的100字节会正常写入PCIe设备的BAR空间。
- 超出映射范围的地址访问会触发内核页错误,由于这些虚拟地址未绑定到PCIe BAR的物理地址,内核无法完成映射,最终抛出SIGSEGV信号终止进程。
- 之前误以为末端数据正确是误判,超出映射范围的写入根本没有成功提交到PCIe设备,页错误会直接中断写入流程,未完成的操作不会生效。
2. 速度差异的核心原因
两种场景的耗时差距,本质是实际完成的写入量不同:
- 完整映射时,
memcpy需要把512MB数据全部通过PCIe总线写入设备,受限于PCIe链路的实际有效带宽(比如x1链路有效带宽通常低于8Gbps),再加上O_SYNC标志强制每笔写入同步到设备,所以耗时长达2.5s。 - 部分映射时,
memcpy在触发段错误前仅完成了少量数据写入(通常是几个内存页的大小,远小于512MB),内核触发页错误并终止进程的速度很快,因此总耗时仅0.5s左右。
内容的提问来源于stack exchange,提问作者userYou
相关产品推荐
相关产品推荐

