clBuildProgram failed with error: Failed to build program executable

clBuildProgram failed with error: Failed to build program executable

我是 OpenCL 的初学者。我试图构建一个简单的应用程序,只需添加 2 个向量即可获得结果。这是我的以下主机代码

#define USE_PLATFORM 0
#define USE_DEVICE 2
#define DATA_SIZE 1024

#define USE_KERNEL_PATH "/Users/huangxin/Documents/August13Programming/FirstEGOpenCL/FirstEGOpenCL/kernel.cl"

using namespace std;

int main(int argc, const char * argv[]) {
    int err;
    cl_uint numPlatforms;
    cl_uint numDevices;
    cl_command_queue command;
    size_t global;

    //Query the number of platforms supported.
    err = clGetPlatformIDs(0, NULL, &numPlatforms);
    if (err != CL_SUCCESS || USE_PLATFORM >= numPlatforms)
    {
        printf("Error at: clGetPlatformIDs(querying platforms count failed):\n");
        exit(-1);
    }

    //Get all platforms.
    vector<cl_platform_id> platforms(numPlatforms);
    err = clGetPlatformIDs(numPlatforms, &platforms[0], &numPlatforms);
    if (err != CL_SUCCESS)
    {
        printf("Error at: clGetPlatformIDs(getting all platforms failed):\n");
        exit(-1);
    }

    //Query the number of devices supported by the platform spicified.
    err = clGetDeviceIDs(platforms[USE_PLATFORM], CL_DEVICE_TYPE_ALL, 0, NULL, &numDevices);
    if (err != CL_SUCCESS || USE_PLATFORM >= numDevices)
    {
        printf("Error at: clGetDeviceIDs(querying devices count failed):\n");
        exit(-1);
    }

    //Get all devices.
    vector<cl_device_id> devices(numDevices);
    err=clGetDeviceIDs(platforms[USE_PLATFORM], CL_DEVICE_TYPE_ALL, numDevices, &devices[0], &numDevices);
    if (err != CL_SUCCESS)
    {
        printf("Error at: clGetDeviceIDs(getting all devices failed):\n");
        exit(-1);
    }


    //Get device infomation.
    char deviceInfo[1024];
    //get device max work item dimensions.
    size_t maxItemSize[3];
    clGetDeviceInfo(devices[USE_DEVICE], CL_DEVICE_NAME, sizeof(deviceInfo)*1024, deviceInfo, NULL);
    clGetDeviceInfo(devices[USE_DEVICE], CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(size_t)*3, maxItemSize, NULL);
    cout << "Device selected: " << deviceInfo << endl;
    cout << "Max item size: " << maxItemSize[0] << "," << maxItemSize[1] << ","<< maxItemSize[2] << endl;

    //Set property with certain platform
    cl_context_properties prop[] = {CL_CONTEXT_PLATFORM, reinterpret_cast<cl_context_properties>(platforms[USE_PLATFORM]), 0};

    //create context with certain property.
    cl_context context = clCreateContextFromType(prop, CL_DEVICE_TYPE_ALL, NULL, NULL, &err);
    if (err != CL_SUCCESS)
    {
        printf("Error at: clCreateContextFromType(get context failed):\n");
        exit(-1);
    }

    //create command queue using selected device and context.
    command = clCreateCommandQueue(context, devices[USE_DEVICE], 0, NULL);

    //create program with specified kernel source.
    const char *kernelSource = getKernelSource(USE_KERNEL_PATH);
    cl_program program = clCreateProgramWithSource(context, 1, &kernelSource, 0, &err);
    if (err != CL_SUCCESS)
    {
        printf("Error at: clCreateProgramWithSource(get program failed):\n");
        exit(-1);
    }

    //since OpenCL is a dynamic-compile architechture, we need to build the program.
    err = clBuildProgram(program, 0, 0, 0, 0, 0);
    if (err != CL_SUCCESS)
    {
        cout << err << endl;
        size_t len;
        char buffer[2048];

        printf("Error: Failed to build program executable!\n");
        clGetProgramBuildInfo(program, devices[USE_DEVICE], CL_PROGRAM_BUILD_LOG, sizeof(buffer), buffer, &len);
        printf("%s\n", buffer);
        exit(1);
    }

    //kernel是OpenCL中对执行在一个最小粒度的compute item上的代码及参数的抽象
    //create the kernel function using the built program.
    cl_kernel adder = clCreateKernel(program, "adder", &err);
    if (err != CL_SUCCESS)
    {
        printf("Error at: clCreateKernel(get kernel function failed):\n");
        exit(-1);
    }

    //create the vector of input random data.
    vector<float> inA(DATA_SIZE), inB(DATA_SIZE);
    for(int i = 0; i < DATA_SIZE; i++) {
        inA[i] = (float)(random() % DATA_SIZE) / 1000;
        inB[i] = (float)(random() % DATA_SIZE) / 1000;
    }

    //create the read-only device mem using specified context, that is to copy the host mem to the device mem.
    cl_mem cl_a = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(cl_float) * DATA_SIZE, &inA[0], NULL);
    cl_mem cl_b = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(cl_float) * DATA_SIZE, &inB[0], NULL);
    //create the result mem.
    cl_mem cl_res = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(cl_float) * DATA_SIZE, NULL, NULL);

    //setting up the arguement of kernel memory
    clSetKernelArg(adder, 0, sizeof(cl_mem), &cl_a);
    clSetKernelArg(adder, 1, sizeof(cl_mem), &cl_b);
    clSetKernelArg(adder, 2, sizeof(cl_mem), &cl_res);

    START_CHECK_RUNNING_TIME
    //enqueue the kernel into the specified command(#TODO:come back later to check the remaining arguement.
    global = DATA_SIZE;
    err = clEnqueueNDRangeKernel(command, adder, 1, 0, &global, 0, 0, 0, 0);
    if (err != CL_SUCCESS)
    {
        printf("Error at: clEnqueueNDRangeKernel(enqueue kernel failed):\n");
        exit(-1);
    }

    printf("*****************FLAG***************");

    //copy the results from the kernel into the host(CPU).
    vector<float> res(DATA_SIZE);
     err = clEnqueueReadBuffer(command, cl_res, CL_TRUE, 0, sizeof(float) * DATA_SIZE, &res[0], 0, 0, 0);
    END_CHECK_RUNNING_TIME

    //check the number of right compute.
    int cnt = 0;
    for (int i = 0; i < res.size(); i++) {
        cnt += (res[i] == inA[i] + inB[i] ? 1 : 0);
    }
    cout << "Computed " << res.size() << " values\n";
    cout << "Correct values:(" << cnt << "/" << res.size() << "),correct rate:" << (float)cnt / res.size() * 100 << "%" << endl;

    gettimeofday(&sTime, NULL);
    for (int i = 0; i < res.size(); i++) {
        for (int j = 0; j < 10000; j++)
            res[i] = inA[i] + inB[i];
    }
    gettimeofday(&eTime, NULL);timeuse = 1000000 * ( eTime.tv_sec - sTime.tv_sec ) + eTime.tv_usec -sTime.tv_usec; printf("Running time: %fs\n", (double)timeuse/(1000000));

    //cleaning up the variables.
    clReleaseKernel(adder);
    clReleaseProgram(program);
    clReleaseMemObject(cl_a);
    clReleaseMemObject(cl_b);
    clReleaseMemObject(cl_res);
    clReleaseCommandQueue(command);
    clReleaseContext(context);
    return 0;
}

