【问题标题】:OpenCL C program gives bizzare outputOpenCL C 程序给出了奇怪的输出
【发布时间】:2015-09-27 15:01:44
【问题描述】:

我编写了一个简单的 OpenCL C 代码。它的内核代码是:

__kernel void hello(__global int * A,__global int * B)
{
    int x=get_global_id(0);
    B[x]=x;
    A[x]+=1;
}

以下是主机代码的一部分:

int main()
{
    cl_platform_id* platforms=NULL;
    cl_device_id* devices=NULL;
    cl_uint ret,platformCount,deviceCount;
    cl_context context = NULL;
    cl_command_queue command_queue=NULL;
    char* name;
    int i,j,l;
    size_t size;
    cl_mem memobj = NULL;
    cl_mem memobj1 = NULL;
    cl_program program = NULL;
    cl_kernel kernel = NULL;
    int array_size=10;
    int *A=(int*)malloc(array_size*sizeof(int));
    int *B=(int*)malloc(array_size*sizeof(int));
    printf("\nhey");
    for(i=0;i<array_size;i++)
        A[i]=0;
    ret=clGetPlatformIDs(0,NULL,&platformCount);
    printf("\n-----------------Found %d platforms-----------\n",platformCount);
    platforms=(cl_platform_id*)malloc(sizeof(cl_platform_id)*platformCount);
    ret=clGetPlatformIDs(platformCount,platforms,NULL);
    if(ret==CL_SUCCESS)
        printf("\nPlatform ids obtained successfully!");
    for(i=platformCount-1;i>=0;i--)
    {   
        char * platformname;
        printf("\n-------------In platform %d-----------------",i);
        ret=clGetPlatformInfo(platforms[i], CL_PLATFORM_NAME ,0,NULL,&size);
        platformname=(char*)malloc(sizeof(char)*size);
        ret=clGetPlatformInfo(platforms[i], CL_PLATFORM_NAME ,size,platformname,NULL);
        if(ret==CL_SUCCESS)
            printf("\nPlatform info obtained successfully!");

        printf("\n----------------For %s-----------------------",platformname);

        ret=clGetDeviceIDs(platforms[i],CL_DEVICE_TYPE_DEFAULT,NULL,NULL,&deviceCount);
        devices=(cl_device_id*)malloc(sizeof(cl_device_id)*deviceCount);
        ret=clGetDeviceIDs(platforms[i],CL_DEVICE_TYPE_DEFAULT,deviceCount,devices,NULL);
        if(ret==CL_SUCCESS)
            printf("\nFound %d devices!",deviceCount);

        for(j=0;j<deviceCount;j++)
        {
            char*devicename;
            printf("\n-------------Device %d.%d-----------------",i,j+1);
            ret=clGetDeviceInfo(devices[j], CL_DEVICE_NAME ,0,NULL,&size);
            devicename=(char*)malloc(sizeof(char)*size);
            ret=clGetDeviceInfo(devices[j], CL_DEVICE_NAME ,size,devicename,NULL);
            if(ret==CL_SUCCESS)
                printf("\nDevice info obtained successfully!");
            printf("\nThe device name is %s && size=%d\n",devicename,size);

            printf("\nFound %d corresponding devices",deviceCount);
            context=clCreateContext(NULL,1,&devices[j], NULL, NULL, &ret);
            if(ret==CL_SUCCESS)
                printf("\nContext created successfully");

            command_queue=clCreateCommandQueue(context,devices[j], CL_QUEUE_PROFILING_ENABLE,&ret);
            if(ret==CL_SUCCESS)
                printf("\nCommand queue created successfully");

            memobj=clCreateBuffer(context, CL_MEM_READ_WRITE ,array_size*sizeof(int),NULL,&ret);
            if(ret==CL_SUCCESS)
                printf("\nMemory object 1 created successfully");
            memobj1=clCreateBuffer(context, CL_MEM_READ_WRITE ,array_size*sizeof(int),NULL,&ret);
            if(ret==CL_SUCCESS)
                printf("\nMemory object 2 created successfully");
            ret=clEnqueueWriteBuffer(command_queue, memobj, CL_TRUE, 0, array_size*sizeof(int), A, 0, NULL, NULL);
            if(ret==CL_SUCCESS)
                printf("\nData written into buffer1  successfully");
            ret=clEnqueueWriteBuffer(command_queue, memobj1, CL_TRUE, 0, array_size*sizeof(int),B, 0, NULL, NULL);
            if(ret==CL_SUCCESS)
            printf("\nData written into buffer2 successfully");
             FILE *fp;
                char fileName[] = "./6.cl";
                char *source_str;
                size_t source_size;
                /* Load kernel code */
                fp = fopen(fileName, "r");
                if (!fp) {
                fprintf(stderr, "Failed to load kernel.\n");
                exit(1);
                }
                source_str = (char*)malloc(MAX_SOURCE_SIZE);
                source_size = fread(source_str, 1, MAX_SOURCE_SIZE, fp);
                printf("\nThe program is \n%s\n",source_str);
                fclose(fp);

            program=clCreateProgramWithSource(context, 1, (const char **)&source_str,(const size_t *)&source_size, &ret);       
            if(ret==CL_SUCCESS)
            printf("\nProgram created successfully");

            ret = clBuildProgram(program, 1, &devices[j], NULL, NULL, NULL);        
            if(ret==CL_SUCCESS)
                printf("\nProgram built successfully");

            ret=clGetProgramBuildInfo(program,devices[j], CL_PROGRAM_BUILD_STATUS ,0,NULL,&size);
            printf("\n Program buildinfo status=%d",ret);
            cl_build_status *status=(cl_build_status *)malloc(sizeof(cl_build_status )*size);
            clGetProgramBuildInfo(program,devices[j], CL_PROGRAM_BUILD_STATUS ,size,status,NULL);
            printf("\nBuild status=%d\n",*status);

            printf("\nBuild log i=%d, j=%d",i,j);
            ret=clGetProgramBuildInfo(program,devices[j], CL_PROGRAM_BUILD_LOG ,0,NULL,&size);
            printf("\nclGetProgramBuildInfo ret1=%d",ret);
            char buildlog[2048];
            ret=clGetProgramBuildInfo(program,devices[j], CL_PROGRAM_BUILD_LOG ,sizeof(buildlog),buildlog,NULL);
            printf("\nclGetProgramBuildInfo ret2=%d",ret);
            printf("\n!!!!!!!!!!!!!!!!!!!!!Program ended!!!!!!!!!!!\n");
            printf("\n\nBuildlog:   %s\n\n",buildlog);



            kernel = clCreateKernel(program, "hello", &ret);
            if(ret==CL_SUCCESS)
                printf("\nKernel created successfully");
            ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *) &memobj);
            printf("\nKernel argument 1=%d",ret);
            ret = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *) &memobj1);
            printf("\nKernel argument 2=%d",ret);
            cl_uint work_dim = 1;       
            size_t global_item_size=array_size;
            size_t local_item_size=32;
            cl_event event;
            ret = clEnqueueNDRangeKernel(command_queue, kernel, work_dim, NULL,&global_item_size, &local_item_size,0,NULL,&event);  
            if(ret==CL_SUCCESS)
                printf("\nKernel executed successfully");
            //ret=clEnqueueTask(command_queue,kernel,0,NULL,NULL);
            clWaitForEvents(1, &event);//make sure kernel has finished
            clFinish(command_queue);//make sure all enqueued tasks finished
            //get the profiling data and calculate the kernel execution time

            cl_ulong time_start, time_end;
            double total_time;
            clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_START, sizeof(time_start), &time_start, NULL);
            clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_END, sizeof(time_end), &time_end, NULL);
            total_time = (cl_double)(time_end - time_start)/1000000.0;
            printf("OpenCl Execution time is: %10.5f[ms] \n",total_time);
            ret = clEnqueueReadBuffer(command_queue, memobj1, CL_TRUE, 0,array_size * sizeof(int), B, 0, NULL, NULL);
            ret = clEnqueueReadBuffer(command_queue, memobj, CL_TRUE, 0,array_size * sizeof(int), A, 0, NULL, NULL);
            int t;
            printf("\nThe result is:");
            for(t=0;t<array_size;t++)
                printf("\t%d",B[t]);
            printf("\nThe result A is:");
            for(t=0;t<array_size;t++)
                printf("\t%d",A[t]);

            //Read file here
            }
        }

    return 0;

}   

