在 Mpi框架下使用 Cuda开发

在MPI框架下使用CUDA开发 #

Date: 2015/11/2

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

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);
}

#include <stdio.h>

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

void deal() { int N = 1«20; float x, y, d_x, d_y; x = (float)malloc(Nsizeof(float)); y = (float)malloc(Nsizeof(float));

cudaMalloc(&d_x, Nsizeof(float)); cudaMalloc(&d_y, Nsizeof(float));

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

cudaMemcpy(d_x, x, Nsizeof(float), cudaMemcpyHostToDevice); cudaMemcpy(d_y, y, Nsizeof(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;
}

#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.ompicxx -c mpif.cpp -o mpif.o

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

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

mpirun -hostfile hostfile -np 10 ./test

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