gpt4 book ai didi

c - OpenCL clCreateBuffer() 使程序崩溃

转载 作者:太空宇宙 更新时间:2023-11-04 00:03:09 25 4
gpt4 key购买 nike

我已经将 OpenCL 编程作为大学项目的一部分,当我尝试在 clCreateBuffer() 例程期间将数据输入到缓冲区对象时遇到了一些问题。

该程序是一个简单的二维矩阵加法。代码如下:

#define _CRT_SECURE_NO_WARNINGS
#define PROGRAM_FILE "add_kernel.cl"
#define ADD_FUNC "add_matrix"
#define MATRIX_DIM 256

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#ifdef MAC
#include <OpenCL/cl.h>
#else
#include <CL/cl.h>
#endif

/* Find a GPU associated with the first available platform */
cl_device_id create_device() {

cl_platform_id platform;
cl_device_id dev;
int err;

/* Identify a platform */
err = clGetPlatformIDs(1, &platform, NULL);
if(err < 0) {
perror("Couldn't identify a platform");
exit(1);
}

/* Access a GPU */
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &dev, NULL);
if(err < 0) {
perror("Couldn't access any GPU type");
exit(1);
}

return dev;
}

cl_program build_program(cl_context ctx, cl_device_id dev, const char* filename) {

cl_program program;
FILE *program_handle;
char *program_buffer, *program_log;
size_t program_size, log_size;
int err;

/* Read program file and place content into buffer */
program_handle = fopen(filename, "r");
if(program_handle == NULL) {
perror("Couldn't find the program file");
exit(1);
}
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);

/* Create program from file */
program = clCreateProgramWithSource(ctx, 1,
(const char**)&program_buffer, &program_size, &err);
if(err < 0) {
perror("Couldn't create the program");
exit(1);
}
free(program_buffer);

/* Build program */
err = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
if(err < 0) {

/* Find size of log and print to std output */
clGetProgramBuildInfo(program, dev, CL_PROGRAM_BUILD_LOG,
0, NULL, &log_size);
program_log = (char*) malloc(log_size + 1);
program_log[log_size] = '\0';
clGetProgramBuildInfo(program, dev, CL_PROGRAM_BUILD_LOG,
log_size + 1, program_log, NULL);
printf("%s\n", program_log);
free(program_log);
exit(1);
}
return program;
}

int main(){

/* Host/device data structures */
cl_device_id device;
cl_context context;
cl_command_queue queue;
cl_program program;
cl_kernel add_kernel;
size_t global_size;
cl_ulong mem_size;
cl_int i, j, err, check;

/* Data and buffers */
cl_uint matrix_dim;
float a_mat[MATRIX_DIM][MATRIX_DIM], b_mat[MATRIX_DIM][MATRIX_DIM],
c_mat[MATRIX_DIM][MATRIX_DIM], check_mat[MATRIX_DIM][MATRIX_DIM];
cl_mem a_buffer, b_buffer, c_buffer;

/* Initialize A, B, and check matrices */
srand((unsigned int)time(0));
for(i=0; i<MATRIX_DIM; i++) {
for(j=0; j<MATRIX_DIM; j++) {
a_mat[i][j] = (float)rand()/RAND_MAX;
}
}
srand((unsigned int)time(0));
for(i=0; i<MATRIX_DIM; i++) {
for(j=0; j<MATRIX_DIM; j++) {
b_mat[i][j] = (float)rand()/RAND_MAX;
check_mat[i][j] = 0.0f;
}
}
for(i=0; i<MATRIX_DIM; i++) {
for(j=0; j<MATRIX_DIM; j++) {
check_mat[i][j] += a_mat[i][j] + b_mat[i][j];
}
}

/* Create a device and context */
device = create_device();
context = clCreateContext(NULL, 1, &device, NULL, NULL, &err);
if(err < 0) {
perror("Couldn't create a context");
exit(1);
}

/* Build the program */
program = build_program(context, device, PROGRAM_FILE);

add_kernel = clCreateKernel(program, ADD_FUNC, &err);
if(err < 0) {
perror("Couldn't create a kernel");
exit(1);
};

/* Create buffers */
a_buffer = clCreateBuffer(context,
CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
sizeof(a_mat), a_mat, &err);
if(err < 0) {
perror("Couldn't create buffer A");
exit(1);
};
b_buffer = clCreateBuffer(context,
CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
sizeof(b_mat), b_mat, &err);
if(err < 0) {
perror("Couldn't create buffer B");
exit(1);
};
c_buffer = clCreateBuffer(context, CL_MEM_WRITE_ONLY,
sizeof(c_mat), NULL, &err);
if(err < 0) {
perror("Couldn't create buffer C");
exit(1);
};

/* Create a command queue */
queue = clCreateCommandQueue(context, device, 0, &err);
if(err < 0) {
perror("Couldn't create a command queue");
exit(1);
};

/* Create arguments for multiplication kernel */
err = clSetKernelArg(add_kernel, 0, sizeof(a_buffer), &a_buffer);
err |= clSetKernelArg(add_kernel, 1, sizeof(b_buffer), &b_buffer);
err |= clSetKernelArg(add_kernel, 2, sizeof(c_buffer), &c_buffer);
global_size = MATRIX_DIM * MATRIX_DIM;

//printf("%lu\n", global_size);

err = clEnqueueNDRangeKernel(queue, add_kernel, 1, NULL, &global_size,
NULL, 0, NULL, NULL);
if(err < 0) {
perror("Couldn't enqueue the addition kernel");
exit(1);
}

/* Read output buffer */
err = clEnqueueReadBuffer(queue, c_buffer, CL_TRUE, 0,
sizeof(c_mat), c_mat, 0, NULL, NULL);
if(err < 0) {
perror("Couldn't read the buffer");
exit(1);
}

/* Check result */
check = 1;
for(i=0; i<MATRIX_DIM; i++) {
for(j=0; j<MATRIX_DIM; j++) {
if(c_mat[i][j] != check_mat[i][j]){
check = 0;
break;
}
}
}

if(check)
printf("Addition check succeeded.\n");
else
printf("Addition check failed.\n");





/* Deallocate resources */
clReleaseMemObject(a_buffer);
clReleaseMemObject(b_buffer);
clReleaseMemObject(c_buffer);
clReleaseKernel(add_kernel);
clReleaseCommandQueue(queue);
clReleaseProgram(program);
clReleaseContext(context);
return 0;
}

