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】:

错误代码在&lt;CL/cl.h&gt;中定义

错误 -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 ”。它只是这段代码 __kernel void matvec_mult(__global float4* matrix, __global float4* vector,__global float* result) int i = get_global_id(0);结果[i] = 点(矩阵[i],向量[0]); 我在我的 PC 上测试了你的代码,结果很好(不过,我有 Radeon GPU)。检查您的 OpenCL SDK 和项目设置,看起来您的问题与代码本身无关。 查看代码,位于github.com/RomanArzumanyan/SCOW。您需要文件platforms.h 和platforms.c。里面的功能正是你所需要的。

以上是关于Nvidia GEForce 上的 OpenCL 示例程序问题的主要内容,如果未能解决你的问题,请参考以下文章

在 NVIDIA GEFORCE GTX 1050 上下载适用于 windows 10 的 openCL 1.2 [关闭]

无法在 GeForce 540M 上运行 CUDA 或 OpenCL

如何创建 NVIDIA OpenCL 项目

NVIDIA 硬件的 OpenCL 1.2 何时可用?

nvidia390对应的cuda

Nvidia Tesla 上的 OpenCL:未找到任何平台