You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenCL入门示例clFinish调用阻塞无返回问题求助

OpenCL Hello World 程序阻塞问题排查

问题描述

刚学习OpenCL,尝试用Hello World示例验证环境,但程序在调用clFinish时阻塞无法返回。设备是Ryzen 5 3400G,系统为Linux,gcc版本10.2.1-6。

原代码

#include <math.h>
#ifdef __APPLE__
    #include <OpenCL/opencl.h>
#else
    #include <CL/cl.h>
#endif

const char *KernelSource = "\n" \
"__kernel void hello(             \n" \
"   __global char* a,         \n" \
"   __global char* b,         \n" \
"   __global char* c,         \n" \
"   const unsigned int count)  \n" \
"{                           \n" \
"   int i = get_global_id(0);  \n" \
"   if(i < count)             \n" \
"      c[i] = a[i] + b[i];   \n" \
"}                           \n" \
"\n";

#define DATA_SIZE (16)

int main(int argc, char** argv)
{
    int err;                         // error code returned from api calls
    cl_device_id device_id;          // compute device id 
    cl_context context;              // compute context
    cl_command_queue commands;       // compute command queue
    cl_program program;              // compute program
    cl_kernel kernel;                // compute kernel
    cl_mem input;                    // device memory used for the input array
    cl_mem input2;                   // device memory used for the input array
    cl_mem output;                   // device memory used for the output array
    size_t global;                   // global domain size for our calculation
    size_t local;                    // local domain size for our calculation
    
    int i;
    unsigned int count = DATA_SIZE;

    // Input data
    char a[DATA_SIZE] = "Hello \0\0\0\0\0\0";
    char b[DATA_SIZE] = {15, 10, 6, 0, -11, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    // Output data
    char c[DATA_SIZE];
    
    cl_platform_id platform;
    unsigned int no_plat;
    err =  clGetPlatformIDs(1,&platform,&no_plat);

    // Where to run
    err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device_id, NULL);
    if (err != CL_SUCCESS) return -1;
    context = clCreateContext(0, 1, &device_id, NULL, NULL, &err);
    if (!context) return -1;
    commands = clCreateCommandQueue(context, device_id, 0, &err);
    if (!commands) return -1;
    
    // What to run
    program = clCreateProgramWithSource(context, 1, (const char **) & KernelSource, NULL, &err);
    if (!program) return -1;

    err = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
   if (err != CL_SUCCESS) return -1;
    kernel = clCreateKernel(program, "hello", &err);
    if (!kernel || err != CL_SUCCESS) return -1;
    
    // Create space for data and copy a and b to device (note that we could also use clEnqueueWriteBuffer to upload)
    input = clCreateBuffer(context,  CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,  sizeof(char) * DATA_SIZE, a, NULL);
    input2 = clCreateBuffer(context,  CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,  sizeof(char) * DATA_SIZE, b, NULL);
    output = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(char) * DATA_SIZE, NULL, NULL);
    if (!input || !output) return -1;
    
    // Send data
    err  = clSetKernelArg(kernel, 0, sizeof(cl_mem), &input);
    err |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &input2);
    err |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &output);
    err |= clSetKernelArg(kernel, 3, sizeof(unsigned int), &count);
    if (err != CL_SUCCESS) return -1;
    
    local = DATA_SIZE;

    // Run kernel!
    global = DATA_SIZE; // count;
    err = clEnqueueNDRangeKernel(commands, kernel, 1, NULL, &global, &local, 0, NULL, NULL);
    if (err != CL_SUCCESS) return -1;

    clFinish(commands);

    // Read result
    err = clEnqueueReadBuffer( commands, output, CL_TRUE, 0, sizeof(char) * count, c, 0, NULL, NULL );  
    if (err != CL_SUCCESS) return -1;

    printf("%s\n", c);

    // Clean up
    clReleaseMemObject(input);
    clReleaseMemObject(output);
    clReleaseProgram(program);
    clReleaseKernel(kernel);
    clReleaseCommandQueue(commands);
    clReleaseContext(context);
    sleep(1); // Leopard pty bug workaround.
    return 0;
}

编译警告

from world.c:11:
/usr/include/CL/cl_version.h:22:9: note: ‘#pragma message: cl_version.h: CL_TARGET_OPENCL_VERSION is not defined. Defaulting to 300 (OpenCL 3.0)’
   22 | #pragma message("cl_version.h: CL_TARGET_OPENCL_VERSION is not defined. Defaulting to 300 (OpenCL 3.0)")
      |         ^~~~~~~
world.c: In function ‘main’:
world.c:61:2: warning: ‘clCreateCommandQueue’ is deprecated [-Wdeprecated-declarations]
   61 |  commands = clCreateCommandQueue(context, device_id, 0, &err);
      |  ^~~~~~~~
