在两个 GPU 上运行的代码不会达到并发执行,并且具有不相关的加速



我有这样的代码:

for(int i =0; i<2; i++)
{
    //initialization of memory and some variables
    ........
    ........
    RunDll(input image, output image); //function that calls kernel
}

上述循环中的每个迭代都是独立的。我想同时运行它们。所以,我试了这个:

for(int i =0; i<num_devices; i++)
{
    cudaSetDevice(i);
    //initialization of memory and some variables
    ........
    ........
    RunDll(input image, output image); 
    {
        RunBasicFBP_CUDA(parameters); //function that calls kernel 1
        xSegmentMetal(parameters); //CPU function
        RunBasicFP_CUDA(parameters);  //function that uses output of kernel 1 as input for kernel 2
        for (int idx_view = 0; idx_view < param.fbp.num_view; idx_view++)
        {
            for (int idx_bin = 1; idx_bin < param.fbp.num_bin-1; idx_bin++)
            {
                sino_diff[idx_view][idx_bin] = sino_org[idx_view][idx_bin] - sino_mask[idx_view][idx_bin];
            }
        }
        RunBasicFP_CUDA(parameters);
        if(some condition)
        {
            xInterpolateSinoLinear(parameters);  //CPU function
        }
        else
        {
            xInterpolateSinoPoly(parameters);  //CPU function
        }
        RunBasicFBP_CUDA( parameters );
    }
}

我正在使用 2 GTX 680,我想同时使用这两个设备。使用上面的代码,我没有得到任何加速。处理时间几乎与在单个 GPU 上运行时相同。

如何在两个可用设备上实现并发执行?

在您的评论中,您说:

RunDll 有两个内核,它们正在一个接一个地启动。内核确实有 cudaThreadSynchronize()

请注意,cudaThreadSynchronize() 等同于 cudaDeviceSynchronize()(前者实际上已弃用),这意味着您将在一个 GPU 上运行,同步,然后在另一个 GPU 上运行。另请注意,cudaMemcpy()是一个阻塞例程,则需要cudaMemcpyAsync()版本来避免所有阻塞(如@JackOLantern在注释中指出的那样)。

一般来说,您需要发布有关RunDLL()内部内容的更多详细信息,因为没有这些详细信息,您的问题就没有足够的信息来给出明确的答案。理想情况下,请遵循这些准则。

在我回答您之前的文章(同时运行两个 for 循环,在两个 GPU 上涉及 GPU 和 CPU 任务的循环周期数相同)中,我指出在使用 GPU 时,您不会实现2的加速2

为了解释原因,让我们考虑以下代码片段

Kernel1<<<...,...>>>(...); // assume Kernel1 takes t1 seconds
// assume CPUFunction + cudaMemcpys take tCPU seconds
cudaMemcpy(...,...,...,cudaMemcpyDeviceToHost); // copy the results of Kernel1 to CPU
CPUFunction(...); // assume it takes tCPU seconds
cudaMemcpy(...,...,...,cudaMemcpyHostToDevice); // copy data from the CPU to Kernel2
Kernel2<<<...,...>>>(...); // assume it takes t2 seconds

我使用的是cudaDeviceSynchronize()还是cudaMemcpy来获取同步并不重要。

仅在一个 GPU 上的for循环中执行上述代码片段的成本是

t1 + tCPU + t2 + t1 + tCPU +

t2 = 2t1 + 2tCPU + 2t2

对于2 GPU,如果您能够在两个不同的 GPU 上实现执行 Kernel1Kernel2的完美并发性,那么执行上述代码片段的成本将是

t1(在两个 GPU 上并发执行Kernel1)+ 2*tCPU(您需要对 CPU 函数进行两次调用,每次调用 CPU 函数的不同实例的输出 Kernel1 ) + t2(在两个 GPU 上并发执行Kernel2

因此,使用两个 GPU 而不是一个 GPU 实现的加速比将是

2*(t1 + tCPU + t2))/(t1 + 2tCPU + t2)

当 tCPU 等于零时,加速比变为2

这是阿姆达尔定律的表达。

相关内容

  • 没有找到相关文章

最新更新