内核代码如下:

__kernel void add_matrix(__global float* matrix_a,
__global float* matrix_b,
__global float* result) {

int i = get_global_id(0);
result[i] = matrix_a[i] + matrix_b[i];
}

现在,它适用于高达 358x358 的尺寸,但只要我将 359 放入 MATRIX_DIM,它就会崩溃。它显示通常的“foo.exe 已停止工作”。我知道它必须用 clCreateBuffer() 命令做一些事情,因为如果我从第一个 clCreateBuffer() 和下面的代码中删除代码,它会正常运行和终止,但只要我添加一个它就会崩溃。

CL_DEVICE_MAX_MEM_ALLOC_SIZE 选项显示了 512MB 的可用内存,而我尝试传递的数据远少于此。

我可以做些什么来增加我可以处理的数据量吗?

我的 GPU 是 Radeon 蓝 gem HD5770

编辑:在评论中提出建议后,我运行了产生以下消息的调试器:

Program received signal SIGSEGV, Segmentation fault.
In amdocl!_aclHsaLoader () (C:\WINDOWS\SysWOW64\amdocl.dll)
#15 0x00401355 in create_device () at C:\test\testcl.c:26
C:\test\testcl.c:26:503:beg:0x401355

虽然我真的不确定这意味着什么。有什么想法吗?

最佳答案

主要问题是,您在这些代码行的堆栈上分配了很多内存,因此,您遇到了堆栈溢出:

float a_mat[MATRIX_DIM][MATRIX_DIM], b_mat[MATRIX_DIM][MATRIX_DIM],
c_mat[MATRIX_DIM][MATRIX_DIM], check_mat[MATRIX_DIM][MATRIX_DIM];

在我这里的测试中,执行甚至没有进入main方法。您必须使用以下方法在堆上分配这些矩阵:

float *a_mat = calloc(MATRIX_DIM*MATRIX_DIM, sizeof(*a_mat));
float *b_mat = calloc(MATRIX_DIM*MATRIX_DIM, sizeof(*b_mat));
float *c_mat = calloc(MATRIX_DIM*MATRIX_DIM, sizeof(*c_mat));
float *check_mat = calloc(MATRIX_DIM*MATRIX_DIM, sizeof(*check_mat));

但是现在,每个矩阵只有一个一维 (1D) 数据缓冲区,因此,您必须更改每个 2D 索引[i][j] 到相应的一维索引 [i*MATRIX_DIM][j],例如:

a_mat[i*MATRIX_DIM+j] = (float)rand()/RAND_MAX;

编辑:您还必须更新对 clCreateBufferclEnqueueReadBuffer 的调用。矩阵大小不能再用 sizeof(matrix_name) 确定(其中 matrix_namea_matb_mat 之一, ...)。您必须用 MATRIX_DIM*MATRIX_DIM*sizeof(*matrix_name) 替换每个这样的 sizeof(有 4 个)。不要忘记在 matrix_name 之前取消引用,例如:

a_buffer = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
MATRIX_DIM*MATRIX_DIM*sizeof(*a_mat), a_mat, &err);

(编辑结束)。

不要忘记在最后释放数据缓冲区:

free(a_mat);
free(b_mat);
free(c_mat);
free(check_mat);

为了让内核运行,我什至不得不修复内核程序的读取。 ftell 的返回值总是有点太大。实际字节数由 fread 返回。因此,更改这些行

program_buffer[program_size] = '\0';
fread(program_buffer, sizeof(char), program_size, program_handle);

program_size  = fread(program_buffer, sizeof(char), program_size, program_handle); // changed
program_buffer[program_size] = '\0'; // moved here

关于c - OpenCL clCreateBuffer() 使程序崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34754528/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com