【问题标题】:OpenCL: getting INVALID_COMMAND_QUEUE from device to host memory transfer after kernel is called in loop many timesOpenCL:多次循环调用内核后,从设备到主机内存传输获取 INVALID_COMMAND_QUEUE
【发布时间】:2012-10-17 21:48:36
【问题描述】:

我正在开发一个在循环中多次调用同一个内核的 OpenCL 程序。当我使用 clEnqueueReadBuffer 将设备内存传输回主机时,它报告命令队列无效。

下面是一个调用来启动双音排序的函数,它被缩短以使其更具可读性。设备列表、上下文、命令队列和内核在外部创建并传递给该函数。 list 包含要排序的列表,sizelist 中的元素个数。

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 遇到过这样的问题吗?什么可能导致命令队列失效?

【问题讨论】:

    标签: c osx-snow-leopard opencl nvidia


    【解决方案1】:

    回答您的一个问题:是的,您可以将任意数量的内核排入命令队列(无论是来自循环内还是其他方式)。我可以确认这至少可以在 Windows 上的 NVIDIA、AMD 和 Intel 驱动程序上正常工作。

    【讨论】:

      【解决方案2】:

      可能有多种原因,例如内核中的(全局或本地)内存溢出。

      global_ws 也应该是 local_ws 的倍数。

      查看 SortingNetworks 示例 http://developer.download.nvidia.com/compute/cuda/3_0/sdk/website/OpenCL/website/samples.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-26
        • 1970-01-01
        • 2014-05-26
        • 1970-01-01
        • 2012-12-31
        • 2011-12-06
        • 2021-07-29
        • 1970-01-01
        相关资源
        最近更新 更多