gpt4 book ai didi

multithreading - OpenCL-如何有效地将工作项分配到不同的设备

转载 作者:行者123 更新时间:2023-12-03 13:19:43 25 4
gpt4 key购买 nike

我正在编写一个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设备时不会考虑这些因素。我会问你:

  • 内核大小是多少?
  • 他们完成多快?
  • 如果内核很小,并且它们很快完成。这样,启动它们的开销将很高。因此,将它们分布在许多设备上的更精细的粒度并不能克服额外的开销。在这种情况下,最好直接增加工作量并仅使用1台设备。
  • 内核独立吗?他们使用不同的缓冲区吗?
  • 另一个重要的事情是每个设备都拥有完全不同的内存,否则设备之间的内存浪费将延迟内核启动,在这种情况下,单个设备(将所有内存缓冲区都保留在本地)将表现更好。
  • OpenCL会将内核使用的所有缓冲区复制到设备,并将使用该内核正在写入的缓冲区“阻止”所有内核(即使在其他设备中);将等待它完成,然后将缓冲区复制回另一台设备。
  • 主机是瓶颈吗?
  • 主机有时不如您想像的那样快,并且有时内核运行速度如此之快,以至于主机成为调度作业的大瓶颈。
  • 如果将CPU用作CL设备,则它不能同时执行两项任务(充当主机并运行内核)。 在计划内核时,您应该始终选择GPU设备而不是CPU设备。
  • 切勿让设备清空
  • 在排队执行更多工作之前,等到设备完成执行通常是一个非常糟糕的主意。即使在当前内核完成之前,也应该提前(1或2)将内核抢先排队。否则,设备利用率将无法达到80%。由于从内核完成直到主机意识到它要花费大量的时间,而直到主机将更多数据排队给内核的时间也更长(通常> 2ms,对于10ms的内核,这浪费了33%) 。

  • 我会做:
  • 将此行更改为已提交的作业:if(status >= CL_SUBMITTED)
  • 确保将设备订购为GPU-> CPU。因此,GPU是设备0,1,CPU是设备2。
  • 尝试卸下CPU设备(仅使用GPU)。也许速度会更好。
  • 关于multithreading - OpenCL-如何有效地将工作项分配到不同的设备,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27239154/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com