正确的地方使用cudaSetDeviceFlags?

时间:2017-11-08 09:28:07

标签: c++ multithreading cuda

Win10 x64,CUDA 8.0,VS2015,6核CPU(12个逻辑核心),2个GTX580 GPU。

一般情况下,我正在开发一个多线程应用程序,它启动2个与2个可用GPU相关联的线程,这些线程存储在线程池中。

每个线程在启动时执行以下初始化过程(即仅在每个线程的运行时期间执行此操作):

::cudaSetDevice(0 or 1, as we have only two GPUs);
::cudaDeviceSetCacheConfig(cudaFuncCachePreferL1);
::cudaSetDeviceFlags(cudaDeviceMapHost | cudaDeviceScheduleBlockingSync);

然后,从其他工作线程(另外12个不接触GPU的线程),我开始向这两个与GPU相关的工作线程提供数据,只要GPU线程数量相等,它就能完美运行可用的物理GPU数量。

现在我想启动4个GPU线程(即每个GPU 2个线程)并使每个线程通过单独的CUDA流工作。我知道对于正确的CUDA流使用至关重要的要求,我满足了所有这些要求。我失败的是上面提到的初始化过程。

一旦尝试从不同的GPU线程执行此过程两次但对于相同的GPU,:: cudaSetDeviceFlags(...)开始失败,“在此过程中设备处于活动状态时无法设置” 错误消息。

我查看了手册,似乎我明白了为什么会发生这种情况,我无法理解的是如何正确使用:: cudaSetDeviceFlags(...)进行设置。

我可以评论这个:: cudaSetDeviceFlags(...)行,即使每个GPU有8个线程,propgram也能正常工作,但我需要设置cudaDeviceMapHost标志才能使用流,固定内存不会被否则就可以了。

编辑要考虑的额外信息#1:

  1. 如果在:: cudaSetDevice之前调用:: cudaSetDeviceFlags则没有错误 发生。
  2. 每个GPU线程通过分配一大块固定内存     :: VirtualAlloc - > :: cudaHostRegister线程启动时的方法     (无论推出多少GPU线程)都能正常工作     在线程终止时释放它(via :: cudaHostUnregister - >     :: VirtualFree)。 :: cudaHostUnregister失败,“指针没有     对应于已注册的内存区域“如果每个GPU的线程数大于1,则为一半线程。

1 个答案:

答案 0 :(得分:2)

嗯,非常复杂的trythis-trythat-seewhathappens-tryagain练习方法终于成功了。

以下是有关:: cudaSetDeviceFlags()的文档的摘录:

  

将标志记录为初始化当前时要使用的标志   设备。 如果没有设备进入调用线程,那么   flags将应用于初始化的任何设备的初始化   通过调用主机线程,除非该设备已经拥有它   初始化标志由此主机线程或任何主机线程显式设置。

因此,在GPU工作线程中,必须在 :: cudaSetDevice()之前调用:: cudaSetDeviceFlags()

我已经在GPU线程初始化代码中实现了这样的事情,以确保在设备集实际应用之前设置了设备标志:

bse__throw_CUDAHOST_FAILED(::cudaSetDeviceFlags(nFlagsOfDesire));
bse__throw_CUDAHOST_FAILED(::cudaSetDevice(nDevice));

unsigned int nDeviceFlagsActual = 0;
bse__throw_CUDAHOST_FAILED(::cudaGetDeviceFlags(&nDeviceFlagsActual));
bse__throw_IF(nFlagsOfDesire != nDeviceFlagsActual);

此外,talonmies的评论显示了解决:: cudaHostUnregister错误的方法。