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

PyOpenCL设备入队内核后随机崩溃及线程挂起问题排查

异构OpenCL灰度化任务调度问题

我正在尝试以异构方式执行灰度化处理:将100张图片分配给计算机上所有可用设备,让所有任务同时完成,以此实现比单设备更快的处理效率。

内核代码

我特意在内核中添加了while(1){};语句,目的是观察调度器工作机制,同时让设备在任务上消耗更多时间。代码如下:

__kernel void grayscale(__global uchar *input,
                        __global uchar *output,
                        uint width,
                        ulong size,
                        const ulong chunk_size)
{
    ulong gid_column = get_global_id(0);
    ulong gid_row = get_global_id(1);
    ulong pixel;
    float luma,r,g,b;
    while(1){};
    for(ulong i = 0; i<chunk_size;i++){
        pixel = ((gid_column*chunk_size)+(gid_row*width)+i)*3;
        if(pixel<size-3){
            r = input[pixel+0];
            g = input[pixel+1];
            b = input[pixel+2];
            luma = 0.299f * b + 0.587f * g + 0.114f * r;
            output[pixel+0] = luma;
            output[pixel+1] = luma;
            output[pixel+2] = luma;
        }
        else break;
    } 
}

调度逻辑代码

以下是处理任务分配的Python代码段,逻辑为:先给第一个设备分配任务,后续每次将新任务分配给当前最空闲的设备。

def grayscale(self, images):
    result = []
    device_queues = {}
    device_queues_status = {}
    DEBUG_PROCESED_TASKS = {}
    selected_device = None

    for device in self.opencl_devices:
        device_queues[device] = []
        device_queues_status[device] = 0
        DEBUG_PROCESED_TASKS[device.device_name] = 0

    for image in images:
        for device in device_queues:
            device_queues_status[
                device] = OpenCLFunctions.Pictures.get_work_amount(
                    device_queues[device])
        selected_device = min(device_queues_status,
                              key=device_queues_status.get)
        ev = selected_device._grayscale(image)
        device_queues[selected_device].append(ev)
        DEBUG_PROCESED_TASKS[selected_device.device_name] += 1
    print(DEBUG_PROCESED_TASKS)


def _grayscale(self, input_image):
    ENQUEUE_PROCESS_ASYNC = opencl_device.enqueue_nd_range_kernel
    ENQUEUE_COPY_ASYNC = opencl_device.enqueue_copy
    OPENCL_BUFFER = opencl_device.Buffer

    program = self.kernels["_grayscale"].grayscale
    buffers = OpenCLBuffer(
        OPENCL_BUFFER(self.context,
                      opencl_device.mem_flags.READ_WRITE
                      | opencl_device.mem_flags.ALLOC_HOST_PTR,
                      size=input_image.size),
        OPENCL_BUFFER(self.context,
                      opencl_device.mem_flags.READ_WRITE
                      | opencl_device.mem_flags.ALLOC_HOST_PTR,
                      size=input_image.size))
    input_copy = ENQUEUE_COPY_ASYNC(self.queue,
                                    buffers.opencl_buffer_input,
                                    input_image,
                                    is_blocking=False)
    program.set_args(
        buffers.opencl_buffer_input, buffers.opencl_buffer_output,
        opencl_device_numpy.uint32(input_image.shape[0]),
        opencl_device_numpy.uint64(buffers.size),
        opencl_device_numpy.uint64(self.CHUNK_PROCESSING_SIZE))
    max_work_group_size_kernel = program.get_work_group_info(
        opencl_device.kernel_work_group_info.WORK_GROUP_SIZE, self.device)
    prefered_local_size = program.get_work_group_info(
        opencl_device.kernel_work_group_info.
        PREFERRED_WORK_GROUP_SIZE_MULTIPLE, self.device)
    global_size = OpenCLFunctions.Pictures._get_global_size_picture(
        input_image.shape[0], input_image.shape[1],
        self.CHUNK_PROCESSING_SIZE)
    local_size, global_size = OpenCLFunctions.OpenCLScheduler._get_optimal_local_global_size(
        global_size, max_work_group_size_kernel,
        self.device.max_work_group_size, self.device.max_work_item_sizes,
        prefered_local_size)
    try:
        ev = ENQUEUE_PROCESS_ASYNC(self.queue,
                                   program,
                                   global_size,
                                   local_size,
                                   wait_for=[input_copy])
        return [ev, buffers.opencl_buffer_output]
    except Exception as e:
        print(e)

遇到的问题

调用ev = selected_device._grayscale(image)后,调试器无法查看变量,Python主线程挂起;内核入队后虽能运行一小段时间,但表现不稳定。

已尝试的解决方法

  • 阻止Python垃圾回收器回收事件对象
  • 用长循环替代while(1){};
  • 添加变量监控以追踪调度器处理后的忙碌事件
  • 使用更小的数据集

预期行为

因GPU上的while(1){};语句导致任务处于忙碌状态,调度器应识别到该设备忙碌,进而将下一个任务分配给其他设备(如CPU或核显)。

请问我是否遗漏了什么关键环节?(注:此问题仅用于研究实验,我希望理解该特定问题的成因。)


内容的提问来源于stack exchange,提问作者Seeven

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 20:52:15