Blame test/mpi/coll/scatterv.c

Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 *  (C) 2001 by Argonne National Laboratory.
Packit Service c5cf8c
 *      See COPYRIGHT in top-level directory.
Packit Service c5cf8c
 */
Packit Service c5cf8c
#include "mpi.h"
Packit Service c5cf8c
#include <stdlib.h>
Packit Service c5cf8c
#include <stdio.h>
Packit Service c5cf8c
#include "mpitest.h"
Packit Service c5cf8c
Packit Service c5cf8c
/* Prototypes for picky compilers */
Packit Service c5cf8c
void SetData(double *, double *, int, int, int, int, int, int);
Packit Service c5cf8c
int CheckData(double *, int, int, int, int, int, int);
Packit Service c5cf8c
/*
Packit Service c5cf8c
   This is an example of using scatterv to send a matrix from one
Packit Service c5cf8c
   process to all others, with the matrix stored in Fortran order.
Packit Service c5cf8c
   Note the use of an explicit UB to enable the sources to overlap.
Packit Service c5cf8c
Packit Service c5cf8c
   This tests scatterv to make sure that it uses the datatype size
Packit Service c5cf8c
   and extent correctly.  It requires number of processors that
Packit Service c5cf8c
   can be split with MPI_Dims_create.
Packit Service c5cf8c
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
void SetData(double *sendbuf, double *recvbuf, int nx, int ny,
Packit Service c5cf8c
             int myrow, int mycol, int nrow, int ncol)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int coldim, i, j, m, k;
Packit Service c5cf8c
    double *p;
Packit Service c5cf8c
Packit Service c5cf8c
    if (myrow == 0 && mycol == 0) {
Packit Service c5cf8c
        coldim = nx * nrow;
Packit Service c5cf8c
        for (j = 0; j < ncol; j++) {
Packit Service c5cf8c
            for (i = 0; i < nrow; i++) {
Packit Service c5cf8c
                p = sendbuf + i * nx + j * (ny * coldim);
Packit Service c5cf8c
                for (m = 0; m < ny; m++) {
Packit Service c5cf8c
                    for (k = 0; k < nx; k++) {
Packit Service c5cf8c
                        p[k] = 1000 * j + 100 * i + m * nx + k;
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                    p += coldim;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    for (i = 0; i < nx * ny; i++)
Packit Service c5cf8c
        recvbuf[i] = -1.0;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int CheckData(double *recvbuf, int nx, int ny, int myrow, int mycol, int nrow, int expect_no_value)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int coldim, m, k;
Packit Service c5cf8c
    double *p, val;
Packit Service c5cf8c
    int errs = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    coldim = nx;
Packit Service c5cf8c
    p = recvbuf;
Packit Service c5cf8c
    for (m = 0; m < ny; m++) {
Packit Service c5cf8c
        for (k = 0; k < nx; k++) {
Packit Service c5cf8c
            /* If expect_no_value is true then we assume that the pre-scatterv
Packit Service c5cf8c
             * value should remain in the recvbuf for our portion of the array.
Packit Service c5cf8c
             * This is the case for the root process when using MPI_IN_PLACE. */
Packit Service c5cf8c
            if (expect_no_value)
Packit Service c5cf8c
                val = -1.0;
Packit Service c5cf8c
            else
Packit Service c5cf8c
                val = 1000 * mycol + 100 * myrow + m * nx + k;
