使用多个GPU时OpenCL内核启动延迟?

使用多个GPU时OpenCL内核启动延迟?,opencl,gpu,multiple-gpu,Opencl,Gpu,Multiple Gpu,我有一个应用程序,我设计运行在AMD GPU的OpenCL。昨天终于让这个应用程序运行起来并且没有bug(哈哈),目标是一个GPU。现在,该应用程序可以工作了,是时候将其扩展到多个GPU了 阅读很多关于如何设置它的内容。我们使用的是单上下文、多队列方法 我拉取设备列表,选择2个GPU并创建一个包含它们的上下文,然后创建一个包含这两个设备的构建程序。创建两个单独的队列 原始工作应用程序的伪代码,现在转换为处理2个GPU: context = clCreateContext(0, 2, device

我有一个应用程序,我设计运行在AMD GPU的OpenCL。昨天终于让这个应用程序运行起来并且没有bug(哈哈),目标是一个GPU。现在,该应用程序可以工作了,是时候将其扩展到多个GPU了

阅读很多关于如何设置它的内容。我们使用的是单上下文、多队列方法

我拉取设备列表,选择2个GPU并创建一个包含它们的上下文,然后创建一个包含这两个设备的构建程序。创建两个单独的队列

原始工作应用程序的伪代码,现在转换为处理2个GPU:

context = clCreateContext(0, 2, device_list, NULL, NULL, &ret);
for(x = 0; x < 2; x++)
  queue[x] = clCreateCommandQueue(context, device_list[x], ENABLE_PROFILING, &ret);
clBuildProgram(program, 2, device_list, options, NULL, NULL);

create kernels..

run...
for(outer_loop = 0; outer_loop < 10; outer_loop++) {
  clEnqueueNDRangeKernel(queue[0], kernel_init, offset, &event[0]);
  clEnqueueNDRangeKernel(queue[1], kernel_init, different_offset, &event[1]);
  clFinish(queue[0]);
  clFinish(queue[1]);

  get profiling data and printf results
}
我运行这个的机器有5个GPU。无论我使用哪两个GPU,两个GPU中的一个(并不总是同一个)在启动时都会获得4-5秒的延迟。使用单个GPU-无延迟

这可能是什么原因造成的?有什么想法吗?我没有阻止-clFinish只是为了获取分析信息。即使它阻塞了,也不会延迟5秒

另外,我认为内核对全局的写入可能是延迟的一部分。我评论了这些文字。不。没有变化


事实上,我加了一个回报;作为内核的第一行,它完全不做任何事情。40毫秒下降到0.25秒,但5秒的延迟仍然存在

OpenCL驱动程序不关心内核中发生了什么。如果内核写入/读取或为空内核,或者如果它只写入缓冲区的一个部分。它关心缓冲区参数标志,并确保数据在整个GPU中保持一致,如果内核在其他内核中有任何依赖关系,则阻塞内核。 GPU到GPU的传输是透明的,并且可能非常昂贵

当使用多个GPU时,必须认真对待隐藏的数据复制和同步,因为这通常是主要的瓶颈

如果内核可以并行运行(因为GPU1处理的数据与GPU2上的不同,等等…),那么应该为每个GPU创建不同的缓冲区。或者,如果数据相同,请正确设置类型
CL\u READ\u
/
CL\u WRITE\u
,以确保正确的OpenCL行为。以及最低限度的复制/一致性操作


例如,对于这些内核:

kernel Sum(read_only A, read_only B, write_only C);
kernel Sum_bad(read_write A, read_write B, write_only C);
如果使用单个GPU,两者的行为将完全相同,因为所有内存都驻留在同一个GPU中。 但使用多个GPU可能会导致可怕的问题,例如:

Queue 1/GPU 1: Sum_Bad(A,B,C);
Queue 2/GPU 2: Sum_Bad(A,D,E);
事件将发生如下:

  • 内存A、B将被复制到GPU1内存(如果它还不存在的话)。C在GPU1中分配的内存
  • GPU1将运行内核
  • 内存A将从GPU1复制到GPU2。内存D将被复制到GPU2。内存已分配
  • GPU2将运行内核
  • 如您所见,GPU2必须等待第一个参数完成,另外还要等待所有参数复制回来。(可以是5秒吗?可能,取决于尺寸)


    但是,使用正确的方法:

    Queue 1/GPU 1: Sum(A,B,C);
    Queue 2/GPU 2: Sum(A,D,E);
    
    事件将发生如下:

  • 内存A、B将被复制到GPU1内存(如果它还不存在的话)。C在GPU1中分配的内存
  • GPU1将运行内核
  • 并行(因为不存在依赖性)

  • 内存A、D将被复制到GPU2(如果它还不存在的话)。内存已分配
  • GPU2将运行内核

  • 你试过在CodeXL中运行所有这些吗?您可以准确地获得正在发生的事情(数据传输、API调用、内核执行等)的时间表。不幸的是,与我们利用如此有限的信息来解决问题相比,使用正确的工具来解决问题的可能性要大得多。为了确保(我在别处看到了这一解决方案),我刚刚升级到最新的AMD驱动程序和匹配的OpenCL库。没有变化。同样的延迟也存在。不,我还没有使用CodeXL。不幸的是,我不在图形环境中,尝试查找、阅读和理解如何使用命令行版本似乎比最初学习OpenCL更加困难。如果所有其他方法都失败了,我将尝试这种方法。现在修改代码,使其具有单独的缓冲区,但与此同时,即使内核没有做任何事情,复制/延迟问题是否会出现,它只是返回?仅仅在循环开始之前写入一次数据,它还会这样做吗?此外,我似乎需要两个不同的上下文来拥有两个不同的缓冲区?正确吗?关于gpu到gpu的传输非常昂贵-5秒?在GPU之间移动805兆的数据?在主机端,我可以在毫秒内读取、阻塞、写入、阻塞。如果我遇到80毫秒的延迟-好的-我会告诉你的。但是5000?我目前正在重新编写代码,以基本上复制所有内容,并有2个上下文。一旦它停止在setKernelArg上执行segfaulting,我会报告发生了什么。好的,把bug弄出来。这绝对似乎解决了这个问题-然而-随着这个程序的增长,数据可能需要共享。我知道有多个gpu应用程序共享数据,但没有这个问题。再说一次,5秒是超越极限的。似乎对于我正在做的事情——所有GPU都独立工作,不需要共享数据,多上下文方法效果最好。昨天,所有5个GPU协同工作,每秒解决8840万个问题,使其运行正常。如果需要GPU共享缓冲区空间,我想我会再次解决这个问题。谢谢
    Queue 1/GPU 1: Sum(A,B,C);
    Queue 2/GPU 2: Sum(A,D,E);