在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个进程都在本机!而通常情况下,我们的要求是要在集群中跑程序,那么所需要完成的事情有:
- 在节点上都安装MPI、CUDA相关的库,
- 把程序copy到每一个节点的相同目录下。
- 新建hostfile文件,里面写上所有节点的IP(或机器名)
- 执行
mpirun -hostfile hostfile -np 10 ./test
mpirun -hostfile hostfile -np 10 ./test
PS: 使用前面的程序,可以看到各机器跑了哪些进程,方便理解。 Categories: Cuda&MPI