Duxy's

a digged hole

在MPI框架下使用CUDA开发

接到任务:研究MPI与CUDA的使用。以前只是听了听课,从来没有实际操作过。于是做了一些简单的实验,来熟悉这两个东东的使用。

程序

MPI与CUDA本身的使用就不在这里多列了,主要是讲解如何联合开发和编译。
其实用起来还是比较简单的,都是基于C语言的程序。

先开发一套使用CUDA实现的函数,其基本形式如下:

#include <stdio.h>

__global__
void saxpy(int n, float a, float *x, float *y)
{
  int i = blockIdx.x*blockDim.x + threadIdx.x;
  if (i < n) y[i] = a*x[i] + y[i];
}

void deal()
{
  int N = 1<<20;
  float *x, *y, *d_x, *d_y;
  x = (float*)malloc(N*sizeof(float));
  y = (float*)malloc(N*sizeof(float));

  cudaMalloc(&d_x, N*sizeof(float)); 
  cudaMalloc(&d_y, N*sizeof(float));

  for (int i = 0; i < N; i++) {
    x[i] = 1.0f;
    y[i] = 2.0f;
  }

  cudaMemcpy(d_x, x, N*sizeof(float), cudaMemcpyHostToDevice);
  cudaMemcpy(d_y, y, N*sizeof(float), cudaMemcpyHostToDevice);

  // Perform SAXPY on 1M elements
  saxpy<<<(N+255)/256, 256>>>(N, 2.0f, d_x, d_y);

  cudaMemcpy(y, d_y, N*sizeof(float), cudaMemcpyDeviceToHost);

  float maxError = 0.0f;
  for (int i = 0; i < N; i++)
    maxError = max(maxError, abs(y[i]-4.0f));
  printf("Max error: %f\n", maxError);
}

将原本的main函数改造了一下,定义了一个头文件暴露接口,这就成了一个使用CUDA开发的运行库了。

使用cpp文件编写MPI程序,在其中引入上面编写的头文件,然后在MPI调用的过程中调用该函数。

#include <stdio.h>
#include <mpi.h>
#include "saxpy.h"

int main(int argc, char *argv[]) {
    char hostname[MPI_MAX_PROCESSOR_NAME];
    int task_count;
    int rank;
    int len;
    int ret;

    ret = MPI_Init(&argc, &argv);
    if (MPI_SUCCESS != ret) {
        printf("start mpi fail\n");
        MPI_Abort(MPI_COMM_WORLD, ret);
    }

    MPI_Comm_size(MPI_COMM_WORLD, &task_count);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Get_processor_name(hostname, &len);

    printf("task_count = %d, my rank = %d on %s\n", task_count, rank, hostname);

    deal();//在此调用用cuda写的函数

    MPI_Finalize();

    return 0;
}

编译

由于编译条件不同,所以将上述两个文件分别编译:

nvcc -c saxpy.cu -o saxpy.o
mpicxx -c mpif.cpp -o mpif.o

然后使用mpi的编译器mpixx联编:

mpicxx mpif.o saxpy.o -L/usr/local/cuda/lib64 -lcudart -o test

就有了可执行程序test了

运行

运行其实就是mpi程序的运行,只不过是运行过程中有GPU的调用而已。

使用mpirun -np 10 ./test,就可以建立10个进程来跑程序。这10个进程都在本机!而通常情况下,我们的要求是要在集群中跑程序,那么所需要完成的事情有:
1. 在节点上都安装MPI、CUDA相关的库,
2. 把程序copy到每一个节点的相同目录下。
3. 新建hostfile文件,里面写上所有节点的IP(或机器名)
4. 执行mpirun -hostfile hostfile -np 10 ./test

PS: 使用前面的程序,可以看到各机器跑了哪些进程,方便理解。