【问题标题】:OpenCL Reduce kernel returning only one valueOpenCL 减少内核只返回一个值
【发布时间】:2018-12-06 17:31:18
【问题描述】:

我正在测试 OpenCL 2.0 缩减内核以获得 2d-workgroups 的最大值。

我打电话:

//get global max
float max_v;
max_v = work_group_reduce_max(hsv_fi.z);

if(get_local_id(0) == 0 && get_local_id(1) == 0){
    result[get_group_id(0)] = 1337;// max_v;
}

在我的内核末尾。 1337 用于测试目的。我期望一个包含 1337 个值的 workgroupsize 数组。

但我不知何故只得到一个值。我在内核中有什么明显的错误吗?

我尝试通过以下方式阅读:

int errcode;
float* resultData = (float*)oclEnvironment._commandQueue.enqueueMapBuffer(resultBuffer, true, CL_MAP_READ, 0, size, 0, 0, &errcode);
std::copy((float*)resultData, (float*)(resultData + size), (float*)dest);

我的 *dest 指针是:

std::vector<float> resultArray;

我保留了工作组大小,并通过以下方式将指针交给它 (*dest):

resultArray.data()

有什么建议吗?我觉得我错过了一些小事。

谢谢!

编辑:

cl::NDRange global(width, height);
//Intel HD 530 can have a max. workgroup size of 256.
int dim1 = 16;
int dim2 = 16;
cl::NDRange local(dim1, dim2);

//Calculate the number of workgroups
int numberOfWorkgroups = ceil((width * height) / (float)(dim1 * dim2));

//each workgroup reduces the data to a single element. This elements are then reduced on host in the final reduction step.
    oclEnvironment._commandQueue.enqueueNDRangeKernel(_kernel, cl::NullRange, global, local);

edit2:

我还是不明白 OpenCL 在做什么。我有一个 480x360 的图像,我希望它作为每个元素 3 个字节(rgb)的缓冲区。我现在在列表中得到了 30 个有效的最大值,但不是我怀疑的 675 个。图像的分辨率为 480 * 360。我的最大工作组大小为 (16,16,1)。所以我得到了我认为的 675 个工作组。不知何故,我只收到了 30 个值,其他的都是零。我试图将输入填充到 480*368 以使两个维度都是 16 的倍数。仍然相同。如果这 30 个值减少了我的整个数据集并且我收到的该列表的最大值是最大值,那就没问题了。但由于我不确定发生了什么,我不能确定是这样。

【问题讨论】:

  • 应该不是问题,但是(float*) 中的额外std::copy 转换有什么用?
  • size 是字节大小还是浮点数?用法似乎不一致。
  • (float*) 确实没有必要。我可以删除它们,但对我的问题没有任何影响。大小是浮点数或工作组数。
  • 我怀疑enqueueMapBuffer 的大小是字节数,而不是项目数。
  • 我用 size * sizeof(float) 试过了,但它崩溃了。

标签: c++ opencl


【解决方案1】:

user10605163 的 cmets 将我引向了这个问题。正如他正确怀疑的那样,我只从缓冲区中读取了工作组的大小,而不是工作组的大小乘以 sizeof(float) 。这让我很困惑,因为我也忘记使用 sizeof(float) 乘数创建缓冲区,所以一开始并不认为这是错误的。一旦我对我的代码进行了调试和尝试,这个简单的提示就是我的问题的解决方案,OpenCL 就像我现在期望的那样工作。

我喜欢在这里写的一件事,因为它也让我很头疼,如果你试图避免在数据中使用填充,不要在内核中写一些东西,比如

if(get_global_linear_id() >= bufferSize)
{
    return;
}else{
    ... work + blocking call (barrier or work_group_reduce_*) ...
}

这将使您的系统崩溃或占用您的 GPU,直到您重新启动系统。如果您尝试调试使用 CPU 平台,它不会冻结您的系统。但是改变上面的行为,或者使用填充,例如零,或者其他东西,这样你的工作项就不会像我的那样卡住。

这与实际的解决方案无关,但花了我时间去弄清楚,也许将来会对某人有所帮助。

【讨论】:

    猜你喜欢
    • 2011-12-06
    • 2011-04-15
    • 2017-01-15
    • 1970-01-01
    • 2013-02-26
    • 1970-01-01
    • 1970-01-01
    • 2020-09-19
    • 2016-11-27
    相关资源
    最近更新 更多