【发布时间】:2023-03-15 10:50:01
【问题描述】:
我正在尝试在 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, 0, size, &temps[0]);
queue.enqueueFillBuffer(sum_buffer_2, 0, 0, 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, CL_TRUE, 0, output_size, &temps_sum[0]);
double summed = temps_sum[0];
std::cout << "SUMMED: " << summed << std::endl;
我试过到处看看,但我完全卡住了。
【问题讨论】:
-
“停止工作”是什么意思?什么失败了?在哪里?
-
基本上,排序没有正确排序。它几乎可以 - 它有点像块排序,所以前 2/5 被排序,最后 2/5 被排序,然后中间只是一个乱码。对于求和,它只是求和不正确。我尝试了另一种求和方法,但数字太高,而提供的结果太低。
-
你能把你的代码简化成一件事吗?这里的人不想涉足您的参数处理和错误检查等。将其归结为几行 C++ 和一个简短的 OpenCL 内核,它展示了您所看到的问题之一。
-
我包含了所有内容,以便人们可以根据需要自行运行代码(尽管他们需要删除 Utils.h,哎呀)。老实说,我不知道问题出在哪里。我会把它简化为只显示总和的东西,但是是的。