这里主要介绍MPI框架,以及怎样将其与CUDA结合起来运用。
1. MPI
MPI可以视为大一号的CUDA。一个MPI框架由分布式计算节点组成,每一个节点可以视为是一个“Thread”,但这里的不同之处在于这些节点没有所谓的共享内存,或者说Global Memory。所以,在后面也会看到,一般会有一个节点专门处理数据传输和分配的问题。MPI和CUDA的另一个不同之处在于MPI只有一级结构,即所有的节点都在一个全局命名空间下,不像CUDA那样有Grid/Block/Thread三级层次。MPI同样也是基于SPMD模型,所有的节点执行相同的指令,而每个节点根据自己的ID来确定指令处理的数据,产生相应的输出。
2. MPI API
仍然以向量相加为例:
int main(int argc, char *argv[]) {
int size = 1024;
int pid = -1;
int np = -1;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &pid);
MPI_Comm_size(MPI_COMM_WORLD, &np);
if (np < 3) {
if (pid == 0) printf("Need 3 or more processes.\n");
MPI_Abort(MPI_COMM_WORLD, 1);
return 1;
}
if (pid < np - 1)
compute_node(size / (np - 1));
else
data_server(szie);
MPI_Finalize();
return 0;
}
上述代码展示了一个简单的向量相加的MPI实现。MPI_Init()和MPI_Finalize()用于初始化和结束MPI框架;MPI_COMM_WORLD代表了所有分配到的节点的集群;MPI_Comm_rank()用于获取节点在集群中的标号,相当与CUDA中的threadIdx.x;MPI_Comm_size()用于获取集群节点的数量,相当于blockDim.x;MPI_Abort()用于中止执行。
如前所述,有一个节点,也就是np-1节点,来负责数据的传输和分配,而其他的节点则负责计算。
3. 节点间通信
并行计算节点间的通信是必不可少的部分