Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
多GPU Cuda计算_Cuda_Dot Product_Multi Gpu - Fatal编程技术网

多GPU Cuda计算

多GPU Cuda计算,cuda,dot-product,multi-gpu,Cuda,Dot Product,Multi Gpu,我是多gpu编程的新手,我对多gpu计算有一些问题。例如,让我们以点积为例。我正在运行一个CPU线程,它创建了两个大型阵列a[N]和B[N]。由于这些阵列的大小,我需要将它们的点积计算分成2个GPU,这两个GPU都是特斯拉M2050(计算能力2.0)。问题是我需要在CPU线程控制的do循环中多次计算这些点积。每个点积都需要上一个点积的结果。我读过关于创建两个不同的线程分别控制两个不同的GPU(如cuda上的示例所述),但我不知道如何在它们之间同步和交换数据。还有其他选择吗?我真的非常感谢任何帮助

我是多gpu编程的新手,我对多gpu计算有一些问题。例如,让我们以点积为例。我正在运行一个CPU线程,它创建了两个大型阵列a[N]和B[N]。由于这些阵列的大小,我需要将它们的点积计算分成2个GPU,这两个GPU都是特斯拉M2050(计算能力2.0)。问题是我需要在CPU线程控制的do循环中多次计算这些点积。每个点积都需要上一个点积的结果。我读过关于创建两个不同的线程分别控制两个不同的GPU(如cuda上的示例所述),但我不知道如何在它们之间同步和交换数据。还有其他选择吗?我真的非常感谢任何帮助/例子。提前谢谢

要创建多个线程,可以使用OpenMP或pthreads。要执行您所说的操作,似乎需要创建并启动两个线程(omp parallel section,或pthread_create),让每个线程执行其部分计算,并将其中间结果存储在单独的进程范围变量中(回想一下,全局变量在进程的线程之间自动共享,因此原始线程将能够看到两个派生线程所做的更改)。要使原始线程等待其他线程完成,请同步(使用全局屏障或线程连接操作)并在两个衍生线程完成后将结果合并到原始线程中(如果将数组拆分为两半,并通过乘以相应的元素并对两半执行全局求和缩减来计算点积,则只需将两个衍生线程的两个中间结果相加)


您还可以使用MPI或fork,在这种情况下,通信可以以类似于网络编程的方式完成…管道/套接字或通过(阻塞)进行通信和同步发送和接收。

在CUDA 4.0之前,多GPU编程需要多线程CPU编程。这可能是一个挑战,尤其是当您需要在线程或GPU之间进行同步和/或通信时。如果所有并行性都在GPU代码中,那么多CPU线程可能会增加软件的复杂性不需要进一步提高GPU的性能

因此,从CUDA 4.0开始,您可以从一个单线程主机程序轻松编程多个GPU

对多个GPU进行编程可以如此简单:

int numDevs = 0;
cudaGetNumDevices(&numDevs);
...
for (int d = 0; d < numDevs; d++) {
    cudaSetDevice(d);
    kernel<<<blocks, threads>>>(args);
}
(我承认,如果n不是numDevs的偶数倍,那么上面的索引是不正确的,但我将把修复它作为读者的练习。)

这很简单,是一个很好的开始。首先让它工作,然后优化

一旦你让它工作起来,如果你在设备上所做的一切都是点产品,你会发现你的带宽受到限制——主要是通过PCI-e,而且你也不会在设备之间获得并发性,因为推力:
internal\u product
是同步的,因为回读会返回结果。所以你可以使用cudaMemcpyAsync(设备向量构造函数将使用cudaMemcpy)。但更简单、可能更有效的方法是使用“零拷贝”——直接访问主机内存(也在上面链接的多gpu编程演示文稿中讨论)。因为您所做的只是读取每个值一次并将其添加到总和中(并行重用发生在共享内存副本中),您可以直接从主机读取,而不是从主机到设备复制,然后从内核中的设备内存读取。此外,您还需要在每个GPU上异步启动内核,以确保最大的并发性

你可以这样做:

int bytes = sizeof(float) * n;
cudaHostAlloc(h_vecA, bytes, cudaHostAllocMapped | cudaHostAllocPortable);
cudaHostAlloc(h_vecB, bytes, cudaHostAllocMapped | cudaHostAllocPortable);
cudaHostAlloc(results, numDevs * sizeof(float), cudaHostAllocMapped | cudaHostAllocPortable);
// ... then fill your input arrays h_vecA and h_vecB


for (int d = 0; d < numDevs; d++) {
    cudaSetDevice(d);
    cudaEventCreate(event[d]));
    cudaHostGetDevicePointer(&dptrsA[d], h_vecA, 0);
    cudaHostGetDevicePointer(&dptrsB[d], h_vecB, 0);
    cudaHostGetDevicePointer(&dresults[d], results, 0);
}

...

for (int d = 0; d < numDevs; d++) {
    cudaSetDevice(d);
    int first = d * (n/d);
    int last   = (d+1)*(n/d)-1;
    my_inner_product<<<grid, block>>>(&dresults[d], 
                                      vecA+first, 
                                      vecA+last, 
                                      vecB+first, 0.f);
    cudaEventRecord(event[d], 0);
}

// wait for all devices
float total = 0.0f;
for (int d = 0; d < devs; d++) {
    cudaEventSynchronize(event[d]);
    total += results[numDevs];
}
int bytes=sizeof(float)*n;
cudaHostAlloc(h_vecA,字节,cudaHostAllocMapped | cudaHostAllocPortable);
cudaHostAlloc(h_vecB,字节,cudaHostAllocMapped | cudaHostAllocPortable);
cudaHostAlloc(结果,numDevs*sizeof(浮动),cudaHostAllocMapped | cudaHostAllocPortable);
//…然后填充您的输入数组h_vecA和h_vecB
对于(int d=0;d
这个实现不会大大降低我的应用程序的加速比吗?由于GPU-CPU-CPU-GPU之间的频繁通信。我看到了一些关于属于不同设备的并发流的信息,这些信息可能会对我有所帮助,但我找不到有用的例子。谢谢你详细而有用的回答!@harrism,链接to您的演示文稿已过时。您能再次上传吗?谢谢。请改为。
int bytes = sizeof(float) * n;
cudaHostAlloc(h_vecA, bytes, cudaHostAllocMapped | cudaHostAllocPortable);
cudaHostAlloc(h_vecB, bytes, cudaHostAllocMapped | cudaHostAllocPortable);
cudaHostAlloc(results, numDevs * sizeof(float), cudaHostAllocMapped | cudaHostAllocPortable);
// ... then fill your input arrays h_vecA and h_vecB


for (int d = 0; d < numDevs; d++) {
    cudaSetDevice(d);
    cudaEventCreate(event[d]));
    cudaHostGetDevicePointer(&dptrsA[d], h_vecA, 0);
    cudaHostGetDevicePointer(&dptrsB[d], h_vecB, 0);
    cudaHostGetDevicePointer(&dresults[d], results, 0);
}

...

for (int d = 0; d < numDevs; d++) {
    cudaSetDevice(d);
    int first = d * (n/d);
    int last   = (d+1)*(n/d)-1;
    my_inner_product<<<grid, block>>>(&dresults[d], 
                                      vecA+first, 
                                      vecA+last, 
                                      vecB+first, 0.f);
    cudaEventRecord(event[d], 0);
}

// wait for all devices
float total = 0.0f;
for (int d = 0; d < devs; d++) {
    cudaEventSynchronize(event[d]);
    total += results[numDevs];
}