In file included from world.c:11:
/usr/include/CL/cl.h:1906:1: note: declared here
 1906 | clCreateCommandQueue(cl_context                     context,
      | ^~~~~~~~~~~~~~~~~~~~

clinfo输出

Number of platforms                               1
  Platform Name                                   Clover
  Platform Vendor                                 Mesa
  Platform Version                                OpenCL 1.1 Mesa 20.3.5
  Platform Profile                                FULL_PROFILE
  Platform Extensions                             cl_khr_icd
  Platform Extensions function suffix             MESA

  Platform Name                                   Clover
Number of devices                                 1
  Device Name                                     AMD Radeon(TM) Vega 11 Graphics (RAVEN, DRM 3.40.0, 4.19.0-12-amd64, LLVM 11.0.1)
  Device Vendor                                   AMD
  Device Vendor ID                                0x1002
  Device Version                                  OpenCL 1.1 Mesa 20.3.5
  Driver Version                                  20.3.5
  Device OpenCL C Version                         OpenCL C 1.1 
  Device Type                                     GPU
  Device Profile                                  FULL_PROFILE
  Device Available                                Yes
  Compiler Available                              Yes
  Max compute units                               11
  Max clock frequency                             1400MHz
  Max work item dimensions                        3
  Max work item sizes                             256x256x256
  Max work group size                             256
  Preferred work group size multiple (kernel)     64
  Preferred / native vector sizes                 
    char                                                16 / 16      
    short                                                8 / 8       
    int                                                  4 / 4       
    long                                                 2 / 2       
    half                                                 0 / 0        (n/a)
    float                                                4 / 4       
    double                                               2 / 2        (cl_khr_fp64)
  Half-precision Floating-point support           (n/a)
  Single-precision Floating-point support         (core)
    Denormals                                     No
    Infinity and NANs                             Yes
    Round to nearest                              Yes
    Round to zero                                 No
    Round to infinity                             No
    IEEE754-2008 fused multiply-add               No
    Support is emulated in software               No
    Correctly-rounded divide and sqrt operations  No
  Double-precision Floating-point support         (cl_khr_fp64)
    Denormals                                     Yes
    Infinity and NANs                             Yes
    Round to nearest                              Yes
    Round to zero                                 Yes
    Round to infinity                             Yes
    IEEE754-2008 fused multiply-add               Yes
    Support is emulated in software               No
  Address bits                                    64, Little-Endian
  Global memory size                              31611129856 (29.44GiB)
  Error Correction support                        No
  Max memory allocation                           22127790899 (20.61GiB)
  Unified memory for Host and Device              No
  Minimum alignment for any data type             128 bytes
  Alignment of base address                       32768 bits (4096 bytes)
  Global Memory cache type                        None
  Image support                                   No
  Local memory type                               Local
  Local memory size                               32768 (32KiB)
  Max number of constant args                     16
  Max constant buffer size                        67108864 (64MiB)
  Max size of kernel argument                     1024
  Queue properties                                
    Out-of-order execution                        No
    Profiling                                     Yes
  Profiling timer resolution                      0ns
  Execution capabilities                           
    Run OpenCL kernels                            Yes
    Run native kernels                            No
  Device Extensions                               cl_khr_byte_addressable_store cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_int64_base_atomics cl_khr_int64_extended_atomics cl_khr_fp64

NULL platform behavior
  clGetPlatformInfo(NULL, CL_PLATFORM_NAME, ...)  No platform
  clGetDeviceIDs(NULL, CL_DEVICE_TYPE_ALL, ...)   No platform
  clCreateContext(NULL, ...) [default]            No platform
  clCreateContext(NULL, ...) [other]              Success [MESA]
  clCreateContextFromType(NULL, CL_DEVICE_TYPE_DEFAULT)  Success (1)
    Platform Name                                 Clover
    Device Name                                   AMD Radeon(TM) Vega 11 Graphics (RAVEN, DRM 3.40.0, 4.19.0-12-amd64, LLVM 11.0.1)
  clCreateContextFromType(NULL, CL_DEVICE_TYPE_CPU)  No devices found in platform
  clCreateContextFromType(NULL, CL_DEVICE_TYPE_GPU)  Success (1)
    Platform Name                                 Clover
    Device Name                                   AMD Radeon(TM) Vega 11 Graphics (RAVEN, DRM 3.40.0, 4.19.0-12-amd64, LLVM 11.0.1)
  clCreateContextFromType(NULL, CL_DEVICE_TYPE_ACCELERATOR)  No devices found in platform
  clCreateContextFromType(NULL, CL_DEVICE_TYPE_CUSTOM)  No devices found in platform
  clCreateContextFromType(NULL, CL_DEVICE_TYPE_ALL)  Success (1)
    Platform Name                                 Clover
    Device Name                                   AMD Radeon(TM) Vega 11 Graphics (RAVEN, DRM 3.40.0, 4.19.0-12-amd64, LLVM 11.0.1)

问题原因分析

  1. 本地工作组大小不兼容:从clinfo输出看,设备的Preferred work group size multiple (kernel)是64,代码中设置local = 16,虽然小于最大工作组大小256,但Clover平台对非推荐倍数的工作组大小兼容性较差,导致内核无法调度执行,进而阻塞clFinish。
  2. API版本不匹配:默认使用OpenCL 3.0,但设备仅支持OpenCL 1.1,部分API调用存在兼容性问题。
  3. 使用废弃API:clCreateCommandQueue是OpenCL 1.2及以后废弃的接口,在旧版本平台上可能引发异常。
  4. 错误检查不完整:部分API调用未检查错误,无法定位早期问题。

修改后的可运行代码

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __APPLE__
    #include <OpenCL/opencl.h>
#else
    #include <CL/cl.h>
#endif

// 明确指定目标OpenCL版本为1.1,匹配设备支持版本
#define CL_TARGET_OPENCL_VERSION 110

const char *KernelSource = "\n" \
"__kernel void hello(             \n" \
"   __global char* a,         \n" \
"   __global char* b,         \n" \
"   __global char* c,         \n" \
"   const unsigned int count)  \n" \
"{                           \n" \
"   int i = get_global_id(0);  \n" \
"   if(i < count)             \n" \
"      c[i] = a[i] + b[i];   \n" \
"}                           \n" \
"\n";

#define DATA_SIZE (16)

// 辅助函数:打印OpenCL错误信息
void print_cl_error(const char* func_name, cl_int err) {
    fprintf(stderr, "Error in %s: %d\n", func_name, err);
}

int main(int argc, char** argv)
{
    cl_int err;
    cl_device_id device_id;
    cl_context context;
    cl_command_queue commands;
    cl_program program;
    cl_kernel kernel;
    cl_mem input, input2, output;
    size_t global, local;
    
    unsigned int count = DATA_SIZE;
    char a[DATA_SIZE] = "Hello \0\0\0\0\0\0";
    char b[DATA_SIZE] = {15, 10, 6, 0, -11, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    char c[DATA_SIZE];
    
    cl_platform_id platform;
    unsigned int no_plat;
    err = clGetPlatformIDs(1, &platform, &no_plat);
    if (err != CL_SUCCESS) {
        print_cl_error("clGetPlatformIDs", err);
        return -1;
    }

    err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device_id, NULL);
    if (err != CL_SUCCESS) {
        print_cl_error("clGetDeviceIDs", err);
        return -1;
    }
    
    context = clCreateContext(0, 1, &device_id, NULL, NULL, &err);
    if (!context || err != CL_SUCCESS) {
        print_cl_error("clCreateContext", err);
        return -1;
    }
    
    // 使用新版API创建命令队列
    cl_queue_properties props[] = {CL_QUEUE_PROPERTIES, CL_QUEUE_PROFILING_ENABLE, 0};
    commands = clCreateCommandQueueWithProperties(context, device_id, props, &err);
    if (!commands || err != CL_SUCCESS) {
        print_cl_error("clCreateCommandQueueWithProperties", err);
        clReleaseContext(context);
        return -1;
    }
    
    program = clCreateProgramWithSource(context, 1, (const char **)&KernelSource, NULL, &err);
    if (!program || err != CL_SUCCESS) {
        print_cl_error("clCreateProgramWithSource", err);
        clReleaseCommandQueue(commands);
        clReleaseContext(context);
        return -1;
    }

    err = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
    if (err != CL_SUCCESS) {
        // 打印编译错误日志
        size_t log_size;
        clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);
        char* log = (char*)malloc(log_size);
        clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, log_size, log, NULL);
        fprintf(stderr, "Program build log:\n%s\n", log);
        free(log);
        print_cl_error("clBuildProgram", err);
        clReleaseProgram(program);
        clReleaseCommandQueue(commands);
        clReleaseContext(context);
        return -1;
    }
    
    kernel = clCreateKernel(program, "hello", &err);
    if (!kernel || err != CL_SUCCESS) {
        print_cl_error("clCreateKernel", err);
        clReleaseProgram(program);
        clReleaseCommandQueue(commands);
        clReleaseContext(context);
        return -1;
    }
    
    input = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(char)*DATA_SIZE, a, &err);
    if (err != CL_SUCCESS) {
        print_cl_error("clCreateBuffer(input)", err);
        goto cleanup;
    }
    input2 = clCreateBuffer(context, CL
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 00:15:40