自从 CUDA 4.0 发布以来,您所询问的类型的多 GPU 计算相对容易。在此之前,您需要使用多线程主机应用程序,每个 GPU 有一个主机线程以及某种线程间通信系统,以便在同一主机应用程序中使用多个 GPU。
现在可以对主机代码的内存分配部分执行类似的操作:
double *dev_a[2], *dev_b[2], *dev_c[2];
const int Ns[2] = {N/2, N-(N/2)};
// allocate the memory on the GPUs
for(int dev=0; dev<2; dev++) {
cudaSetDevice(dev);
cudaMalloc( (void**)&dev_a[dev], Ns[dev] * sizeof(double) );
cudaMalloc( (void**)&dev_b[dev], Ns[dev] * sizeof(double) );
cudaMalloc( (void**)&dev_c[dev], Ns[dev] * sizeof(double) );
}
(免责声明:在浏览器中编写,从未编译,从未测试,使用风险自负)。
这里的基本思想是你使用cudaSetDevice
当您在设备上执行操作时,可以在设备之间进行选择。因此,在上面的代码片段中,我假设了两个 GPU,并在每个设备上分配了内存 [第一个设备上的 (N/2) 个双倍,第二个设备上的 N-(N/2) 个]。
从主机到设备的数据传输可以简单如下:
// copy the arrays 'a' and 'b' to the GPUs
for(int dev=0,pos=0; dev<2; pos+=Ns[dev], dev++) {
cudaSetDevice(dev);
cudaMemcpy( dev_a[dev], a+pos, Ns[dev] * sizeof(double), cudaMemcpyHostToDevice);
cudaMemcpy( dev_b[dev], b+pos, Ns[dev] * sizeof(double), cudaMemcpyHostToDevice);
}
(免责声明:在浏览器中编写,从未编译,从未测试,使用风险自负)。
代码的内核启动部分可能类似于:
for(int i=0;i<10000;++i) {
for(int dev=0; dev<2; dev++) {
cudaSetDevice(dev);
add<<<NB,NT>>>( dev_a[dev], dev_b[dev], dev_c[dev], Ns[dev] );
}
}
(免责声明:在浏览器中编写,从未编译,从未测试,使用风险自负)。
请注意,我在内核调用中添加了一个额外的参数,因为可能会使用不同数量的要处理的数组元素来调用内核的每个实例。我会将其留给您来完成所需的修改。
但是,同样,基本思想是相同的:使用cudaSetDevice
选择一个给定的 GPU,然后以正常方式在其上运行内核,每个内核都有自己独特的参数。
您应该能够将这些部分组合在一起以生成简单的多 GPU 应用程序。还有很多其他功能可以在最新的 CUDA 版本和硬件中使用来协助多个 GPU 应用程序(例如统一寻址、点对点设施更多),但这应该足以让您入门。 CUDA SDK 中还有一个简单的多 GPU 应用程序,您可以查看更多想法。