2016-01-12 4 views
2

Я принял программирование OpenCL как часть университетского проекта, и у меня есть небольшая проблема, когда я пытаюсь ввести данные в буферный объект во время процедуры clCreateBuffer().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 показывает количество 512 МБ доступной памяти, а данные, которые я пытаюсь передать, намного меньше.

Есть ли что-нибудь, что я могу сделать, чтобы увеличить количество данных, которые я могу обработать?

Мой GPU является Radeon Sapphire HD5770

EDIT: После того, как предложение в комментариях, я побежал отладчик показал следующее сообщение:

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 

Я действительно не знаю, что это означает, что, хотя. Есть идеи?

+0

Вы использовали отладчик, чтобы убедиться, что clCreateBuffer является то, что выходит из строя? – immibis

+0

@immibis Я использовал отладчик, и вы были правы, проблема в том, что проблема заключается в create_device() в строке 26. Вот данные: Программный сигнал SIGSEGV, ошибка сегментации. В amdocl! _aclHsaLoader() (C: \ WINDOWS \ SysWOW64 \ amdocl.dll) # 15 0x00401355 в create_device() в C: \ test \ testcl.c: 26 C: \ test \ testcl.c: 26: 503: beg: 0x401355 – kmentis

ответ

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]; 

В моем тесте здесь, исполнение Ждут» t даже ввел метод 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; 

EDIT: Вы должны также обновить вызовы clCreateBuffer унд clEnqueueReadBuffer. Размер матрицы не может быть определен с sizeof(matrix_name) (где matrix_name является одним из a_mat, b_mat, ...). Вы должны заменить каждый такой sizeof (их 4) с MATRIX_DIM*MATRIX_DIM*sizeof(*matrix_name). Не забывайте derefence перед 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); 

(Конец Edit).

Не забудьте освободить данные-буфера в конце:

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 
+0

Благодарим вас за ответ. Я изменил все, что вы предлагали, но теперь появилось еще 2 проблемы. Во-первых, проверка результатов не выполняется. Я пробовал статические числа (1 + 1), и кажется, что только первый элемент матрицы возврата (c_mat) обрабатывается GPU, остальные - все 0. Вторая проблема заключается в том, что теперь даже с матрицей 50x50 драйверы AMD потерпеть неудачу. – kmentis

+0

@kmentis Извините, я забыл опубликовать необходимые исправления вызовов 'sizeof'. Я отредактировал свой ответ. Теперь он также должен работать на вас. –

+0

Хорошо! Теперь он отлично работает для гораздо большего количества точек данных! Спасибо вам большое за ваше время! :) – kmentis

Смежные вопросы