Packit Service c5cf8c
Packit Service c5cf8c
            if (p[k] != val) {
Packit Service c5cf8c
                errs++;
Packit Service c5cf8c
                if (errs < 10) {
Packit Service c5cf8c
                    printf("Error in (%d,%d) [%d,%d] location, got %f expected %f\n",
Packit Service c5cf8c
                           m, k, myrow, mycol, p[k], val);
Packit Service c5cf8c
                } else if (errs == 10) {
Packit Service c5cf8c
                    printf("Too many errors; suppressing printing\n");
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
        p += coldim;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    return errs;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int main(int argc, char **argv)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int rank, size, myrow, mycol, nx, ny, stride, cnt, i, j, errs, errs_in_place;
Packit Service c5cf8c
    double *sendbuf, *recvbuf;
Packit Service c5cf8c
    MPI_Datatype vec, block, types[2];
Packit Service c5cf8c
    MPI_Aint displs[2];
Packit Service c5cf8c
    int *scdispls;
Packit Service c5cf8c
    int blens[2];
Packit Service c5cf8c
    MPI_Comm comm2d;
Packit Service c5cf8c
    int dims[2], periods[2], coords[2], lcoords[2];
Packit Service c5cf8c
    int *sendcounts;
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
    MTest_Init(&argc, &argv);
Packit Service c5cf8c
    MPI_Comm_rank(MPI_COMM_WORLD, &rank;;
Packit Service c5cf8c
    MPI_Comm_size(MPI_COMM_WORLD, &size);
Packit Service c5cf8c
Packit Service c5cf8c
    /* Get a 2-d decomposition of the processes */
Packit Service c5cf8c
    dims[0] = 0;
Packit Service c5cf8c
    dims[1] = 0;
Packit Service c5cf8c
    MPI_Dims_create(size, 2, dims);
Packit Service c5cf8c
    periods[0] = 0;
Packit Service c5cf8c
    periods[1] = 0;
Packit Service c5cf8c
    MPI_Cart_create(MPI_COMM_WORLD, 2, dims, periods, 0, &comm2d);
Packit Service c5cf8c
    MPI_Cart_get(comm2d, 2, dims, periods, coords);
Packit Service c5cf8c
    myrow = coords[0];
Packit Service c5cf8c
    mycol = coords[1];
Packit Service c5cf8c
/*
Packit Service c5cf8c
    if (rank == 0)
Packit Service c5cf8c
        printf("Decomposition is [%d x %d]\n", dims[0], dims[1]);
Packit Service c5cf8c
*/
Packit Service c5cf8c
Packit Service c5cf8c
    /* Get the size of the matrix */
Packit Service c5cf8c
    nx = 10;
Packit Service c5cf8c
    ny = 8;
Packit Service c5cf8c
    stride = nx * dims[0];
Packit Service c5cf8c
Packit Service c5cf8c
    recvbuf = (double *) malloc(nx * ny * sizeof(double));
Packit Service c5cf8c
    if (!recvbuf) {
Packit Service c5cf8c
        MPI_Abort(MPI_COMM_WORLD, 1);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    sendbuf = 0;
Packit Service c5cf8c
    if (myrow == 0 && mycol == 0) {
Packit Service c5cf8c
        sendbuf = (double *) malloc(nx * ny * size * sizeof(double));
Packit Service c5cf8c
        if (!sendbuf) {
Packit Service c5cf8c
            MPI_Abort(MPI_COMM_WORLD, 1);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    sendcounts = (int *) malloc(size * sizeof(int));
Packit Service c5cf8c
    scdispls = (int *) malloc(size * sizeof(int));
Packit Service c5cf8c
Packit Service c5cf8c
    MPI_Type_vector(ny, nx, stride, MPI_DOUBLE, &vec;;
Packit Service c5cf8c
    blens[0] = 1;
Packit Service c5cf8c
    blens[1] = 1;
Packit Service c5cf8c
    types[0] = vec;
Packit Service c5cf8c
    types[1] = MPI_UB;
Packit Service c5cf8c
    displs[0] = 0;
Packit Service c5cf8c
    displs[1] = nx * sizeof(double);
Packit Service c5cf8c
Packit Service c5cf8c
    MPI_Type_struct(2, blens, displs, types, &block);
Packit Service c5cf8c
    MPI_Type_free(&vec;;
Packit Service c5cf8c
    MPI_Type_commit(&block);
Packit Service c5cf8c
Packit Service c5cf8c
    /* Set up the transfer */
Packit Service c5cf8c
    cnt = 0;
Packit Service c5cf8c
    for (i = 0; i < dims[1]; i++) {
Packit Service c5cf8c
        for (j = 0; j < dims[0]; j++) {
Packit Service c5cf8c
            sendcounts[cnt] = 1;
Packit Service c5cf8c
            /* Using Cart_coords makes sure that ranks (used by
Packit Service c5cf8c
             * sendrecv) matches the cartesian coordinates (used to
Packit Service c5cf8c
             * set data in the matrix) */
Packit Service c5cf8c
            MPI_Cart_coords(comm2d, cnt, 2, lcoords);
Packit Service c5cf8c
            scdispls[cnt++] = lcoords[0] + lcoords[1] * (dims[0] * ny);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    SetData(sendbuf, recvbuf, nx, ny, myrow, mycol, dims[0], dims[1]);
Packit Service c5cf8c
    MPI_Scatterv(sendbuf, sendcounts, scdispls, block, recvbuf, nx * ny, MPI_DOUBLE, 0, comm2d);
Packit Service c5cf8c
    if ((errs = CheckData(recvbuf, nx, ny, myrow, mycol, dims[0], 0))) {
Packit Service c5cf8c
        fprintf(stdout, "Failed to transfer data\n");
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* once more, but this time passing MPI_IN_PLACE for the root */
Packit Service c5cf8c
    SetData(sendbuf, recvbuf, nx, ny, myrow, mycol, dims[0], dims[1]);
Packit Service c5cf8c
    MPI_Scatterv(sendbuf, sendcounts, scdispls, block,
Packit Service c5cf8c
                 (rank == 0 ? MPI_IN_PLACE : recvbuf), nx * ny, MPI_DOUBLE, 0, comm2d);
Packit Service c5cf8c
    errs_in_place = CheckData(recvbuf, nx, ny, myrow, mycol, dims[0], (rank == 0));
Packit Service c5cf8c
    if (errs_in_place) {
Packit Service c5cf8c
        fprintf(stdout, "Failed to transfer data (MPI_IN_PLACE)\n");
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    errs += errs_in_place;
Packit Service c5cf8c
Packit Service c5cf8c
    if (sendbuf)
Packit Service c5cf8c
        free(sendbuf);
Packit Service c5cf8c
    free(recvbuf);
Packit Service c5cf8c
    free(sendcounts);
Packit Service c5cf8c
    free(scdispls);
Packit Service c5cf8c
    MPI_Type_free(&block);
Packit Service c5cf8c
    MPI_Comm_free(&comm2d);
Packit Service c5cf8c
    MTest_Finalize(errs);
Packit Service c5cf8c
    return MTestReturnValue(errs);
Packit Service c5cf8c
}