Программа OpenCL не выполняется

0

Я немного изменил эту программу для своего понимания, но теперь она не работает. Это мой код:

#include <iostream>
#include "CL/cl.h"
#include <math.h>

using namespace std;
#define MYSIZE 1000

#if defined(cl_khr_fp64) //Khronos extension available
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#define DOUBLE_SUPPORT_AVAILABLE
#elif defined(cl_amd_fp64) //AMD extension available
#pragma OPENCL EXTENSION cl_amd_fp64 : enable
#define DOUBLE_SUPPORT_AVAILABLE
#endif

#ifdef DOUBLE_SUPPORT_AVAILABLE

//double
typedef double myreal;
const char *SOURCE = "\n" \
"__kernel void addArray(__global double *A, __global double *B, __global double *C, const unsigned int size) \n" \
"{                                                                                                           \n" \
    "int i = get_global_id(0);                                                                               \n" \
    "if(i < size)                                                                                            \n" \
        "    C[i] = A[i] + B[i];                                                                             \n" \
"}                                                                                                           \n" \
"\n";

#else

//float
typedef float myreal;
const char *SOURCE = "\n" \
"__kernel void addArray(__global float *A, __global float *B, __global float *C, const unsigned int size) \n" \
"{                                                                                                           \n" \
    "int i = get_global_id(0);                                                                               \n" \
    "if(i < size)                                                                                            \n" \
        "    C[i] = A[i] + B[i];                                                                             \n" \
"}                                                                                                           \n" \
"\n";

#endif