我面临几个问题:

  1. 程序输出数组 B 的垃圾值并返回未修改的数组 A。
  2. 如果不是ret = clEnqueueNDRangeKernel(command_queue, kernel, work_dim, NULL,&amp;global_item_size, &amp;local_item_size,1,NULL,&amp;event);
    我使用ret = clEnqueueNDRangeKernel(command_queue, kernel, work_dim, NULL,&amp;global_item_size, &amp;local_item_size,0,NULL,NULL);,程序输出正确的结果。我在 2 个 GPU 和一个 CPU 上运行此代码。如果我使用后一种形式的 clEnqueueNDRangeKernel,即不进行分析,我会在 GPU 中获得正确的输出,而在 CPU 的情况下会出现垃圾值。
  3. 代码列出的特定平台的设备数量少于实际可用的设备数量。

【问题讨论】:

    标签: c linux parallel-processing opencl gpgpu


    【解决方案1】:
    ret = clEnqueueNDRangeKernel(command_queue, kernel, work_dim, NULL,&global_item_size, &local_item_size,1,NULL,&event);
    

    您正在传递一个空的 (NULL) 事件等待列表,但声称其中包含 1 个事件。这将失败,并且如果您正在检查 OpenCL API 调用中的错误代码(您应该始终这样做),您可能会收到 CL_INVALID_EVENT_WAIT_LIST,这会将您指向问题。

    如果您只想从内核检索事件(例如用于分析),但不想将任何事件依赖项传递给它,那么正确的形式应该是:

    ret = clEnqueueNDRangeKernel(command_queue, kernel, work_dim, NULL,&global_item_size, &local_item_size,0,NULL,&event);
    

    您提供的代码的第二个问题是您的工作组大小不能完全划分全局大小:

    size_t global_item_size=array_size; // which is 10
    size_t local_item_size=32;
    

    这将导致clEnqueueNDRangeKernel 返回CL_INVALID_WORK_GROUP_SIZE,并且无法将任何工作排入队列。


    代码列出的特定平台的设备数量少于实际可用的设备数量。

    您正在请求CL_DEVICE_TYPE_DEFAULT 类型的所有设备。如果您真的想要所有设备,请使用CL_DEVICE_TYPE_ALL。如果您只想要 GPU 设备,请询问CL_DEVICE_TYPE_GPU

    【讨论】:

    • 这行得通。它在两个 GPU 上都给出了正确的输出,但是当我在 CPU 上运行这段代码时它给出了垃圾值。
    • 您是否在检查每个 OpenCL API 调用返回的错误代码?如果你有,而且他们都是CL_SUCCESS,请用完整的主机代码更新你的问题,我可以再看看。
    • 更新:此代码在第一次运行时会给出垃圾值,而与使用的设备无关。实际上我正在运行两个循环,即 1 for(i=platformCount-1;i>=0;i--){ /*获取数组设备中对应的设备 ID */ for(j=0;j
    • 好的,检查所有的错误代码,如果它们都正常,那么用一个完整的、最小的例子来更新问题,重现你的问题。
    • @ikk 更新了第二个问题的答案。修复该问题后,您的代码对我来说可以正常工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-12
    • 2021-07-13
    相关资源
    最近更新 更多