MPI是一种消息传递库规范。接口规范已经在C/c++和Fortran程序中定义好了。提供的示例使用了C语言和LAM/MPI.LAM/MPI是一种高质量消息传递接口(MPI)的实现。
   
    例1:demo.c
   
    #include “mpi.h”
   
    #include <stdio.h>
   
    int main(int argc,char *argv[])
   
    {
   
    int  numtasks, rank, rc;
   
    MPI_Init(&argc,&argv);
   
    MPI_Comm_size(MPI_COMM_WORLD,&numtasks);
   
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);
   
    printf (“Number of tasks= %d My rank= %dn”, numtasks,rank);
   
    MPI_Finalize();
   
    }
   
    命令
   
    lamboot
   
    mpicc -o demo demo.c
   
    mpirun -np <number of processes> demo

    结果

    下一个示例使用MPI来设计矩阵乘法。

   一个大小为N的矩阵,该矩阵可以被搬运数整除(比如:一个矩阵的大小为4,那么搬运数也为4,每个搬运工将从矩阵A中领取1行)。控制器给每个搬运工发送同等数量的行的矩阵A,全矩阵B和追查行的位置偏移。每个搬运工接收控制器发送的信息,并完成有关行的矩阵乘法,并创建结果矩阵C的相关行,将它发送给偏移行的位置。控制器从每个搬运工那接收所有矩阵C的结果行,并完成结果矩阵。
   
    例2:
   
    /**********************************************************************
   
    * MPI-based matrix multiplication AxB=C
   
    *********************************************************************/
   
    #include <stdio.h>
   
    #include “mpi.h”
   
    #define N    4        /* number of rows and columns in matrix */
   
    MPI_Status status;
   
    double a[N][N],b[N][N],c[N][N];
   
    main(int argc, char **argv)
   
    {
   
    int numtasks,taskid,numworkers,source,dest,rows,offset,i,j,k;
   
    struct timeval start, stop;
   
    MPI_Init(&argc, &argv);
   
    MPI_Comm_rank(MPI_COMM_WORLD, &taskid);
   
    MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
   
    numworkers = numtasks-1;
   
    /*---------------------------- master ----------------------------*/
   
    if (taskid == 0) {
   
    for (i=0; i<N; i++) {
   
    for (j=0; j<N; j++) {
   
    a[i][j]= 1.0;
   
    b[i][j]= 2.0;
   
    }
   
    }
   
    gettimeofday(&start, 0);
   
    /* send matrix data to the worker tasks */
   
    rows = N/numworkers;
   
    offset = 0;
   
    for (dest=1; dest<=numworkers; dest++)
   
    {
   
    MPI_Send(&offset, 1, MPI_INT, dest, 1, MPI_COMM_WORLD);
   
    MPI_Send(&rows, 1, MPI_INT, dest, 1, MPI_COMM_WORLD);
   
    MPI_Send(&a[offset][0], rows*N, MPI_DOUBLE,dest,1, MPI_COMM_WORLD);
   
    MPI_Send(&b, N*N, MPI_DOUBLE, dest, 1, MPI_COMM_WORLD);
   
    offset = offset + rows;
   
    }
   
    /* wait for results from all worker tasks */
   
    for (i=1; i<=numworkers; i++)
   
    {
   
    source = i;
   
    MPI_Recv(&offset, 1, MPI_INT, source, 2, MPI_COMM_WORLD, &status);
   
    MPI_Recv(&rows, 1, MPI_INT, source, 2, MPI_COMM_WORLD, &status);
   
    MPI_Recv(&c[offset][0], rows*N, MPI_DOUBLE, source, 2, MPI_COMM_WORLD, &status);
   
    }
   
    gettimeofday(&stop, 0);
   
    printf(“Here is the result matrix:n”);
   
    for (i=0; i<N; i++) {
   
    for (j=0; j<N; j++)
   
    printf(“%6.2f   ”, c[i][j]);
   
    printf (“n”);
   
    }
   
    fprintf(stdout,“Time = %.6fnn”,
   
    (stop.tv_sec+stop.tv_usec*1e-6)-(start.tv_sec+start.tv_usec*1e-6));
   
    }
   
    /*---------------------------- worker----------------------------*/
   
    if (taskid > 0) {
   
    source = 0;
   
    MPI_Recv(&offset, 1, MPI_INT, source, 1, MPI_COMM_WORLD, &status);
   
    MPI_Recv(&rows, 1, MPI_INT, source, 1, MPI_COMM_WORLD, &status);
   
    MPI_Recv(&a, rows*N, MPI_DOUBLE, source, 1, MPI_COMM_WORLD, &status);
   
    MPI_Recv(&b, N*N, MPI_DOUBLE, source, 1, MPI_COMM_WORLD, &status);
   
    /* Matrix multiplication */
   
    for (k=0; k<N; k++)
   
    for (i=0; i<rows; i++) {
   
    c[i][k] = 0.0;
   
    for (j=0; j<N; j++)
   
    c[i][k] = c[i][k] + a[i][j] * b[j][k];
   
    }
   
    MPI_Send(&offset, 1, MPI_INT, 0, 2, MPI_COMM_WORLD);
   
    MPI_Send(&rows, 1, MPI_INT, 0, 2, MPI_COMM_WORLD);
   
    MPI_Send(&c, rows*N, MPI_DOUBLE, 0, 2, MPI_COMM_WORLD);
   
    }
   
    MPI_Finalize();
   
    }
   
    结果

 

