我最近尝试将我的CUDA代码与OpenMP结合使用,但是出现了一些问题。我的CUDA-OpenMP代码写成
int main (void)
{
cudaGetDeviceCount(&gpuNum);
//declare variables
float *data_h; *data_d[gpuNum];
data_h = (float*)malloc(Mem);
....
....
omp_set_num_threads(gpuNum);
#pragma omp parallel
{
int cpuid = omp_get_thread_num();
cudaSetDevice(cpuid);
cudaMalloc((void**)&data_d[cpuid], Mem );
cudaMemcpy( data_d[cpuid], data_h, Mem, cudaMemcpyHostToDevice);
kernel<<< gpu_block, gpu_thread >>>();
cudaMemcpy( data_h, data_d[cpuid], Mem, cudaMemcpyDeviceToHost);
}
printf("end of parallel\n");
//post process
}
问题在于,有时当我运行此代码时,一切进展顺利,但有时它会停止并且“并行结束”句子将不会打印出来。这种情况是随机发生的,任何人都可以告诉我这可能是什么原因?
答案 0 :(得分:2)
我想提供一些失败的可能性:
在并行区域中,假设当执行前两行时,活动线程将被另一行切换,
#pragma omp parallel{
int cpuid = omp_get_thread_num();
cudaSetDevice(cpuid);
...
}
然后另一个线程将调用设备设备功能,所选设备将被更改。
虽然memcopy操作阻塞,但内核调用却没有。因此,如果在内核调用之后切换线程,则在一次内核调用未完成时,将发出另一个内核调用。要执行并发内核,您需要使用“ streams ”。看看
CUDA concurrent kernel execution with multiple kernels per stream
答案 1 :(得分:0)
如果您想获得最佳性能,我建议您不要使用OpenMP来运行CUDA。我从我的经验中知道,OpenMP创建的thred并不是无成本的,而且需要一些时间。在创建线程期间,您将能够在许多设备上运行更多的gpu内核。
如上所述@phoad,如果您的数据集是独立的,则可以使用流。你可以在网上找到很多例子。
另一种可能性是重新设计你的内核。一个内核可以做同样的工作并返回数组。