cudaMemcpy太慢了

时间:2011-09-15 11:25:20

标签: cuda bus

我使用cudaMemcpy()一次将1GB的数据准确复制到设备上。这需要5.9秒。反过来需要5.1s。这是正常的吗?在复制之前,功能本身是否有这么多开销? 理论上PCIe总线的吞吐量至少应为4GB / s 没有内存传输重叠,因为特斯拉C870不支持它。任何提示?

编辑2:我的测试程序+更新的时间;我希望阅读不是太多! cutCreateTimer()函数不会为我编译:'错误:标识符“cutCreateTimer”未定义' - 这可能与机器上安装的旧cuda版本(2.0)有关

 __host__ void time_int(int print){
static struct timeval t1; /* var for previous time stamp */
static struct timeval t2; /* var of current time stamp */
double time;
if(gettimeofday(&t2, 0) == -1) return;
if(print != 0){
  time = (double) (t2.tv_sec - t1.tv_sec) + ((double) (t2.tv_usec - t1.tv_usec)) / 1000000.0;
  printf(...);
}
t1 = t2;
}

main:
time(0);
void *x;
cudaMallocHost(&x,1073741824);
void *y;
cudaMalloc(&y, 1073741824);
time(1);
cudaMemcpy(y,x,1073741824, cudaMemcpyHostToDevice);
time(1);
cudaMemcpy(x,y,1073741824, cudaMemcpyDeviceToHost);
time(1);

显示的时间是:
0.86秒分配
0.197 s第一份副本
5.02秒的第二份副本
奇怪的是:虽然第一次复制显示0.197s,但如果我观看程序运行则需要更长的时间。

3 个答案:

答案 0 :(得分:9)

是的,这很正常。 cudaMemcpy()执行了大量检查并且有效(如果主机内存是由通常的malloc()mmap()分配的)。它应检查每页数据是否在内存中,并将页面(逐个)移动到驱动程序。

您可以使用cudaHostAlloc functioncudaMallocHost来分配内存,而不是malloc。它将分配固定内存,该内存始终存储在RAM中,并且可以直接由GPU的DMA访问(更快cudaMemcpy())。引用第一个链接:

  

分配页锁定且可供设备访问的主机内存的计数字节。驱动程序跟踪使用此功能分配的虚拟内存范围,并自动加速对cudaMemcpy()等函数的调用。

唯一的限制因素是系统中固定内存的总量是有限的(不超过RAM大小;最好不要超过RAM - 1Gb):

  

分配过多的固定内存可能会降低系统性能,因为它会减少系统可用于分页的内存量。因此,最好谨慎地使用此功能来为主机和设备之间的数据交换分配暂存区域。

答案 1 :(得分:6)

假设传输时间准确,从固定内存传输1 GB的1.1秒似乎很慢。您确定PCIe插槽配置的宽度是否正确?要获得完整性能,您需要x16配置。一些平台提供两个插槽,其中一个配置为x16,另一个配置为x4。因此,如果您的机器有两个插槽,您可能需要尝试将卡移动到另一个插槽中。其他系统有两个插槽,如果只占用一个插槽,则可以获得x16,但如果两个插槽都被占用,则会获得两个x8插槽。 BIOS设置可能有助于确定如何配置PCIe插槽。

Tesla C870是一项相当古老的技术,但如果我没记错的话,使用第一代PCIe接口的这些部件应该可以正确地从固定内存传输大约2 GB / s的传输速率。目前的Fermi级GPU使用PCIe第2代接口,从固定存储器传输速率可达到5 GB / s以上(吞吐量测量,1 GB / s = 10 ^ 9字节/秒)。

请注意,PCIe使用分组传输,并且数据包开销在通用芯片组支持的数据包大小方面可能很重要,而较新的芯片组通常支持稍长的数据包。一个不太可能超过标称每个方向最大值的70%(对于PCIe 1.0 x16为4 GB / s,对于PCIe 2.0 x16为8 GB / s),即使是从/向固定主机内存的传输也是如此。这是一份白皮书,解释了开销问题,并有一个方便的图表显示了各种数据包大小可实现的利用率:

http://www.plxtech.com/files/pdf/technical/expresslane/Choosing_PCIe_Packet_Payload_Size.pdf

答案 2 :(得分:1)

除了没有正确配置的系统外,可怕的PCIe带宽的最佳解释是IOH /插槽与GPU插入的PCIe插槽之间不匹配。

大多数多插槽Intel i7级(Nehalem,Westmere)主板每个插槽都有一个I / O集线器。由于系统内存直接连接到每个CPU,因此“本地”的DMA访问(从连接到与执行DMA访问的GPU相同的IOH的CPU获取内存)比非本地内存(从连接的CPU获取内存)快得多到另一个IOH,一个必须通过连接两个CPU的QPI互连来满足的事务。)

重要说明:不幸的是,SBIOS通常配置交错系统,这会导致连续的内存分配在套接字之间交错。这减轻了CPU的本地/非本地访问的性能悬崖(一种方式来考虑它:它使所有内存访问对于两个套接字同样不好),但是由于它导致数据的每个其他页面导致对数据的GPU访问造成严重破坏。 -socket系统是非本地的。

如果系统只有一个IOH,那么Nehalem和Westmere类系统似乎不会遇到这个问题。

(顺便说一句,Sandy Bridge级处理器通过将PCI Express支持集成到CPU中,沿着这条道路再迈出一步,因此使用Sandy Bridge,多插槽机器会自动拥有多个IOH。)

您可以通过使用将其固定到套接字的工具运行测试(Linux上的numactl,如果可用)或使用平台相关代码来控制分配和线程在特定套接字上运行来调查此假设。你可以学到很多东西而不需要花哨 - 只需在main()的开头调用一个具有全局效果的函数来强制所有东西都放在一个或另一个插槽上,看看它是否会对你的PCIe传输性能产生很大的影响。