2015-11-26 9 views
0

Я пытаюсь запустить мои первые коды в OpenCL и использую книгу OpenCL в Action. Вот код для одного образца книги. Этот код не запускается и, по-видимому, не удается установить аргументы ядра. Когда я запускаю код, печатный вывод: «Невозможно установить буфер как аргумент ядра». Код хорошо работает на AMD, но он не работает, когда я запускаю его на платформе NVIDIA. Любые идеи, почему код работает неправильно?Настройка аргументов ядра в OpenCL

#define _CRT_SECURE_NO_WARNINGS 
#define PROGRAM_FILE "blank.cl" 
#define KERNEL_FUNC "blank" 

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <string.h> 

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

/* Find a GPU or CPU 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 device */ 
    err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &dev, NULL); 
    if (err == CL_DEVICE_NOT_FOUND) { 
     err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_CPU, 1, &dev, NULL); 
    } 
    if (err < 0) { 
     perror("Couldn't access any devices"); 
     exit(1); 
    } 

    return dev; 
} 

/* Create program from a file and compile it */ 
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() { 

    /* OpenCL data structures */ 
    cl_device_id device; 
    cl_context context; 
    cl_command_queue queue; 
    cl_program program; 
    cl_kernel kernel; 
    cl_int i, j, err; 

    /* Data and buffers */ 
    float data_one[100], data_two[100], result_array[100]; 
    cl_mem buffer_one, buffer_two; 
    void* mapped_memory; 

    /* Initialize arrays */ 
    for (i = 0; i<100; i++) { 
     data_one[i] = 1.0f*i; 
     data_two[i] = -1.0f*i; 
     result_array[i] = 0.0f; 
    } 

    /* 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 and create the kernel */ 
    program = build_program(context, device, PROGRAM_FILE); 
    kernel = clCreateKernel(program, KERNEL_FUNC, &err); 
    if (err < 0) { 
     perror("Couldn't create a kernel"); 
     exit(1); 
    }; 

    /* Create buffers */ 
    buffer_one = clCreateBuffer(context, CL_MEM_READ_WRITE | 
     CL_MEM_COPY_HOST_PTR, sizeof(data_one), data_one, &err); 
    if (err < 0) { 
     perror("Couldn't create a buffer object"); 
     exit(1); 
    } 
    buffer_two = clCreateBuffer(context, CL_MEM_READ_WRITE | 
     CL_MEM_COPY_HOST_PTR, sizeof(data_two), data_two, NULL); 

    /* Set buffers as arguments to the kernel */ 
    err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &buffer_one); 
    err |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &buffer_two); 
    if (err < 0) { 
     perror("Couldn't set the buffer as the kernel argument"); 
     exit(1); 
    } 

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

    /* Enqueue kernel */ 
    err = clEnqueueTask(queue, kernel, 0, NULL, NULL); 
    if (err < 0) { 
     perror("Couldn't enqueue the kernel"); 
     exit(1); 
    } 

    /* Enqueue command to copy buffer one to buffer two */ 
    err = clEnqueueCopyBuffer(queue, buffer_one, buffer_two, 0, 0, 
     sizeof(data_one), 0, NULL, NULL); 
    if (err < 0) { 
     perror("Couldn't perform the buffer copy"); 
     exit(1); 
    } 

    /* Enqueue command to map buffer two to host memory */ 
    mapped_memory = clEnqueueMapBuffer(queue, buffer_two, CL_TRUE, 
     CL_MAP_READ, 0, sizeof(data_two), 0, NULL, NULL, &err); 
    if (err < 0) { 
     perror("Couldn't map the buffer to host memory"); 
     exit(1); 
    } 

    /* Transfer memory and unmap the buffer */ 
    memcpy(result_array, mapped_memory, sizeof(data_two)); 
    err = clEnqueueUnmapMemObject(queue, buffer_two, mapped_memory, 
     0, NULL, NULL); 
    if (err < 0) { 
     perror("Couldn't unmap the buffer"); 
     exit(1); 
    } 

    /* Display updated buffer */ 
    for (i = 0; i<10; i++) { 
     for (j = 0; j<10; j++) { 
      printf("%6.1f", result_array[j + i * 10]); 
     } 
     printf("\n"); 
    } 

    /* Deallocate resources */ 
    clReleaseMemObject(buffer_one); 
    clReleaseMemObject(buffer_two); 
    clReleaseKernel(kernel); 
    clReleaseCommandQueue(queue); 
    clReleaseProgram(program); 
    clReleaseContext(context); 

    return 0; 
} 

и вот ядро ​​в отдельном файле blank.cl:

__kernel void blank(__global float *a, __global float *b) { 
} 
+0

А где blank.cl? – doqtor

+0

Извините, я забыл об этом. Я добавил ядро ​​в конце вопроса. – mfaieghi

ответ

0

Я только понял, что проблема была из-за неправильного объявления ядра в отдельном файле * .cl. Код работает правильно. У меня просто было неправильное ядро!

1

Я подозреваю, что вы запустить его на Windows. Этот код не учитывает Windows EOL, который имеет 2 символа: '\ r \ n', а последний символ после чтения ядра из файла - '\ r', который компилятор OpenCL не может переваривать.

Есть 2 варианта. Вы можете либо преобразовать файл blank.cl в формат unix, либо добавить program_buffer[program_size-1] = '\0'; после program_buffer[program_size] = '\0';.

+0

Я запускаю его на Windows. Когда я запускаю его на Windows 10 с устройством AMD, он работает правильно, но он не работает в Windows 10 на NVIDIA. – mfaieghi

+1

Не все компиляторы одинаковы, с «\ r» может быть и не так. Я тестировал его с помощью Nvidia в Windows 7, и мне потребовалось одно из предложенных мной изменений. Ты это пробовал? – doqtor

+1

Если это действительно причина, я бы рекомендовал встраивать ядро ​​cl в код в виде строки и попробовать. Вы можете сделать это с помощью: 'const char * kern = R" [#include "mykern.cl"] ";' – DarkZeros

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