Nvidia GEForce 上的 OpenCL 示例程序问题
Posted
技术标签:
【中文标题】Nvidia GEForce 上的 OpenCL 示例程序问题【英文标题】:OpenCL Sample Program issue on Nvidia GEForce 【发布时间】:2014-07-25 08:01:48 【问题描述】:我是 OpenCL 的新手,并尝试运行来自矩阵向量乘法教程之一的示例代码。有两个文件,一个是启动内核的 matvec.c,另一个是保存内核函数的 matvec.cl。 程序如下:
#define PROGRAM_FILE "matvec.cl"
#define KERNEL_FUNC "matvec_mult"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#ifdef MAC
#include <OpenCL/cl.h>
#else
#include <CL/cl.h>
#endif
int main()
cl_platform_id platform;
cl_device_id device;
cl_context context;
cl_command_queue queue;
cl_int i, err;
cl_program program;
FILE *program_handle;
char *program_buffer, *program_log;
size_t program_size, log_size;
cl_kernel kernel;
size_t work_units_per_kernel;
float mat[16], vec[4], result[4];
float correct[4] = 0.0f, 0.0f, 0.0f, 0.0f;
cl_mem mat_buff, vec_buff, res_buff;
for(i=0; i<16; i++)
mat[i] = i * 2.0f;
for(i=0; i<4; i++)
vec[i] = i * 3.0f;
correct[0] += mat[i] * vec[i];
correct[1] += mat[i+4] * vec[i];
correct[2] += mat[i+8] * vec[i];
correct[3] += mat[i+12] * vec[i];
clGetPlatformIDs(1, &platform, NULL);
clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1,
&device, NULL);
context = clCreateContext(NULL, 1, &device, NULL,
NULL, &err);
program_handle = fopen(PROGRAM_FILE, "r");
fseek(program_handle, 0, SEEK_END);
program_size = ftell(program_handle);
rewind(program_handle);
program_buffer = (char*)malloc(program_size + 1);
program_buffer[program_size] = '\0';
fread(program_buffer, sizeof(char), program_size,
program_handle);
fclose(program_handle);
program = clCreateProgramWithSource(context, 1,
(const char**)&program_buffer, &program_size, &err);
free(program_buffer);
clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
kernel = clCreateKernel(program, KERNEL_FUNC, &err);
queue = clCreateCommandQueue(context, device, 0, &err);
mat_buff = clCreateBuffer(context, CL_MEM_READ_ONLY |
CL_MEM_COPY_HOST_PTR, sizeof(float)*16, mat, &err);
vec_buff = clCreateBuffer(context, CL_MEM_READ_ONLY |
CL_MEM_COPY_HOST_PTR, sizeof(float)*4, vec, &err);
res_buff = clCreateBuffer(context, CL_MEM_WRITE_ONLY,
sizeof(float)*4, NULL, &err);
clSetKernelArg(kernel, 0, sizeof(cl_mem), &mat_buff);
clSetKernelArg(kernel, 1, sizeof(cl_mem), &vec_buff);
clSetKernelArg(kernel, 2, sizeof(cl_mem), &res_buff);
work_units_per_kernel = 4;
clEnqueueNDRangeKernel(queue, kernel, 1, NULL,
&work_units_per_kernel, NULL, 0, NULL, NULL);
clEnqueueReadBuffer(queue, res_buff, CL_TRUE, 0,
sizeof(float)*4, result, 0, NULL, NULL);
if((result[0] == correct[0]) && (result[1] == correct[1])
&& (result[2] == correct[2]) && (result[3] == correct[3]))
printf("Matrix-vector multiplication successful.\n");
else
printf("Matrix-vector multiplication unsuccessful.\n");
clReleaseMemObject(mat_buff);
clReleaseMemObject(vec_buff);
clReleaseMemObject(res_buff);
clReleaseKernel(kernel);
clReleaseCommandQueue(queue);
clReleaseProgram(program);
clReleaseContext(context);
system("pause");
return 0;
内核函数如下:
#include <CL\cl.h>
__kernel void matvec_mult(__global float4* matrix, __global float4* vector,__global
float* result)
int i = get_global_id(0);
result[i] = dot(matrix[i], vector[0]);
当我运行此示例代码时,它显示“矩阵向量乘法不成功”。我正在使用 Visual Studio 2010 并尝试调试代码。由简单的“for 循环”生成的正确变量的值与内核函数生成的结果变量不匹配。有人可以帮我解决这个问题并指出我哪里出错了,我无法确认是代码问题还是系统问题。提前感谢您的帮助。
其中一个错误:“IntelliSense:标识符“get_global_id”未定义”。
【问题讨论】:
您没有检查来自任何 OpenCL API 函数调用的错误代码。这些函数中的任何一个都可能返回错误——我们不可能猜出它是哪一个。请在您的代码中添加一些错误检查,重新运行程序,然后让我们知道哪个函数失败(以及它报告的错误代码)。 @Jprice,我试图检查编译器提到的任何错误。 matvec.c 中没有特别的错误,但是,我收到 matvec.cl 中内核函数的未定义智能感知错误。它说,__kernel undefined、__global undefined、matrix、vector、dot & get_global_id 也是 undefined。但即使有这些错误,它也可以编译。我无法追踪此问题的确切原因。此外,在调试时它只给了我内核的地址,而我在 Visual Studio 中调试 OpenCL 代码的经验并不多。 OpenCL API 函数返回代码或设置代码值,例如:clCreateKernel(program, KERNEL_FUNC, &err) 或:err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &mat_buff)。每次检查err值,必须是CL_SUCCESS。 @Roman,感谢您的回复。我已按照您的说明检查了代码。所有 API 函数调用都会生成一个值“0”。唯一不生成“0”的函数调用是 kernel = clCreateKernel(program, KERNEL_FUNC, &err);它生成“-45”。你能帮忙解决这个问题吗? 【参考方案1】:错误代码在<CL/cl.h>
中定义
错误 -45 是 CL_INVALID_PROGRAM_EXECUTABLE。根据Khronos,这意味着“没有成功构建的程序可执行文件”。在您的内核源代码的第一个原始内容中包含不必要的内容。删除它:
#include <CL\cl.h>
OpenCL C 不允许包含常规 C/C++ 标头。只能包含符合 OpenCL C 标准的源文件。
一般来说,为了查看 OpenCL 编译器会产生什么错误,在构建内核时,包含这样的源代码:(我从现有代码中获取了 sn-p,因此检查变量名称等)
cl_int ret;
program = clCreateProgramWithSource(
context, 1, (const char**)&src_file, NULL, &ret);
if(ret != CL_SUCCESS)
fprintf(stderr, "Error with code %d happened.\n", ret);
// Warnings will be treated like errors, this is useful for debug
char build_params[] = "-Werror";
ret = clBuildProgram(program, 0, NULL, build_params, NULL, NULL);
if (ret != CL_SUCCESS)
size_t len = 0;
char *buffer;
clGetProgramBuildInfo(program,
device_id, CL_PROGRAM_BUILD_LOG, 0, NULL, &len);
buffer = calloc(len, sizeof(char));
clGetProgramBuildInfo(program,
device_id, CL_PROGRAM_BUILD_LOG, len, buffer, NULL);
fprintf(stderr, "%s\n", buffer);
free(buffer);
【讨论】:
感谢您的回复。是的,您的代码能够指出问题所在。这是错误:前端编译器构建失败。您对这个问题有什么建议吗? 这意味着 OpenCL 编译器前端无法将 OpenCL C 代码处理为中间表示。通常这是由语法错误引起的。您是否删除了内核文件中包含的标头? 再次感谢。我的 matvec.cl 文件中没有包含任何标题。我已经删除了“#include以上是关于Nvidia GEForce 上的 OpenCL 示例程序问题的主要内容,如果未能解决你的问题,请参考以下文章
在 NVIDIA GEFORCE GTX 1050 上下载适用于 windows 10 的 openCL 1.2 [关闭]