【发布时间】:2013-10-08 12:57:08
【问题描述】:
我有一个启动 OpenCL 内核的循环(大约 10 亿次迭代)。每个内核由 1 个线程执行,并执行非常微不足道的操作。问题是在执行几百万次迭代后,代码冻结(停止)并且程序根本没有终止。它在对 clFinish() 的调用中冻结。程序并不总是在同一迭代中冻结。
如果每 1000 次迭代调用一次 clFinish() 而不是在每次迭代中调用一次,问题就消失了,所以我觉得问题是 clFinish() 正在等待内核结束但内核被杀死(不知何故)在调用 clFinish() 之前。另请注意,当我在循环内插入许多 printf() 调用时,问题就消失了!
当我在 CPU 设备上(在我的笔记本电脑上,我使用 AMD SDK)上执行程序时遇到问题,并且我在带有 Nvidia Fermi GPU 的机器上也遇到问题(Nvidia SDK 和驱动程序,AMD SDK 也已安装在那台机器上)。
我在每次 OpenCL API 调用后检查错误,但未检测到错误。我删除了错误检查以使代码清晰。
我的问题:
他们是否对下面的 OpenCL API 有任何不正确的使用?
如果同时启动大量 OpenCL 内核会有什么问题吗?
代码是由我们的一些工具自动生成的,所以请不要问我为什么要调用只有 1 个线程的内核(这是另一个问题,我知道这样的代码不利于性能)。我的目标是了解代码中的问题是什么,理论上应该没有任何问题。
主机代码:
/* OpenCL initialization. */
/* ... */
cl_mem dev_acc = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(double), NULL, &err);
for (int h0 = 1; h0 <= ni; h0 += 1)
for (int h2 = 0; h2 < nj; h2 += 1)
for (int h5 = 0; h5 < h2 - 1; h5 += 1) {
size_t global_work_size[1] = {1};
size_t block_size[1] = {1};
cl_kernel kernel2 = clCreateKernel(program, "kernel2", &err);
clSetKernelArg(kernel2, 0, sizeof(cl_mem), (void *) &dev_acc);
clEnqueueNDRangeKernel(queue, kernel2, 1, NULL, global_work_size,block_size,0, NULL, NULL);
clFinish(queue);
clReleaseKernel(kernel2);
}
内核代码:
__kernel void kernel2(__global double *acc)
{
*acc = 1;
}
编译: gcc -O3 -lm -std=gnu99 polybench.c ocl_utilities.c symm_host.c -lOpenCL -lm -I/opt/AMDAPP/include -L/opt/AMDAPP/lib/x86_64
我使用的是 Ubuntu 12.04,内核 3.2.0-29-generic,X86_64,RAM:2 GB
【问题讨论】:
-
我在 linux (Ubuntu) 中也遇到了 nVIDIA 的这种死锁。但在 ATI/Windows 上没有出现相同的代码。我使用固定内存解决了它。但说实话,我从来不知道是什么导致了这个问题。 (我猜是驱动程序错误)。查看代码,我不会那样做,因为它非常低效。但不应该挂起执行。
-
谢谢。你有没有和我的代码陷入僵局?还是使用您自己的代码?每 100 次迭代仅调用一次 clFinish() 可以为我解决问题,但我仍然需要了解问题所在。关于性能问题。是的,当然,为每个线程启动一个内核并不是一个好主意,但无论如何我都需要了解问题所在,以确保我在调用 OpenCL API 的方式上没有犯错误。
-
原来是库问题引起的。我尝试使用 AMD 库,现在可以正常工作了。