OpenCL clCreateBuffer()崩溃程序

时间:2016-01-12 21:57:16

标签: c memory buffer opencl

我已将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的尺寸,但是只要我在MATRIX_DIM中放入359就会崩溃。它显示通常的“foo.exe已停止工作”。我知道它必须使用clCreateBuffer()命令执行某些操作,因为如果我从第一个clCreateBuffer()及其下面删除代码,它会运行并终止正常,但只要我添加一个崩溃就会崩溃。

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

我有什么办法可以增加我可以处理的数据量吗?

我的GPU是Radeon Sapphire 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

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

1 个答案:

答案 0 :(得分:0)

主要问题是,你在这些代码行上分配了很多内存,所以,你得到了一个堆栈溢出

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]更改为相应的1D索引[i*MATRIX_DIM][j],例如:

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

编辑:您还必须更新对clCreateBufferclEnqueueReadBuffer的来电。无法再使用sizeof(matrix_name)确定矩阵大小(其中matrix_namea_matb_mat之一,...)。您必须使用sizeof替换每个MATRIX_DIM*MATRIX_DIM*sizeof(*matrix_name)(有4个)。不要忘记matrix_name之前的derefence,例如:

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