int main(int argc, char *argv[])
{
    int devType = CL_DEVICE_TYPE_GPU;
    unsigned int count = MYSIZE;
    cl_int err;//err returned from API
    size_t global;//global size
    size_t local;//local size
    cl_platform_id platform;
    cl_device_id device;
    cl_context context;
    cl_command_queue commands;
    cl_program program;
    cl_kernel kernel;

    //connect to a compute device
    err = clGetPlatformIDs(1, &platform, NULL);
    if(err != CL_SUCCESS)
    {
        cerr << "ERROR: Could not find a platform" << endl;
        return -1;
    }

    //get a device of the appropriate type
    err = clGetDeviceIDs(platform, devType, 1, &device, NULL);
    if(err != CL_SUCCESS)
    {
        cerr << "ERROR: Could not find a device" << endl;
        return -1;
    }

    //create a context
    context = clCreateContext(0, 1, &device, NULL, NULL, &err);
    if(!context || (err != CL_SUCCESS))
    {
        cerr << "ERROR: Could not create a context" << endl;
        return -1;
    }

    //create a command queue
    commands = clCreateCommandQueue(context, device, 0, &err);
    if(!commands || (err != CL_SUCCESS))
    {
        cerr << "ERROR: Could not create a command queue" << endl;
        return -1;
    }

    //create the compute program from source
    program = clCreateProgramWithSource(context, 1, (const char **) &SOURCE, NULL, &err);
    if(!program || (err != CL_SUCCESS))
    {
        cerr << "ERROR: Could not create a program from source" << endl;
        return -1;
    }

    //build the program executable
    err = clBuildProgram(program, NULL, NULL, NULL, NULL, NULL);
    if(err != CL_SUCCESS)
    {
        size_t len;
        char buffer[2048];
        clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, sizeof(buffer), buffer, &len);

        cerr << "ERROR: Could not build the program executable" << endl;
        cerr << buffer << endl;
        return -1;
    }

    //create the kernel
    kernel = clCreateKernel(program, "addArray", &err);
    if(!kernel || (err != CL_SUCCESS))
    {
        cerr << "Could not create the kernel" << endl;
        return -1;
    }

    myreal *A = new myreal[MYSIZE];
    myreal *B = new myreal[MYSIZE];
    myreal *C = new myreal[MYSIZE];
    for(int i = 0; i < MYSIZE; i++)
    {
        A[i] = sqrt(i);
        B[i] = -sqrt(i);
    }
    unsigned int correct = 0;//correct answers
    cl_mem A_cl;
    cl_mem B_cl;
    cl_mem C_cl;

    //create device memory buffer
    A_cl = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(myreal) * count, NULL, NULL);
    B_cl = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(myreal) * count, NULL, NULL);
    C_cl = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(myreal) * count, NULL, NULL);
    if(!A_cl || !B_cl || !C_cl)
    {
        cerr << "Could not create device memory buffer" << endl;
        return -1;
    }

    //transfer data to device
    err = clEnqueueWriteBuffer(commands, A_cl, CL_TRUE, 0, sizeof(myreal) * count, A, 0, NULL, NULL);
    if(err != CL_SUCCESS)
    {
        cerr << "Could not transfer data to device" << endl;
        return -1;
    }

    err = clEnqueueWriteBuffer(commands, B_cl, CL_TRUE, 0, sizeof(myreal) * count, B, 0, NULL, NULL);
    if(err != CL_SUCCESS)
    {
        cerr << "Could not transfer data to device" << endl;
        return -1;
    }

    //set the arguments to the compute kernel
    err = 0;
    err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &A_cl);
    err |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &B_cl);
    err |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &C_cl);
    err |= clSetKernelArg(kernel, 3, sizeof(unsigned int), &count);
    if(err != CL_SUCCESS)
    {
        cerr << "Could not set args for kernel" << endl;
        return -1;
    }

    //get max work group size
    err = clGetKernelWorkGroupInfo(kernel, device, CL_KERNEL_WORK_GROUP_SIZE, sizeof(local), &local, NULL);
    if(err != CL_SUCCESS)
    {
        cerr << "Could not get the kernel work group size" << endl;
        return -1;
    }

    //execute the kernel using max work group size
    global = count;
    err = clEnqueueNDRangeKernel(commands, kernel, 1, NULL, &global, &local, 0, NULL, NULL);
    if(err != CL_SUCCESS)
    {
        cerr << "Could not enqueue the kernel for execution: " << err << endl;
        return -1;
    }

    //wait for all commands to finish
    clFinish(commands);

    //read back the results to C
    err = clEnqueueReadBuffer(commands, C_cl, CL_TRUE, 0, sizeof(myreal) * count, C, 0, NULL, NULL);
    if(err != CL_SUCCESS)
    {
        cerr << "Could not read data from C" << endl;
        return -1;
    }

    //validate the results
    correct = 0;
    myreal check = 0;
    for(int i = 0; i < MYSIZE; i++)
    {
        check = A[i] + B[i] - C[i];
        if((check < 1e-14) && (check > -1e-14))
            correct++;
    }

    cout << "Computed " << correct << " correct results with " << ((correct / MYSIZE) * 100) << "% success rate!" << endl;
    delete[] A;
    delete[] B;
    delete[] C;

    clReleaseMemObject(A_cl);
    clReleaseMemObject(B_cl);
    clReleaseMemObject(C_cl);
    clReleaseProgram(program);
    clReleaseKernel(kernel);
    clReleaseCommandQueue(commands);
    clReleaseContext(context);

    return 0;

    return 0;
}

Выход, который я получаю:

Could not enqueue the kernel for execution: -54

Что означает эта ошибка -54?

Я использую MinGW 4.4 32-битный компилятор на Windows7 64 бит. Мой GPU - ATI Radeon 7670m с драйверами OpenCL 1.1. Я использую APP SDK 2.9 для 64 бит.

Теги:
opencl

1 ответ

3
Лучший ответ

В Khronos ссылка cl.h, -54 означает CL_INVALID_WORK_GROUP_SIZE, что вполне самоочевидно.

Совет. Если у вас нет привязки к размеру рабочей группы, вы можете передать NULL вместо local и позволить функции enqueue определить ее для вас.

  • 0
    Спасибо, это сработало! Я только начал изучать OpenCL, поэтому не знал, что ошибки определены в cl.h. Но я до сих пор не понимаю, почему это не удалось в первую очередь? clGetKernelWorkGroupInfo устанавливает для локального значения значение 256. Тогда почему это не удалось?
  • 3
    Размер 1000 нельзя разделить на группы по 256. 1000/256 = 4.xx Планировщик не знает, как обрабатывать оставшиеся работы. Если вы не установите такой размер, планировщик, вероятно, выберет размер 250.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню