MPI - 消息傳遞接口

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

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章