1

同じカーネルをループで数回呼び出す 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 が 1 回だけ呼び出されるようにすると、コードはエラーを返さずに機能しました (ただし、結果は正しくありませんでした)。clEnqueueNDRangeKernel を複数回呼び出すと問題が発生します (これは実際に行う必要があります)。

私は Mac OS 10.6 Snow Leopard を使用しており、Apple の OpenCL 1.0 プラットフォームと NVidia GeForce 9600m を使用しています。他のプラットフォームの OpenCL では、ループ内でカーネルを実行できますか? OS X 上の OpenCL でこのような問題が発生した人はいますか? コマンド キューが無効になる原因は何ですか?

4

2 に答える 2

1

カーネルでの (グローバルまたはローカル) メモリ オーバーランなど、複数の原因が考えられます。

また、global_ws は local_ws の倍数である必要があります。

SortingNetworks サンプルをご覧ください http://developer.download.nvidia.com/compute/cuda/3_0/sdk/website/OpenCL/website/samples.html

于 2012-11-17T18:02:55.203 に答える
1

あなたの質問の 1 つに答えるには: はい、任意の数のカーネルをコマンド キューに入れることができます (ループ内からかどうかに関係なく)。これが少なくとも Windows の NVIDIA、AMD、および Intel ドライバーで期待どおりに動作することを確認できます。

于 2012-11-28T13:43:33.173 に答える