OpenCL 代码不适用于更大的数据集

问题描述

我正在尝试用 OpenCL/C++ 编写一个排序函数一个求和函数。然而,虽然这两个函数在较小的数据集上都可以正常工作,但它们都不适用于任何显着长度的数据集。我尝试使用的数据集大约有 200 万个条目,但函数在大约 500 个时停止工作。任何有关为什么会这样的帮助将不胜感激。 OpenCL 代码如下。

编辑:现在只显示与总和完全相关的代码(根据要求)。

kernel void sum(global const double* A,global double* B) {
    int id = get_global_id(0);
    int N = get_global_size(0);

    B[id] = A[id];

    barrier(CLK_GLOBAL_MEM_FENCE);

    for (int i = 1; i < N/2; i *= 2) { //i is a stride
        if (!(id % (i * 2)) && ((id + i) < N)) 
            B[id] += B[id + i];

        barrier(CLK_GLOBAL_MEM_FENCE);
    }
}

还有 C++ 代码

        std::vector<double> temps(100000,1);

        // Load functions
        cl::Kernel kernel_sum = cl::Kernel(program,"sum");

        // Set up variables
        size_t elements = temps.size();
        size_t size = temps.size() * sizeof(double);
        
        size_t workgroup_size = 10;
        size_t padding_size = elements % workgroup_size;

        // Sum
        if (padding_size) {
            std::vector<double> temps_padding(workgroup_size - padding_size,0);
            temps.insert(temps.end(),temps_padding.begin(),temps_padding.end());
        }

        std::vector<double> temps_sum(elements);
        size_t output_size = temps_sum.size() * sizeof(double);

        cl::Buffer sum_buffer_1(context,CL_MEM_READ_ONLY,size);
        cl::Buffer sum_buffer_2(context,CL_MEM_READ_WRITE,output_size);

        queue.enqueueWriteBuffer(sum_buffer_1,CL_TRUE,size,&temps[0]);
        queue.enqueueFillBuffer(sum_buffer_2,output_size);

        kernel_sum.setArg(0,sum_buffer_1);
        kernel_sum.setArg(1,sum_buffer_2);
        
        queue.enqueueNDRangeKernel(kernel_sum,cl::NullRange,cl::NDRange(elements),cl::NDRange(workgroup_size));
        queue.enqueueReadBuffer(sum_buffer_2,output_size,&temps_sum[0]);
        double summed = temps_sum[0];

        std::cout << "SUMMED: " << summed << std::endl;

我试过四处看看,但我完全被困住了。

解决方法

您正在尝试使用障碍来 个工作组进行同步。这行不通。 Barriers are for synchronising within work groups

工作组彼此之间没有按照明确定义的顺序运行;您只能在工作组中使用这种归约算法。您可能需要使用第二个内核传递来组合来自各个工作组的结果,或者在主机 CPU 上执行此部分。 (或者修改你的算法以某种方式使用原子等)