我正在开发一个 OpenCL 程序,该程序在一个循环中多次调用同一个内核。当我使用 clEnqueueReadBuffer 将设备内存传输回主机时,它报告命令队列无效。
下面是一个被调用以启动双调排序的函数,它被缩短以使其更具可读性。设备列表、上下文、命令队列和内核在外部创建并传递给此函数。 list包含待排序的列表,size是list中元素的个数。
cl_int OpenCLBitonicSort(cl_device_id device, cl_context context,
cl_command_queue commandQueue, cl_kernel bitonicSortKernel,
unsigned int * list, unsigned int size){
//create OpenCL specific variables
cl_int error = CL_SUCCESS;
size_t maximum_local_ws;
size_t local_ws;
size_t global_ws;
//create variables that keep track of bitonic sorting progress
unsigned int stage = 0;
unsigned int subStage;
unsigned int numberOfStages = 0;
//get maximum work group size
clGetKernelWorkGroupInfo(bitonicSortKernel, device,
CL_KERNEL_WORK_GROUP_SIZE, sizeof(maximum_local_ws),
&maximum_local_ws, NULL);
//make local_ws the largest perfect square allowed by OpenCL
for(i = 1; i <= maximum_local_ws; i *= 2){
local_ws = (size_t) i;
}
//total number of comparators will be half the items in the list
global_ws = (size_t) size/2;
//transfer list to the device
cl_mem list_d = clCreateBuffer(context, CL_MEM_COPY_HOST_PTR,
size * sizeof(unsigned int), list, &error);
//find the number of stages needed (numberOfStages = ln(size))
for(numberOfStages = 0; (1 << numberOfStages ^ size); numberOfStages++){
}
//loop through all stages
for(stage = 0; stage < numberOfStages; stage++){
//loop through all substages in each stage
for(subStage = stage, i = 0; i <= stage; subStage--, i++){
//add kernel parameters
error = clSetKernelArg(bitonicSortKernel, 0,
sizeof(cl_mem), &list_d);
error = clSetKernelArg(bitonicSortKernel, 1,
sizeof(unsigned int), &size);
error = clSetKernelArg(bitonicSortKernel, 2,
sizeof(unsigned int), &stage);
error = clSetKernelArg(bitonicSortKernel, 3,
sizeof(unsigned int), &subStage);
//call the kernel
error = clEnqueueNDRangeKernel(commandQueue, bitonicSortKernel, 1,
NULL, &global_ws, &local_ws, 0, NULL, NULL);
//wait for the kernel to stop executing
error = clEnqueueBarrier(commandQueue);
}
}
//read the result back to the host
error = clEnqueueReadBuffer(commandQueue, list_d, CL_TRUE, 0,
size * sizeof(unsigned int), list, 0, NULL, NULL);
//free the list on the device
clReleaseMemObject(list_d);
return error;
}
在此代码中:clEnqueueReadBuffer 表示 commandQueue 无效。但是,当我调用 clEnqueueNDRangeKernel 和 clEnqueueBarrier 时它是有效的。
当我将 numberOfStages 设置为 1 并将 stage 设置为 0 时,clEnqueueNDRangeKernel 仅被调用一次,代码运行时没有返回错误(尽管结果不正确)。多次调用 clEnqueueNDRangeKernel 存在问题(我确实需要这样做)。
我在 Mac OS 10.6 Snow Leopard 上使用 Apple 的 OpenCL 1.0 平台和 NVidia GeForce 9600m。在其他平台上的 OpenCL 中是否可以在循环内运行内核?有人在 OS X 上使用 OpenCL 遇到过这样的问题吗?什么可能导致命令队列无效?
最佳答案
可能有多种原因,例如内核中的(全局或本地)内存溢出。
另外,global_ws 应该是 local_ws 的倍数。
查看 SortingNetworks 示例 http://developer.download.nvidia.com/compute/cuda/3_0/sdk/website/OpenCL/website/samples.html
关于c - OpenCL:多次循环调用内核后,从设备到主机内存传输获取 INVALID_COMMAND_QUEUE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13107080/