接下来,我们优化代码,让它符合以下要求:
   
    应使用#define N 定义矩阵的大小。
   
    矩阵中的元素类型应该是“float”.
   
    矩阵可以是方形矩阵(例如,N*N),但N不能恰好被处理器的数量整除
   
    应检查计算打印结果矩阵的正确性。可使用#define PRINT定义打印代码段
   
    应找到这种代码加速(例如:对于N = 100,200等)与连续矩阵乘法代码比较。
   
    例3:解决方案
   
    /**********************************************************************
   
    * MPI-based matrix multiplication AxB=C
   
    *********************************************************************/
   
    #include <stdio.h>
   
    #include <sys/time.h>
   
    #include “mpi.h”
   
    #define N    500        /* number of rows and columns in matrix */
   
    MPI_Status status;
   
    float a[N][N],b[N][N],c[N][N];
   
    main(int argc, char **argv)
   
    {
   
    int numtasks,taskid,numworkers,source,dest,rows,offset,remain,i,j,k;
   
    struct timeval start, stop;
   
    MPI_Init(&argc, &argv);
   
    MPI_Comm_rank(MPI_COMM_WORLD, &taskid);
   
    MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
   
    numworkers = numtasks-1;
   
    /*---------------------------- master ----------------------------*/
   
    if (taskid == 0) {
   
    for (i=0; i<N; i++) {
   
    for (j=0; j<N; j++) {
   
    a[i][j]= 1.0;
   
    b[i][j]= 2.0;
   
    }
   
    }
   
    #ifdef PRINT
   
    /* print matrices */
   
    printf(“Matrix A:n”);
   
    for (i=0; i<N; i++){
   
    for (j=0; j<N; j++)
   
    printf(“%.3ft”,a[i][j]);
   
    printf(“n”);
   
    }
   
    printf(“Matrix B:n”);
   
    for (i=0; i<N; i++){
   
    for (j=0; j<N; j++)
   
    printf(“%.3ft”,b[i][j]);
   
    printf(“n”);
   
    }
   
    #endif
   
    gettimeofday(&start, 0);
   
    /* send matrix data to the worker tasks */
   
    if (N <= numworkers)
   
    {
   
    rows = 1;
   
    }
   
    else
   
    {
   
    if (N%numworkers!=0) // Not divisible by numworkers
   
    {
   
    rows = N/numworkers+1;
   
    remain = N%numworkers;
   
    }
   
    else
   
    {
   
    rows = N/numworkers;
   
    }
   
    }
   
    offset = 0;
   
    for (dest=1; dest<=numworkers; dest++, remain--)
   
    {
   
    MPI_Send(&offset, 1, MPI_INT, dest, 1, MPI_COMM_WORLD);
   
    MPI_Send(&rows, 1, MPI_INT, dest, 1, MPI_COMM_WORLD);
   
    MPI_Send(&a[offset][0], rows*N, MPI_FLOAT,dest,1, MPI_COMM_WORLD);
   
    MPI_Send(&b, N*N, MPI_FLOAT, dest, 1, MPI_COMM_WORLD);
   
    offset = offset + rows;
   
    if(remain==1) rows-=1;
   
    }
   
    /* wait for results from all worker tasks */
   
    for (i=1; i<=numworkers; i++)
   
    {
   
    source = i;
   
    MPI_Recv(&offset, 1, MPI_INT, source, 2, MPI_COMM_WORLD, &status);
   
    MPI_Recv(&rows, 1, MPI_INT, source, 2, MPI_COMM_WORLD, &status);
   
    MPI_Recv(&c[offset][0], rows*N, MPI_FLOAT, source, 2, MPI_COMM_WORLD, &status);
   
    }
   
    gettimeofday(&stop, 0);
   
    #ifdef PRINT
   
    printf(“Here is the result matrix:n”);
   
    for (i=0; i<N; i++) {
   
    for (j=0; j<N; j++)
   
    printf(“%6.2f   ”, c[i][j]);
   
    printf (“n”);
   
    }
   
    #endif
   
    fprintf(stdout,“Time = %.6fnn”,
   
    (stop.tv_sec+stop.tv_usec*1e-6)-(start.tv_sec+start.tv_usec*1e-6));
   
    }
   
    /*---------------------------- worker----tbw------------------------*/
   
    if (taskid > 0) {
   
    source = 0;
   
    MPI_Recv(&offset, 1, MPI_INT, source, 1, MPI_COMM_WORLD, &status);
   
    MPI_Recv(&rows, 1, MPI_INT, source, 1, MPI_COMM_WORLD, &status);
   
    MPI_Recv(&a, rows*N, MPI_FLOAT, source, 1, MPI_COMM_WORLD, &status);
   
    MPI_Recv(&b, N*N, MPI_FLOAT, source, 1, MPI_COMM_WORLD, &status);
   
    /* Matrix multiplication */
   
    for (k=0; k<N; k++)
   
    for (i=0; i<rows; i++) {
   
    c[i][k] = 0.0;
   
    for (j=0; j<N; j++)
   
    c[i][k] = c[i][k] + a[i][j] * b[j][k];
   
    }
   
    MPI_Send(&offset, 1, MPI_INT, 0, 2, MPI_COMM_WORLD);
   
    MPI_Send(&rows, 1, MPI_INT, 0, 2, MPI_COMM_WORLD);
   
    MPI_Send(&c, rows*N, MPI_FLOAT, 0, 2, MPI_COMM_WORLD);
   
    }
   
    MPI_Finalize();
   
    }