Michael J. Quinn, 《Parallel Programming in C with MPI and OpenMP》程序代码

来源:互联网 发布:股票预测算法 编辑:程序博客网 时间:2024/06/08 06:07

本文中是Michael J. Quinn在书《Parallel Programming in C with MPI and OpenMP》(中文《MPI与OpenMP并行程序设计:C语言版》,陈文光、武永卫等译)中所使用的MyMPI.h和MyMPI.c文件. 有小部分细节上的调整,并经过测试可用.

MyMPI.h

/* MyMPI.h * * Header file for a library of matrix/vector * input/output/redistribution functions. * * Programed by Michael J. Quinn * Last modification: 4 September 2002 * "Parallel Programming in C with MPI and OpenMP" * Typed and modified by xiu_dim, 17 Nov. 2015 *//******************** MACROS *********************/#define DATA_MSG        0#define PROMPT_MSG      1#define RESPONSE_MSG    2#define OPEN_FILE_ERROR -1#define MALLOC_ERROR    -2#define TYPE_ERROR      -3#define PTR_SIZE        (sizeof(void *))#define MIN(a,b)        ((a)<(b)?(a):(b))#define CEILING(i,j)    (((i)+(j)-1)/(j))#define BLOCK_LOW(id,p,n)   ((id)*(n)/(p))#define BLOCK_HIGH(id,p,n)  (BLOCK_LOW((id)+1,p,n)-1)#define BLOCK_SIZE(id,p,n)  \            (BLOCK_HIGH(id,p,n)-BLOCK_LOW(id,p,n)+1)#define BLOCK_OWNER(j,p,n)  (((p)*((j)+1)-1)/(n))/************ MISCELLANEOUS FUNCTIONS ************/int get_size(MPI_Datatype);void* my_malloc(int, int);void terminate(int, char*);/********** DATA DISTRIBUTION FUNCTIONS **********/void create_mixed_xfer_arrays(int, int, int,         int**, int**);void create_uniform_xfer_arrays(int, int, int,         int**, int**);void replicate_block_vector(void*, int, void*,         MPI_Datatype, MPI_Comm);/**************** INPUT FUNCTIONS ****************/void read_row_striped_matrix(char*, void***, void**,         MPI_Datatype, int*, int*, MPI_Comm);void read_col_striped_matrix(char*, void***, void**,         MPI_Datatype, int*, int*, MPI_Comm);void read_checkerboard_matrix(char*, void***, void**,         MPI_Datatype, int*, int*, MPI_Comm);void read_block_vector(char*, void**, MPI_Datatype,         int*, MPI_Comm);void read_replicated_vector(char*, void**, MPI_Datatype,         int*, MPI_Comm);/**************** OUTPUT FUNCTIONS ***************/void print_submatrix(void**, MPI_Datatype, int, int);void print_subvector(void*, MPI_Datatype, int);void print_row_striped_matrix(void**, MPI_Datatype,         int, int, MPI_Comm);void print_col_striped_matrix(void**, MPI_Datatype,         int, int, MPI_Comm);void print_checkerboard_matrix(void**, MPI_Datatype,            int, int, MPI_Comm);void print_block_vector(void*, MPI_Datatype, int, MPI_Comm);void print_replicated_vector(void*, MPI_Datatype, int, MPI_Comm);

MyMPI.c

