在多个GPU上运行OpenCL内核

时间:2013-11-11 00:35:01

标签: opencl

我有一个OpenCL内核,我希望在不同系统上检测到的所有支持OpenCL的设备(如所有可用的GPU)上运行它,我很感激知道是否有任何简单的方法。我的意思是为所有设备创建一个命令队列。

提前致谢:]

3 个答案:

答案 0 :(得分:3)

您无法为所有设备创建单个命令队列;给定的命令队列绑定到单个设备。但是,您可以为每个OpenCL设备创建单独的命令队列,并为它们提供工作,这应该同时执行。

答案 1 :(得分:2)

正如Dithermaster指出你首先为每个设备创建一个单独的命令队列,例如你可能有多个GPU。然后,您可以将它们放在一个数组中,例如,这是一个指向您可以设置的数组的指针:

cl_command_queue* commandQueues;

但是根据我的经验,并不总是在同时执行各种命令队列时“猛烈扣篮”,因为可以使用事件计时信息(检查重叠)进行验证,您可以通过自己的分析或使用第三方分析工具。无论如何,您应该执行此步骤以验证您的设置有效或无效。

另一种可以很好地工作的方法是使用OpenMP同时执行命令队列,例如,你执行以下操作:

#pragma omp parallel for default(shared)
    for (int i = 0; i < numDevices; ++i) {
            someOpenCLFunction(commandQueues[i], ....);
    }

答案 2 :(得分:2)

假设您有N个设备和100个工作要素(作业)。你应该做的是这样的事情:

#define SIZE 3

std::vector<cl::Commandqueue> queues(SIZE); //One queue for each device (same context)
std::vector<cl::Kernel> kernels(SIZE); //One kernel for each device (same context)
std::vector<cl::Buffer> buf_in(SIZE), buf_out(SIZE); //One buffer set for each device (same context)

// Initialize the queues, kernels, buffers etc....
//Create the kernel, buffers and queues, then set the kernel[0] args to point to buf_in[0] and buf_out[0], and so on...

// Create the events in a finished state
std::vector<cl::Event> events;
cl::UserEvent ev; ev.setStatus(CL_COMPLETE);
for(int i=0; i<queues.size(); i++)
    events.push_back(ev);

//Run all the elements (a "first empty, first run" scheduler)
for(int i=0; i<jobs.size(); i++){
    bool found = false;
    int x = -1;
    //Try all the queues
    while(!found){
        for(int j=0; j<queue.size(); j++)
            if(events[j].getInfo<CL_EVENT_COMMAND_ EXECUTION_STATUS>() == CL_COMPLETED){
                found = true;
                x = j;
                break;
            }
        if(!found) Sleep(50); //Sleep a while if not all the queues have completed, other options are possible (like asigning the job to a random one)
    }
    //Run it
    events[x] = cl::Event(); //Clean it
    queues[x].enqueueWriteBuffer(...); //Copy buf_in
    queues[x].enqueueNDRangeKernel(kernel[x], .... ); //Launch the kernel
    queues[x].enqueueReadBuffer(... , events[x]); //Read buf_out
}

//Wait for completion
for(int i=0; i<queues.size(); i++)
    queue[i].Finish();