OpenCL 无法为常量数组设置内核参数
OpenCL can't set kernel args for constant array
我正在尝试设置我的内核的参数,但当我尝试设置 arg-0(即边界)时,我一直收到 CL_INVALID_ARG_SIZE。奇怪的是,如果我只注释掉第一个 clSetKernelArgs,所有其他似乎都有效。我认为这可能是常量数组的问题,除了它适用于 rand_seeds.
success = clSetKernelArg(solver_kernel, 0, sizeof(cl_float) * 10, bounds);
if(success != CL_SUCCESS)
{
printf("%d\n", success);
exit(1);
}
success = clSetKernelArg(solver_kernel, 1, sizeof(cl_float) * 2, seeds);
if(success != CL_SUCCESS)
{
printf("%d\n", success);
exit(1);
}
success = clSetKernelArg(solver_kernel, 2, sizeof(cl_int), &trials);
if(success != CL_SUCCESS)
{
printf("%d\n", success);
exit(1);
}
success = clSetKernelArg(solver_kernel, 3, sizeof(cl_int), &start_temp);
if(success != CL_SUCCESS)
{
printf("%d\n", success);
exit(1);
}
这是我内核的头文件
__kernel void solver_kernel
(
__constant float bounds[10],
__constant int rand_seeds[2],
int trials,
int start_temp
)
The memory object specified as argument value must be a buffer object
(or NULL) if the argument is declared to be a pointer of a built-in or
user defined type with the __global
or __constant
qualifier.
所以你必须先创建一个缓冲区并将其设置为你的内核参数。应该是这样的
cl_mem bounds_buffer = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(cl_float) * 10, bounds, &success);
success = clSetKernelArg(solver_kernel, 0, sizeof(cl_mem), bounds_buffer);
你需要对 rand_seeds
参数做同样的事情,即使你没有在这一行得到错误(可能是因为 sizeof(cl_float) * 2 == sizeof(cl_mem)
偶然,这仍然会产生不正确的结果)。
如果您的缓冲区永远不变,则无需使用缓冲区 + __constant
方式。这是一个替代方案。
实际上有两种在内核中使用常量内存的方法:
- 使用标准缓冲区 +
__constant
标志
- 使用结构参数
首选第一个(因此请使用@Jan 接受的答案),因为您明确说明了您希望如何处理数据。但在实践中,所有的实现都对第二种情况使用常量内存。由于传递给内核的数据是静态的,无论如何都不可修改。
因此,您可以像这样重写内核:
typedef struct float_10 { float f[10];} float_10;
typedef struct int_2 { int i[2];}int_2;
__kernel void solver_kernel
(
float_10 bounds,
int_2 rand_seeds,
int trials,
int start_temp
)
应该有相同的性能。
编辑:因为你需要结构,而不是数组
我正在尝试设置我的内核的参数,但当我尝试设置 arg-0(即边界)时,我一直收到 CL_INVALID_ARG_SIZE。奇怪的是,如果我只注释掉第一个 clSetKernelArgs,所有其他似乎都有效。我认为这可能是常量数组的问题,除了它适用于 rand_seeds.
success = clSetKernelArg(solver_kernel, 0, sizeof(cl_float) * 10, bounds);
if(success != CL_SUCCESS)
{
printf("%d\n", success);
exit(1);
}
success = clSetKernelArg(solver_kernel, 1, sizeof(cl_float) * 2, seeds);
if(success != CL_SUCCESS)
{
printf("%d\n", success);
exit(1);
}
success = clSetKernelArg(solver_kernel, 2, sizeof(cl_int), &trials);
if(success != CL_SUCCESS)
{
printf("%d\n", success);
exit(1);
}
success = clSetKernelArg(solver_kernel, 3, sizeof(cl_int), &start_temp);
if(success != CL_SUCCESS)
{
printf("%d\n", success);
exit(1);
}
这是我内核的头文件
__kernel void solver_kernel
(
__constant float bounds[10],
__constant int rand_seeds[2],
int trials,
int start_temp
)
The memory object specified as argument value must be a buffer object (or NULL) if the argument is declared to be a pointer of a built-in or user defined type with the
__global
or__constant
qualifier.
所以你必须先创建一个缓冲区并将其设置为你的内核参数。应该是这样的
cl_mem bounds_buffer = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(cl_float) * 10, bounds, &success);
success = clSetKernelArg(solver_kernel, 0, sizeof(cl_mem), bounds_buffer);
你需要对 rand_seeds
参数做同样的事情,即使你没有在这一行得到错误(可能是因为 sizeof(cl_float) * 2 == sizeof(cl_mem)
偶然,这仍然会产生不正确的结果)。
如果您的缓冲区永远不变,则无需使用缓冲区 + __constant
方式。这是一个替代方案。
实际上有两种在内核中使用常量内存的方法:
- 使用标准缓冲区 +
__constant
标志 - 使用结构参数
首选第一个(因此请使用@Jan 接受的答案),因为您明确说明了您希望如何处理数据。但在实践中,所有的实现都对第二种情况使用常量内存。由于传递给内核的数据是静态的,无论如何都不可修改。
因此,您可以像这样重写内核:
typedef struct float_10 { float f[10];} float_10;
typedef struct int_2 { int i[2];}int_2;
__kernel void solver_kernel
(
float_10 bounds,
int_2 rand_seeds,
int trials,
int start_temp
)
应该有相同的性能。
编辑:因为你需要结构,而不是数组