/* MyMPI.c -- A library of matrix/vector * input/output/redistribution functions. * * Programed by Michael J. Quinn * Last modification: 4 September 2002 * "Parallel Programming in C with MPI and OpenMP" * Typed and modified by xiu_dim, 17 Nov. 2015 */#include <mpi.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "MyMPI.h"/************ MISCELLANEOUS FUNCTIONS ************//* * Given MPI_DataType 't', function 'get_size' returns the * size of a single datum that data type. */int get_size(MPI_Datatype t){    if (t == MPI_BYTE) return sizeof(char);    if (t == MPI_DOUBLE) return sizeof(double);    if (t == MPI_FLOAT) return sizeof(float);    if (t == MPI_INT) return sizeof(int);    printf("Error: Unrecognized argument to 'get_size'\n");    fflush(stdout);    MPI_Abort(MPI_COMM_WORLD, TYPE_ERROR);}/* * Function 'my_malloc' is called when a process wants * to allocate some space from the heap. If the memory * allocation fails, the process prints an error message * and then aborts execution of the program. */void *my_malloc(    int id,    /* IN - Process rank */    int bytes) /* IN - Bytes to allocate */{    void *buffer;    if ((buffer = malloc((size_t)bytes)) == NULL) {        printf("Error:Malloc failed for process %d\n", id);        fflush(stdout);        MPI_Abort(MPI_COMM_WORLD, MALLOC_ERROR);    }    return buffer;}/* * Function 'terminate' is called when the program should * not continue execution, due to an error conditon that * all of the processes are aware of. Process 0 prints the * error message passed as an argument to the function. *  * All processes must invoke this function together! */void terminate(    int id,              /* IN - Process rank */    char *error_message) /* IN - Message to print */{    if (!id) {        printf("Error: %s\n", error_message);        fflush(stdout);    }    MPI_Finalize();    exit(-1);}/********** DATA DISTRIBUTION FUNCTIONS **********//* * This function creates the count and displacement arrays * needed by scatter and gather functions, when the number * of elements send/received to/from other processes varies. */void create_mixed_xfer_arrays(    int id,      /* IN - Process rank */    int p,       /* IN - Number of processes */    int n,       /* IN - Total number of elements */    int **count, /* OUT - Array of counts */    int **disp)  /* OUT - Array of displacements */{    int i;    *count = my_malloc(id, p*sizeof(int));    *disp = my_malloc(id, p*sizeof(int));    (*count)[0] = BLOCK_SIZE(0,p,n);    (*disp)[0] = 0;    for (i=1; i<p; ++i) {        (*disp)[i] = (*disp)[i-1] + (*count)[i-1];        (*count)[i] = BLOCK_SIZE(i,p,n);    }    return;}/* * This function creates the count and displacement arrays * needed in an all-to-all exchange, when a process gets  * the same number of elements from every other process. */void create_uniform_xfer_arrays(    int id,      /* IN - Process rank */    int p,       /* IN - Number of processes */    int n,       /* IN - Total number of elements */    int **count, /* OUT - Array of counts */    int **disp)  /* OUT - Array of displacements */{    int i;    *count = my_malloc(id, p*sizeof(int));    *disp = my_malloc(id, p*sizeof(int));    (*count)[0] = BLOCK_SIZE(id,p,n);    (*disp)[0] = 0;    for (i=1; i<p; ++i) {        (*disp)[i] = (*disp)[i-1] + (*count)[i-1];        (*count)[i] = BLOCK_SIZE(id,p,n);    }    return;}/* * This function is used to transform a vector from a  * block distribution to a replicated distribution within   * a communicator. */void replicate_block_vector(    void *ablock,       /* IN - Block-distributed vector */    int n,              /* IN - Number of elements in vector */    void *arep,         /* OUT - Replicated vector */    MPI_Datatype dtype, /* IN - Vector element type */    MPI_Comm comm)      /* IN - Communicator */{    int p;     /* Number of processes */    int id;    /* Process rank */    int *cnt;  /* Number of elements contributed by each process */    int *disp; /* Displacement in concatenated array */    MPI_Comm_size(comm, &p);    MPI_Comm_rank(comm, &id);    create_mixed_xfer_arrays(id, p, n, &cnt, &disp);    MPI_Allgatherv(ablock, cnt[id], dtype, arep,             cnt, disp, dtype, comm);    free(cnt);    free(disp);    return;}/**************** INPUT FUNCTIONS ****************//* * In the matrix file, the first two elemnts are  * integers whose values are the dimensions of the  * matrix ('m' rows and 'n' columns). What follows  * are 'm'*'n' values representing the matrix elements  * stored in row-major order. *//* * Process p-1 opens a file and inputs a two-dimensional * matrix, reading and distributing blocks of rows to the * other MPI processes. */void read_row_striped_matrix(    char *s,            /* IN - File name */    void ***subs,       /* OUT - Submatrix row indices */    void **storage,     /* OUT - Submatrix stored here */    MPI_Datatype dtype, /* IN - Matrix element type */    int *m,             /* OUT - Number of rows in matrix */    int *n,             /* OUT - Number of cols in matrix */    MPI_Comm comm)      /* IN - Communicator */{    int p;             /* Number of processes */    int id;            /* Process rank */    int datum_size;    /* Size of matrix element */    int local_rows;    /* Number of rows in this process */    FILE *infileptr;   /* Input file poiter */    void **lptr;       /* Pointer into 'subs' */    void *rptr;        /* Pointer into 'storage' */    MPI_Status status; /* Result of receive */    int x;             /* Result of read */    int i;    MPI_Comm_size(comm, &p);    MPI_Comm_rank(comm, &id);    datum_size = get_size(dtype);    /* Process p-1 opens the file 's' */    if (id == p-1) {        infileptr = fopen(s, "r");        if (infileptr == NULL) *m = 0;        else {            x = fread(m, sizeof(int), 1, infileptr);            x = fread(n, sizeof(int), 1, infileptr);        }    }    /* Process p-1 broadcasts 'm' in communicator 'comm' */    MPI_Bcast(m, 1, MPI_INT, p-1, comm);    if (!(*m)) MPI_Abort(MPI_COMM_WORLD, OPEN_FILE_ERROR);    /* Process p-1 broadcasts 'n' in communicator 'comm' */    MPI_Bcast(n, 1, MPI_INT, p-1, comm);    /* Number of rows in this process */    local_rows = BLOCK_SIZE(id,p,*m);    /* Allocate array for submatrix in this process */    *storage = (void *)my_malloc(id,                             local_rows*(*n)*datum_size);    /* Allocate array for row indices in this pointers */    *subs = (void **)my_malloc(id, local_rows*PTR_SIZE);    /* Connet 'subs' with 'storage' */    lptr = (void *)&(*subs[0]);    rptr = (void *)*storage;    for (i=0; i<local_rows; ++i) {        *(lptr++) = (void *)rptr;        rptr += (*n) * datum_size;    }    if (id == (p-1)) {        for (i=0; i<p-1; ++i) {            /* Process p-1 reads datum from 'infileptr'                and sends it together with tag 'DATA_MSG'                to process i in communicator 'comm' */            x = fread(*storage, datum_size,                     BLOCK_SIZE(i,p,*m)*(*n), infileptr);            MPI_Send(*storage, BLOCK_SIZE(i,p,*m)*(*n),                     dtype, i, DATA_MSG, comm);        }        /* Process p-1 reads datum from 'infileptr' */        x = fread(*storage, datum_size,                     BLOCK_SIZE(i,p,*m)*(*n), infileptr);        fclose(infileptr);    } else        /* This process receives datum from process p-1 */        MPI_Recv(*storage, local_rows*(*n), dtype, p-1,                     DATA_MSG, comm, &status);    return;}/* * Process p-1 opens a file and inputs a two-dimensional * matrix, reading and distributing blocks of columns to  * the other MPI processes. */void read_col_striped_matrix(    char *s,            /* IN - File name */    void ***subs,       /* OUT - 2-D array */    void **storage,     /* OUT - Array elements */    MPI_Datatype dtype, /* IN - Matrix element type */    int *m,             /* OUT - Number of rows in matrix */    int *n,             /* OUT - Number of cols in matrix */    MPI_Comm comm)      /* IN - Communicator */{    int p;             /* Number of processes */    int id;            /* Process rank */    int datum_size;    /* Size of matrix element */    int local_cols;    /* Number of cols in this process */    FILE *infileptr;   /* Input file poiter */    void *buffer;      /* File buffer */    void **lptr;       /* Pointer into 'subs' */    void *rptr;        /* Pointer into 'storage' */    int *send_count;   /* Each process's count */    int *send_disp;    /* Each process's displacement */    int i,j;    MPI_Comm_size(comm, &p);    MPI_Comm_rank(comm, &id);    datum_size = get_size(dtype);    /* Process p-1 opens the file 's' */    if (id == (p-1)) {        infileptr = fopen(s, "r");        if (infileptr == NULL) *m = 0;        else {            fread(m, sizeof(int), 1, infileptr);            fread(n, sizeof(int), 1, infileptr);        }    }    /* Process p-1 broadcasts 'm' in communicator 'comm' */    MPI_Bcast(m, 1, MPI_INT, p-1, comm);    if (!(*m)) MPI_Abort(comm, OPEN_FILE_ERROR);    /* Process p-1 broadcasts 'n' in communicator 'comm' */    MPI_Bcast(n, 1, MPI_INT, p-1, comm);    /* Number of cols in this process */    local_cols = BLOCK_SIZE(id,p,*n);    /* Dynamically allocate two-dimensional matrix 'subs' */    /* Allocate array for submatrix in this process */    *storage = my_malloc(id, (*m)*local_cols*datum_size);    /* Allocate array for row indices in this pointers */    *subs = (void **)my_malloc(id, (*m)*PTR_SIZE);    lptr = (void *)*subs;    rptr = (void *)*storage;    for (i=0; i<(*m); ++i) {        *(lptr++) = (void *)rptr;        rptr += local_cols * datum_size;    }    if (id == (p-1))        buffer = my_malloc(id, (*n)*datum_size);    create_mixed_xfer_arrays(id, p, *n, &send_count, &send_disp);    for (i=0; i<(*m); ++i) {        if (id == (p-1))            fread(buffer, datum_size, *n, infileptr);        MPI_Scatterv(buffer, send_count, send_disp, dtype,             (*storage)+i*local_cols*datum_size,             local_cols, dtype, p-1, comm);    }    free(send_count);    free(send_disp);    if (id == (p-1)) free(buffer);    return;}/* * This function allocate blocks of the matrix to * the MPI processes. * * The number of processes MUST be a square number. */void read_checkerboard_matrix(    char *s,            /* IN - File name */    void ***subs,       /* OUT - 2-D array */    void **storage,     /* OUT - Array elements */    MPI_Datatype dtype, /* IN - Matrix element type */    int *m,             /* OUT - Number of rows in matrix */    int *n,             /* OUT - Number of cols in matrix */    MPI_Comm grid_comm)      /* IN - Communicator */{    int p;              /* Number of processes */    int grid_id;        /* Process rank in grid */    int datum_size;     /* Size of matrix element */    int coords[2];      /* Coords of process receiving next row of matrix */    int grid_coords[2]; /* Coords of this process */    int grid_period[2]; /* Wraparound */    int grid_size[2];   /* Dimemsions of process grid */    int local_rows;     /* Number of matrix rows in this process */    int local_cols;     /* Number of matrix cols in this process */    FILE *infileptr;    /* Input file poiter */    void *buffer;       /* File buffer */    void **lptr;        /* Pointer into 'subs' */    void *rptr;         /* Pointer into 'storage' */    void *laddr;        /* Used when process 0 gets row */    void *raddr;        /* Address of first element to send */    int dest_id;        /* Rank of receiving process */    MPI_Status status;  /* Result of receive */    int i,j,k;    MPI_Comm_size(grid_comm, &p);    MPI_Comm_rank(grid_comm, &grid_id);    datum_size = get_size(dtype);    /* Process 0 opens file, get numbers of rows and cols,        and broadcasts this information to the other processes */    if (grid_id == 0) {        infileptr = fopen(s, "r");        if (infileptr == NULL) *m = 0;        else {            fread(m, sizeof(int), 1, infileptr);            fread(n, sizeof(int), 1, infileptr);        }    }    MPI_Bcast(m, 1, MPI_INT, 0, grid_comm);    if (!(*m)) MPI_Abort(MPI_COMM_WORLD, OPEN_FILE_ERROR);    MPI_Bcast(n, 1, MPI_INT, 0, grid_comm);    /* Each process determines the size of the submatrix       it is responsible for. */    MPI_Cart_get(grid_comm, 2, grid_size,         grid_period, grid_coords);    local_rows = BLOCK_SIZE(grid_coords[0],grid_size[0],*m);    local_cols = BLOCK_SIZE(grid_coords[1],grid_size[1],*n);    /* Dynamicaly allocate two-dimensional matrix 'subs' */    *storage = my_malloc(grid_id,         local_rows*local_cols*datum_size);    *subs = (void **)my_malloc(grid_id, local_rows*PTR_SIZE);    lptr = (void *)*subs;    rptr = (void *)*storage;    for (i=0; i<local_rows; ++i) {        *(lptr++) = (void *)rptr;        rptr += local_cols * datum_size;    }    /* Grid process 0 reads in the matrix one row at a time        and distributes each row among the MPI processes */    if (grid_id == 0)        buffer = my_malloc(grid_id, (*n)*datum_size);    /* For each row of processes in the process grid */    for (i=0; i<grid_size[0]; ++i) {        coords[0] = i;        /* For each matrix row controlled by this process row */        for (j=0; j<BLOCK_SIZE(i,grid_size[0],*m); ++j) {            /* Read in a row of the matrix */            if (grid_id == 0) {                fread(buffer, datum_size, *n, infileptr);            }            /* Distribute it among processes in the grid row */            for (k=0; k<grid_size[1]; ++k) {                coords[1] = k;                /* Find address of first element to send */                raddr = buffer +                     BLOCK_LOW(k,grid_size[1],*n) * datum_size;                /* Determine the grid ID of the process                   getting the subrow */                MPI_Cart_rank(grid_comm, coords, &dest_id);                if (grid_id == 0) {                /* Process 0 is responsible for sending */                    if (dest_id == 0) {                    /* It is sending(copying) to itself */                        laddr = (*subs)[j];                        memcpy(laddr, raddr,                             local_cols*datum_size);                    } else {                    /* It is sending to another process */                        MPI_Send(raddr,                             BLOCK_SIZE(k,grid_size[1],*n),                             dtype, dest_id, 0, grid_comm);                    }                } else if (grid_id == dest_id) {                /* Process 'dest_id' is responsible for receiving */                    MPI_Recv((*subs)[j], local_cols, dtype,                         0, 0, grid_comm, &status);                }            }        }    }    if (grid_id == 0) free(buffer);    return;}/* * Process p-1 opens a file containing a vector, reads  * its contents, and distributes the elements by block * among the processes in a communicator. */void read_block_vector(    char *s,            /* IN - File name */    void **v,           /* OUT - Subvector */    MPI_Datatype dtype, /* IN - Vector element type */    int *n,             /* OUT - Vector length */    MPI_Comm comm)      /* IN - Communicator */{    int p;             /* Number of processes */    int id;            /* Process rank */    int datum_size;    /* Size of vector element */    int local_els;     /* Number of elements in this process */    FILE *infileptr;   /* Input file poiter */    MPI_Status status; /* Result of receive */    int x;             /* Result of read */    int i;    MPI_Comm_size(comm,&p);    MPI_Comm_rank(comm, &id);    datum_size = get_size(dtype);    /* Process p-1 opens file, determines number of vector       elements, and broadcasts this value to the other        processes */    if (id == (p-1)) {        infileptr = fopen(s, "r");        if (infileptr == NULL) *n = 0;        else fread(n, sizeof(int), 1, infileptr);    }    MPI_Bcast(n, 1, MPI_INT, p-1, comm);    if (!(*n)) {        if (!id) {            printf("Input file '%s' cannot be opened\n", s);            fflush(stdout);        }    }    /* Block mapping of vetor elements to processes */    local_els = BLOCK_SIZE(id,p,*n);     *v = my_malloc(id, local_els*datum_size);     if (id == (p-1)) {         for (i=0; i<p-1; ++i) {             x = fread(*v, datum_size, BLOCK_SIZE(i,p,*n),                     infileptr);             MPI_Send(*v, BLOCK_SIZE(i,p,*n), dtype, i,                     DATA_MSG, comm);         }         x = fread(*v, datum_size, BLOCK_SIZE(id,p,*n),                 infileptr);         fclose(infileptr);     } else {         MPI_Recv(*v, BLOCK_SIZE(id,p,*n), dtype, p-1,                 DATA_MSG, comm, &status);      }    return;}/* * Process p-1 opens a file containing a vector, reads its  * contents, and replicates the vector among all processes * in a communicator. */void read_replicated_vector(    char *s,            /* IN - File name */    void **v,           /* OUT - Subvector */    MPI_Datatype dtype, /* IN - Vector element type */    int *n,             /* OUT - Vector length */    MPI_Comm comm)      /* IN - Communicator */{    int p;             /* Number of processes */    int id;            /* Process rank */    int datum_size;    /* Size of vector element */    FILE *infileptr;   /* Input file poiter */    int i;    /* Process p-1 opens file, determines number of vector       elements, and broadcasts this value to the other        processes */    MPI_Comm_size(comm, &p);    MPI_Comm_rank(comm, &id);    datum_size = get_size(dtype);    if (id == (p-1)) {        infileptr = fopen(s, "r");        if (infileptr == NULL) *n = 0;        else fread(n, sizeof(int), 1, infileptr);    }    MPI_Bcast(n, 1, MPI_INT, p-1, comm);    if (!(*n)) terminate(id, "Cannot open vector file!");    *v = my_malloc(id, (*n)*datum_size);    if (id == (p-1)) {        fread(*v, datum_size, *n, infileptr);        fclose(infileptr);    }    MPI_Bcast(*v, *n, dtype, p-1, MPI_COMM_WORLD);    return;}/**************** OUTPUT FUNCTIONS ***************//* * Print elements of a doubly subscripted array. */void print_submatrix(    void **a,           /* IN - Doubly subscripted array */    MPI_Datatype dtype, /* IN - Type of element */    int rows,           /* IN - Number of rows */    int cols)           /* IN - Number of columns */{    int i,j;    for (i=0; i<rows; ++i) {        for (j=0; j<cols; ++j) {            if (dtype == MPI_DOUBLE)                printf("%6.3f",((double **)a)[i][j]);            else {                if (dtype == MPI_FLOAT)                    printf("%6.3f",((float **)a)[i][j]);                else                    printf("%6d",((int **)a)[i][j]);            }        }        putchar('\n');    }    return;}/* * Print elements of a singly subscripted array. */void print_subvector(    void *a,            /* IN - Singly subscripted array */    MPI_Datatype dtype, /* IN - Type of elements */    int n)              /* IN - Size of array */{    int i;    for (i=0; i<n; ++i) {        if (dtype == MPI_DOUBLE)            printf("%6.3f ",((double *)a)[i]);        else {            if (dtype == MPI_FLOAT)                printf("%6.3f ",((float *)a)[i]);            else if (dtype == MPI_INT)                printf("%6d ",((int *)a)[i]);        }    }    return;}/*  * Process 0 prints a matrix that is distributed in row- * striped fashion among the processes in a communicator. */void print_row_striped_matrix(    void **a,           /* IN - 2D array */    MPI_Datatype dtype, /* IN - Matrix element type */    int m,              /* IN - Number of matrix rows */    int n,              /* IN - Number of matrix columns */    MPI_Comm comm)      /* IN - Communicator */{    int p;              /* Number of processes */    int id;             /* Process rank */    int datum_size;     /* Size of matrix element */    int local_rows;     /* Rows in this process */    int max_block_size; /* Most matrix rows held by any process */    void *bstorage;     /* Elements received from another process */    void **b;           /* 2D array indexing into 'bstorage' */    MPI_Status status;  /* Result of receive */    int prompt;         /* Dummy variable */    int i;    MPI_Comm_size(comm, &p);        MPI_Comm_rank(comm, &id);    datum_size = get_size(dtype);    local_rows = BLOCK_SIZE(id,p,n);    if (!id) {        print_submatrix(a, dtype, local_rows, n);        if (p >1) {            max_block_size = BLOCK_SIZE(p-1,p,m);            bstorage = (void *)my_malloc(id,                             max_block_size*n*datum_size);            b = (void **)my_malloc(id,                             max_block_size*PTR_SIZE);            b[0] = bstorage;            for (i=1; i<max_block_size; ++i) {                b[i] = b[i-1] + n * datum_size;            }            for (i=1; i<p; ++i) {                /* Send a prompt message to process i                     in the default communicator */                MPI_Send(&prompt, 1, MPI_INT, i,                             PROMPT_MSG, MPI_COMM_WORLD);                /* Receive datum with tag 'RESPONSE_MSG' from                      process i in the default communicator */                MPI_Recv(bstorage, BLOCK_SIZE(i,p,m)*n, dtype,                    i, RESPONSE_MSG, MPI_COMM_WORLD, &status);                print_submatrix(b, dtype, BLOCK_SIZE(i,p,m), n);            }            free(b);            free(bstorage);        }        putchar('\n');    } else {        /* Receive a prompt message from process 0             in the default communicator */        MPI_Recv(&prompt, 1, MPI_INT, 0, PROMPT_MSG,                     MPI_COMM_WORLD,&status);        /* Send datum with tag 'RESPONSE_MSG' to process 0            in the default communicator */        MPI_Send(*a, local_rows*n, dtype, 0, RESPONSE_MSG,                     MPI_COMM_WORLD);    }    return;}/*  * Process 0 prints a matrix that has a  * columnwise-block-striped data decompsition  * among the processes in a communicator. */void print_col_striped_matrix(    void **a,           /* IN - 2D array */    MPI_Datatype dtype, /* IN - Matrix element type */    int m,              /* IN - Number of matrix rows */    int n,              /* IN - Number of matrix columns */    MPI_Comm comm)      /* IN - Communicator */{    int p;              /* Number of processes */    int id;             /* Process rank */    int datum_size;     /* Size of matrix element */    void *buffer;       /* Buffer to hold one row */    int *rec_count;     /* Number of elements received per process */    int *rec_disp;      /* Offset of each process's block */    MPI_Status status;  /* Result of receive */    int i,j;    MPI_Comm_size(comm, &p);    MPI_Comm_rank(comm, &id);    datum_size = get_size(dtype);    create_mixed_xfer_arrays(id, p, n, &rec_count, &rec_disp);    if (!id) buffer = my_malloc(id, n*datum_size);    for (i=0; i<m; ++i) {        MPI_Gatherv(a[i], BLOCK_SIZE(id,p,n), dtype, buffer,            rec_count, rec_disp, dtype, 0, MPI_COMM_WORLD);        if (!id) {            print_subvector(buffer, dtype, n);            putchar('\n');        }    }    free(rec_count);    free(rec_disp);    if (!id) {        free(buffer);        putchar('n');    }    return;}/* * This function prints a matrix distributed checkerboard * fashion among the processes in a communicator. */void print_checkerboard_matrix(    void **a,           /* IN - 2D array */    MPI_Datatype dtype, /* IN - Matrix element type */    int m,              /* IN - Number of matrix rows */    int n,              /* IN - Number of matrix columns */    MPI_Comm grid_comm) /* IN - Communicator */{    int p;              /* Number of processes */    int grid_id;        /* Process rank in grid */    int datum_size;     /* Size of matrix element */    int coords[2];      /* Grid coords of process sending elements */    int grid_coords[2]; /* Coords of this process */    int grid_period[2]; /* Wraparound */    int grid_size[2];   /* Dimemsions of process grid */    int local_cols;     /* Number of matrix cols in this process */    int els;            /* Element received */    int src;            /* ID of process with subrow */    void *buffer;       /* Buffer to hold one matrix row */    void *laddr;        /* Address to put subrow */    MPI_Status status;  /* Result of receive */    int i,j,k;    MPI_Comm_size(grid_comm, &p);    MPI_Comm_rank(grid_comm, &grid_id);    datum_size = get_size(dtype);    MPI_Cart_get(grid_comm, 2, grid_size,         grid_period, grid_coords);    local_cols = BLOCK_SIZE(grid_coords[1],grid_size[1],n);    if (!grid_id)         buffer = my_malloc(grid_id, n*datum_size);    /* For each row of the process grid */    for (i=0; i<grid_size[0]; ++i) {        coords[0] = i;        /* For each matrix row controlled by the process row*/        for (j=0; j<BLOCK_SIZE(i,grid_size[0],m); ++j) {            /* Collect the matrix row on grid process 0 and                print it */            if (!grid_id) {                for (k=0; k<grid_size[1]; ++k) {                    coords[1] = k;                    MPI_Cart_rank(grid_comm, coords, &src);                    els = BLOCK_SIZE(k,grid_size[1],n);                    laddr = buffer +                         BLOCK_LOW(k,grid_size[1],n) * datum_size;                    if (src == 0) {                        memcpy(laddr, a[j], els*datum_size);                    } else {                        MPI_Recv(laddr, els, dtype, src, 0,                             grid_comm, &status);                    }                }                print_subvector(buffer, dtype, n);                putchar('\n');            } else if (grid_coords[0] == i) {                MPI_Send(a[j], local_cols, dtype, 0, 0, grid_comm);            }        }    }    if (!grid_id) {        free(buffer);        putchar('\n');    }    return;}/* * Process 0 prints a vector that is block distributed   * among the processes in a communicator. */void print_block_vector(    void *v,            /* IN - Address of vector */    MPI_Datatype dtype, /* IN - Vector element type */    int n,              /* IN - Vector length */    MPI_Comm comm)      /* IN - Communicator */{    int p;              /* Number of processes */    int id;             /* Process rank */    int datum_size;     /* Size of vector element */    void *tmp;          /* Other process's subvector */    MPI_Status status;  /* Result of receive */    int prompt;         /* Dummy variable */    int i;    MPI_Comm_size(comm, &p);    MPI_Comm_rank(comm, &id);    datum_size = get_size(dtype);    if (!id) {        print_subvector(v, dtype, BLOCK_SIZE(id,p,n));        if (p>1) {            tmp = my_malloc(id,                     BLOCK_SIZE(p-1,p,n)*datum_size);            for (i=1; i<p; ++i) {                MPI_Send(&prompt, 1, MPI_INT, i,                     PROMPT_MSG, comm);                MPI_Recv(tmp, BLOCK_SIZE(i,p,n), dtype, i,                     RESPONSE_MSG, comm, &status);                print_subvector(tmp, dtype,                     BLOCK_SIZE(i,p,n));            }            free(tmp);        }        printf("\n\n");    } else {        MPI_Recv(&prompt, 1, MPI_INT, 0, PROMPT_MSG,             comm, &status);        MPI_Send(v, BLOCK_SIZE(id,p,n), dtype, 0,             RESPONSE_MSG, comm);    }    return;}/* * Process 0 prints a vector that is replicated among  * the processes in a communicator. */void print_replicated_vector(    void *v,            /* IN - Address of vector */    MPI_Datatype dtype, /* IN - Vector element type */    int n,              /* IN - Vector length */    MPI_Comm comm)      /* IN - Communicator */{    int id; /* Process rank */    MPI_Comm_rank(comm, &id);    if (!id) {        print_subvector(v, dtype, n);        printf("\n\n");    }    return;}
1 0
原创粉丝点击