了解工作项和工作组

时间:2014-02-07 14:15:05

标签: c++ opencl

根据我的previous问题:

我仍在尝试复制图像(没有实际原因,只是从一个简单的开始):

图片包含200 * 300 == 60000像素。

根据CL_DEVICE_MAX_WORK_GROUP_SIZE,最大工作项数为4100。

kernel1:

std::string kernelCode =
            "void kernel copy(global const int* image, global int* result)"
            "{"
                "result[get_local_id(0) + get_group_id(0) * get_local_size(0)] = image[get_local_id(0) + get_group_id(0) * get_local_size(0)];"
            "}";

队列:

for (int offset = 0; offset < 30; ++offset)
        queue.enqueueNDRangeKernel(imgProcess, cl::NDRange(offset * 2000), cl::NDRange(60000));
queue.finish();

给出了段错误,出了什么问题?

使用最后一个参数cl::NDRange(20000)它不会,但只返回部分图像。

另外我不明白,为什么我不能使用这个内核:

kernel2:

std::string kernelCode =
            "void kernel copy(global const int* image, global int* result)"
            "{"
                "result[get_global_id(0)] = image[get_global_id(0)];"
            "}";

查看第31张幻灯片上的this演示文稿:

为什么我不能简单地使用global_id?

EDIT1

平台:AMD加速并行处理

设备:AMD Athlon(tm)II P320双核处理器

EDIT2

结果基于huseyin tugrul buyukisik的回答:

enter image description here

EDIT3

使用最后一个参数cl::NDRange(20000)

enter image description here

内核是第一种方式。

EDIT4

std::string kernelCode =
                "void kernel copy(global const int* image, global int* result)"
                "{"
                    "result[get_global_id(0)] = image[get_global_id(0)];"
                "}";
//...
cl_int err;
    err = queue.enqueueNDRangeKernel(imgProcess, cl::NDRange(0), cl::NDRange(59904), cl::NDRange(128));

    if (err == 0)
        qDebug() << "success";
    else
    {
        qDebug() << err;
        exit(1);
    }

打印成功。

也许这是错的?

int size = _originalImage.width() * _originalImage.height();
int* result = new int[size];
//...
cl::Buffer resultBuffer(context, CL_MEM_READ_WRITE, size);
//...
queue.enqueueReadBuffer(resultBuffer, CL_TRUE, 0, size, result);

有罪的是:

cl::Buffer imageBuffer(context, CL_MEM_USE_HOST_PTR, sizeof(int) * size, _originalImage.bits());
cl::Buffer resultBuffer(context, CL_MEM_READ_ONLY, sizeof(int) * size);
queue.enqueueReadBuffer(resultBuffer, CL_TRUE, 0, sizeof(int) * size, result);

我使用size代替sizeof(int) * size

1 个答案:

答案 0 :(得分:2)

编辑2:

请尝试非常量内存说明符(可能与您的cpu不兼容):

std::string kernelCode =
            "__kernel void copy(__global int* image, __global int* result)"
            "{"
                "result[get_global_id(0)] = image[get_global_id(0)];"
            "}";

您也可能需要更改缓冲区选项。

修改

您在“全局”和“内核”说明符之前忘记了'__,请尝试:

std::string kernelCode =
            "__kernel void copy(__global const int* image, __global int* result)"
            "{"
                "result[get_global_id(0)] = image[get_global_id(0)];"
            "}";

总元素是60000,但是你正在做一个偏移量+ 60000,它会溢出并读取/写入未被利用的区域。

opencl 1.2 c ++绑定的ndrange的通常用法必须是:

cl_int err;
err=cq.enqueueNDRangeKernel(kernelFunction,referenceRange,globalRange,localRange);

然后检查错误以查找您寻找的真实错误代码。 0表示成功。**

如果您想将工作分成较小的部分,则应将每个单位的范围限制为60000 / N

如果除以30份,则

for (int offset = 0; offset < 30; ++offset)
        queue.enqueueNDRangeKernel(imgProcess, cl::NDRange(offset * 2000), cl::NDRange(60000/30));
queue.finish();

并仔细检查每个缓冲区的大小,例如的sizeof(cl_int)* arrElementNumber

对于设备整数,整数的大小可能不相同。你需要60000个元素?然后在创建缓冲区时需要240000个字节作为大小传递。

为了兼容性,如果要在另一台机器上运行此代码,则应在创建缓冲区之前检查整数的大小。

你可能已经知道了,但无论如何我会告诉你:

CL_DEVICE_MAX_WORK_GROUP_SIZE

是可以在计算单元中共享本地/共享内存的线程数。你不需要为此分工。 Opencl自动执行此操作,并为整个工作中的每个线程提供唯一的全局ID,并为计算单元中的每个线程提供唯一的本地ID。如果CL_DEVICE_MAX_WORK_GROUP_SIZE是4100,那么它可以创建在计算单元中共享相同变量的线程。您只需一个adition即可在一次扫描中计算所有60000个变量:为此创建多个工作组,每个组都有一个组ID。

  // this should work without a problem
  queue.enqueueNDRangeKernel(imgProcess, cl::NDRange(0), cl::NDRange(60000));

如果您有AMD gpu或cpu,并且如果您使用的是msvc,则可以从amd站点安装codexl并从下拉菜单中选择系统信息以查看相关数字。

哪种设备属于您的设备?我找不到任何最大工作组大小为4100的设备!我的cpu有1024,gpu有256.那是xeon-phi吗?

例如,总工作项可以大到工作组大小的256 * 256倍。 enter image description here

Codexl还有其他不错的功能,例如性能分析,如果您需要最高性能和错误修正,则可以跟踪代码。