代码有点长,但确实是在做简单的事情。这是我的内核代码

kernel void adder(global const float* a, global const float* b, global float* result)
{
    size_t idx = get_global_id(0);
    for (int i = 0; i < 10000; i++)
        result[idx] = a[idx] +b[idx];
}

我得到了以下结果:

Device selected: GeForce GT 650M
-11
Error: Failed to build program executable!
No kernels or only kernel prototypes found.

我不太明白"No kernels or only kernel prototypes found."是什么意思,如果我使用第一个设备(CPU)或第二个设备(HD Graphics 4000),运行相同的代码真的很奇怪完美。

我想知道哪里出了问题以及为什么会这样。

我是 运行 这些代码在 Xcode 和 Mac OS X 10.10.

正如评论所说,使用是一种很好的做法:

__kernel void adder(__global const float* a, __global const float* b, __global float* result)

因为这样你就清楚地定义了那些特殊的 CL 标志。通常所有 CL 内核都遵循该规则,即使规范允许两者。


但您的问题可能是由于 运行 clBuildProgram() w设备列表中没有任何设备。因此,根本不编译任何东西!

在 CL 中,每个设备都有一个特定的编译器(CPU 没有与 GPU 相同的编译器,有时甚至没有相同的指令集)。所以你应该给 API 必须编译内核的设备列表。

正确的方法是这样的:

err = clBuildProgram(program, 1, &devices[USE_DEVICE], "", 0, 0);

注意:我加了“”,因为以后你可能会想要添加一些构建参数,最好准备好:)