我正在编写一个openCL应用程序,其中有N个工作项,我想将其分配给N> D的D个设备,然后每个设备可以并行处理其自身工作项的元素,从而实现某种“双重”并行性。
这是我已经编写的尝试实现此目标的代码。
首先,我为每个设备创建一个事件,并将它们全部设置为完成:
cl_int err;
cl_event *events = new cl_event[deviceCount];
for(int i = 0; i < deviceCount; i++)
{
events[i] = clCreateUserEvent(context, &err);
events[i] = clSetUserEventStatus(events[i], CL_COMPLETE);
}
每个设备还具有自己的命令队列和内核的“实例”。
然后,进入我的“主循环”以分配工作项。该代码找到第一个可用的设备,并将其与工作项排队。
/*---Loop over all available jobs---*/
for(int i = 0; i < numWorkItems; i++)
{
WorkItem item = workItems[i];
bool found = false; //Check for device availability
int index = -1; //Index of found device
while(!found) //Continuously loop until free device is found.
{
for(int j = 0; j < deviceCount; j++) //Total number of CPUs + GPUs
{
cl_int status;
err = clGetEventInfo(events[j], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(cl_int), &status, NULL);
if(status == CL_COMPLETE) /*Current device has completed all of its tasks*/
{
found = true; //Exit infinite loop
index = j; //Choose current device
break; //Break out of inner loop
}
}
}
//Enqueue my kernel
clSetKernelArg(kernels[index], 0, sizeof(cl_mem), &item);
clEnqueueNDRangeKernel(queues[index], kernels[index], 1, NULL, &glob, &loc, 0, NULL, &events[index]);
clFlush(commandQueues[index]);
}
最后,我在所有设备上调用clFinish进行了总结:
/*---Wait For Completion---*/
for(int i = 0; i < deviceCount; i++)
{
clFinish(queues[i]);
}
但是,此方法存在一些问题:
1)它不会将工作分配到我的所有设备上。在我当前的计算机上,我有3台设备。我上面的算法仅将工作分配给设备1和2。设备3总是被遗弃,因为设备1和2完成得如此之快,以至于他们可以在3机会之前抢走更多的工作项目。
2)即使设备1和2一起运行,我也只能看到非常非常温和的速度增加。例如,如果我将所有工作项分配给设备1,则可能需要10秒钟才能完成;如果我将所有工作项分配给设备2,则可能需要11秒钟才能完成,但是如果我尝试在两个设备之间分配工作,结合起来,可能需要8-9秒,而我希望可能在4-5秒之间。我感到他们可能并没有真正按照我想要的方式并行运行。
我该如何解决这些问题?
最佳答案
您必须小心大小和存储位置。通常,在处理GPU设备时不会考虑这些因素。我会问你:
我会做:
if(status >= CL_SUBMITTED)
关于multithreading - OpenCL-如何有效地将工作项分配到不同的设备,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27239154/