如何在C语言中将向量参数传递给OpenCL内核?

5

我很难将一个向量类型(uint8)的参数从C语言的主机代码传递到OpenCL内核函数。

在主机端,我将数据存储在一个数组中:

cl_uint dataArr[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };

我的真实数据不仅仅是 [1, 8],这只是为了便于解释。

然后我将数据传输到缓冲区以传递给内核:

cl_mem kernelInputData = clCreateBuffer(context,
    CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(cl_uint)*8, dataArr, NULL);

接下来,我将这个缓冲区传递给内核:

clSetKernelArg(kernel, 0, sizeof(cl_mem), &kernelInputData);

内核函数的签名大致如下:

kernel void kernelFunction(constant uint8 *vectorPtr)

然而,内核似乎无法从指向kernelInputData的指针中获取正确的输入数据。当我从内核中返回值时,我发现vectorPtr指向具有这个结构的内容:(1,2,3,4,5,?,?,?)其中问号通常是4293848814,但有时是0。总之,都不是它们应该的值。
我做错了什么?
编辑:
我已经从使用数组切换到在主机端使用cl_uint8。现在我有: cl_uint8 dataVector = { 1, 2, 3, 4, 5, 6, 7, 8 }; 然后我像这样将此向量传递给内核: clSetKernelArg(kernel, 0, sizeof(cl_uint8), &dataVector); 内核函数的签名类似于: kernel void kernelFunction(constant uint8 *vectorPtr) 但是,运行此代码会在clSetKernelArg()上产生一个CL_INVALID_ARG_SIZE错误。如果我将ARG_SIZE参数切换为sizeof(cl_uint8 *),则此错误消失,但是我会在clSetKernelArg()中的__dynamic_cast处得到一个EXC_BAD_ACCESS错误。
我的设备是:
Apple Macbook Pro(2009年中期) OSX 10.8 Mountain Lion NVIDIA GeForce 9400M OpenCL 1.0 CLH 1.0

我不明白,你想传递一个向量还是一个向量数组? “kernel void kernelFunction(constant uint8 *vectorPtr)” 请删除 *。 - Alex Placet
只需一个向量。 clSetKernelArg()的最后一个参数是类型为const void * - JacobEvelyn
1
cl_uint8 dataVector = { 1, 2, 3, 4, 5, 6, 7, 8 }; clSetKernelArg(kernel, 0, sizeof(cl_uint8), &dataVector); 以及 kernel void kernelFunction(constant uint8 vectorPtr) - Alex Placet
哇,我一直以为所有内核函数参数都必须是指针,但显然不是这样。你的代码运行得很好!编辑你的答案,我会标记为正确吗? - JacobEvelyn
2个回答

8
您正在定义一个大小为8的cl_uint数组。 创建cl_mem和设置内核参数的方式正确。 但是您的内核参数不正确:您尝试读取一个cl_uint8而不是cl_uint数组。

如果您想使用向量数据类型,则必须声明:大小为1的cl_uint8 dataArr。 或者如果您想使用大小为8的数组:kernel void kernelFunction(constant uint *vectorPtr, uint size):

编辑:

用于cl_uint8 dataVector的内核参数不是指针。 因此,正确的代码是:

cl_uint8 dataVector = { 1, 2, 3, 4, 5, 6, 7, 8 };
clSetKernelArg(kernel, 0, sizeof(cl_uint8), &dataVector);

并且

kernel void kernelFunction(constant uint8 vectorPtr)

cl_uint8 数组; array.s[0] = 0; array.s[1] = 1; array.s[2] = 2; ... 或者cl_uint8 array = (cl_uint8)(0,1,2,...); - Alex Placet
啊,不那么简单。我已经尝试过(cl_uint8)(0, 1, 2,...)的构造方法,但在主机上无法编译。你提供的另一种构造方法确实有效,这里也提到了类似的方法(http://stackoverflow.com/questions/9230856/failing-to-initialize-opencl-vector-literal/9234640#9234640),但是当我使用`clSetKernelArg(kernel, 0, sizeof(cl_uint8), &testVector)将这样构造的向量传递给内核时,会出现EXC_BAD_ACCESS错误。当clSetKernelArg的arg_size参数为sizeof(cl_mem)sizeof(cl_uint *)`时会发生这种情况。我错过了什么吗? - JacobEvelyn
你的OpenCL设备是什么?OpenCL版本等等? - Alex Placet
这次编辑不够大以至于不让我做出更改,但内核函数参数的 constant 修饰符必须更改为 const,因为 constant 只能应用于指针参数。我有一种感觉,缺少 constant 意味着随着分配更多内存会有很多减速... 你知道是否仍然有办法将数据作为指针传递吗? - JacobEvelyn
我不确定常量内存总是比全局内存更快,这取决于您的设备。对于许多设备,私有内存位于全局内存中。如果您想要最佳内存访问性能,则本地内存将更好。 请阅读以下链接:
  • http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/constant.html
  • http://www.codeproject.com/Articles/122405/Part-2-OpenCL-Memory-Spaces
- Alex Placet
显示剩余5条评论

1

最小可运行示例

int2被传递给内核。它最初被创建为一个cl_int数组。

#include <assert.h>
#include <stdlib.h>

#include <CL/cl.h>

int main(void) {
    const char *source =
        "__kernel void main(__global int2 *out) {\n"
        "      out[get_global_id(0)]++;\n"
        "}\n";
    cl_command_queue command_queue;
    cl_context context;
    cl_device_id device;
    cl_int input[] = {0, 1, 2, 3};
    const size_t global_work_size = sizeof(input) / sizeof(cl_int2);
    cl_kernel kernel;
    cl_mem buffer;
    cl_platform_id platform;
    cl_program program;

    clGetPlatformIDs(1, &platform, NULL);
    clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 1, &device, NULL);
    context = clCreateContext(NULL, 1, &device, NULL, NULL, NULL);
    command_queue = clCreateCommandQueue(context, device, 0, NULL);
    buffer = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, sizeof(input), &input, NULL);
    program = clCreateProgramWithSource(context, 1, &source, NULL, NULL);
    clBuildProgram(program, 1, &device, "", NULL, NULL);
    kernel = clCreateKernel(program, "main", NULL);
    clSetKernelArg(kernel, 0, sizeof(cl_mem), &buffer);
    clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, &global_work_size, NULL, 0, NULL, NULL);
    clFlush(command_queue);
    clFinish(command_queue);
    clEnqueueReadBuffer(command_queue, buffer, CL_TRUE, 0, sizeof(input), &input, 0, NULL, NULL);

    assert(input[0] == 1);
    assert(input[1] == 2);
    assert(input[2] == 3);
    assert(input[3] == 4);
    return EXIT_SUCCESS;
}

在Ubuntu 15.10上测试,OpenCL版本为1.2,NVIDIA驱动版本为352.53。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接