Blame test/mpi/coll/allred4.c

Packit 0848f5
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit 0848f5
/*
Packit 0848f5
 *  (C) 2004 by Argonne National Laboratory.
Packit 0848f5
 *      See COPYRIGHT in top-level directory.
Packit 0848f5
 */
Packit 0848f5
#include "mpi.h"
Packit 0848f5
#include <stdio.h>
Packit 0848f5
#include <stdlib.h>
Packit 0848f5
#include "mpitest.h"
Packit 0848f5
#include <assert.h>
Packit 0848f5
Packit 0848f5
/*
Packit 0848f5
static char MTEST_Descrip[] = "Test MPI_Allreduce with non-commutative user-defined operations using matrix rotations";
Packit 0848f5
*/
Packit 0848f5
Packit 0848f5
/* This example is similar to allred3.c, but uses only 3x3 matrics with
Packit 0848f5
   integer-valued entries.  This is an associative but not commutative
Packit 0848f5
   operation.
Packit 0848f5
   The number of matrices is the count argument. The matrix is stored
Packit 0848f5
   in C order, so that
Packit 0848f5
     c(i,j) is cin[j+i*3]
Packit 0848f5
Packit 0848f5
   Three different matrices are used:
Packit 0848f5
   I = identity matrix
Packit 0848f5
   A = (1 0 0    B = (0 1 0
Packit 0848f5
        0 0 1         1 0 0
Packit 0848f5
        0 1 0)        0 0 1)
Packit 0848f5
Packit 0848f5
   The product
Packit 0848f5
Packit 0848f5
         I^k A I^(p-2-k-j) B I^j
Packit 0848f5
Packit 0848f5
   is
Packit 0848f5
Packit 0848f5
   (0 1 0
Packit 0848f5
     0 0 1
Packit 0848f5
     1 0 0)
Packit 0848f5
Packit 0848f5
   for all values of k, p, and j.
Packit 0848f5
 */
Packit 0848f5
Packit 0848f5
void matmult(void *cinPtr, void *coutPtr, int *count, MPI_Datatype * dtype);
Packit 0848f5
Packit 0848f5
void matmult(void *cinPtr, void *coutPtr, int *count, MPI_Datatype * dtype)
Packit 0848f5
{
Packit 0848f5
    const int *cin = (const int *) cinPtr;
Packit 0848f5
    int *cout = (int *) coutPtr;
Packit 0848f5
    int i, j, k, nmat;
Packit 0848f5
    int tempcol[3];
Packit 0848f5
    int offset1, offset2;
Packit 0848f5
Packit 0848f5
    for (nmat = 0; nmat < *count; nmat++) {
Packit 0848f5
        for (j = 0; j < 3; j++) {
Packit 0848f5
            for (i = 0; i < 3; i++) {
Packit 0848f5
                tempcol[i] = 0;
Packit 0848f5
                for (k = 0; k < 3; k++) {
Packit 0848f5
                    /* col[i] += cin(i,k) * cout(k,j) */
Packit 0848f5
                    offset1 = k + i * 3;
Packit 0848f5
                    offset2 = j + k * 3;
Packit 0848f5
                    tempcol[i] += cin[offset1] * cout[offset2];
Packit 0848f5
                }
Packit 0848f5
            }
Packit 0848f5
            for (i = 0; i < 3; i++) {
Packit 0848f5
                offset1 = j + i * 3;
Packit 0848f5
                cout[offset1] = tempcol[i];
Packit 0848f5
            }
Packit 0848f5
        }
Packit 0848f5
        /* Advance to the next matrix */
Packit 0848f5
        cin += 9;
Packit 0848f5
        cout += 9;
Packit 0848f5
    }
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* Initialize the integer matrix as one of the
Packit 0848f5
   above matrix entries, as a function of count.
Packit 0848f5
   We guarantee that both the A and B matrices are included.
Packit 0848f5
*/
Packit 0848f5
static void initMat(int rank, int size, int nmat, int mat[])
Packit 0848f5
{
Packit 0848f5
    int i, kind;
Packit 0848f5
Packit 0848f5
    /* Zero the matrix */
Packit 0848f5
    for (i = 0; i < 9; i++) {
Packit 0848f5
        mat[i] = 0;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    /* Decide which matrix to create (I, A, or B) */
Packit 0848f5
    if (size == 2) {
Packit 0848f5
        /* rank 0 is A, 1 is B */
Packit 0848f5
        kind = 1 + rank;
Packit 0848f5
    }
Packit 0848f5
    else {
Packit 0848f5
        int tmpA, tmpB;
Packit 0848f5
        /* Most ranks are identity matrices */
Packit 0848f5
        kind = 0;
Packit 0848f5
        /* Make sure exactly one rank gets the A matrix
Packit 0848f5
         * and one the B matrix */
Packit 0848f5
        tmpA = size / 4;
Packit 0848f5
        tmpB = (3 * size) / 4;
Packit 0848f5
Packit 0848f5
        if (rank == tmpA)
Packit 0848f5
            kind = 1;
Packit 0848f5
        if (rank == tmpB)
Packit 0848f5
            kind = 2;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    switch (kind) {
Packit 0848f5
    case 0:    /* Identity */
Packit 0848f5
        mat[0] = 1;
Packit 0848f5
        mat[4] = 1;
Packit 0848f5
        mat[8] = 1;
Packit 0848f5
        break;
Packit 0848f5
    case 1:    /* A */
Packit 0848f5
        mat[0] = 1;
Packit 0848f5
        mat[5] = 1;
Packit 0848f5
        mat[7] = 1;
Packit 0848f5
        break;
Packit 0848f5
    case 2:    /* B */
Packit 0848f5
        mat[1] = 1;
Packit 0848f5
        mat[3] = 1;
Packit 0848f5
        mat[8] = 1;
Packit 0848f5
        break;
Packit 0848f5
    }
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* Compare a matrix with the known result */
Packit 0848f5
static int checkResult(int nmat, int mat[], const char *msg)
Packit 0848f5
{
Packit 0848f5
    int n, k, errs = 0, wrank;
Packit 0848f5
    static int solution[9] = { 0, 1, 0,
Packit 0848f5
        0, 0, 1,
Packit 0848f5
        1, 0, 0
Packit 0848f5
    };
Packit 0848f5
Packit 0848f5
    MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
Packit 0848f5
Packit 0848f5
    for (n = 0; n < nmat; n++) {
Packit 0848f5
        for (k = 0; k < 9; k++) {
Packit 0848f5
            if (mat[k] != solution[k]) {
Packit 0848f5
                errs++;
Packit 0848f5
                if (errs == 1) {
Packit 0848f5
                    printf("Errors for communicators %s\n", MTestGetIntracommName());
Packit 0848f5
                    fflush(stdout);
Packit 0848f5
Packit 0848f5
                }
Packit 0848f5
                if (errs < 10) {
Packit 0848f5
                    printf("[%d]matrix #%d(%s): Expected mat[%d,%d] = %d, got %d\n",
Packit 0848f5
                           wrank, n, msg, k / 3, k % 3, solution[k], mat[k]);
Packit 0848f5
                    fflush(stdout);
Packit 0848f5
                }
Packit 0848f5
            }
Packit 0848f5
        }
Packit 0848f5
        /* Advance to the next matrix */
Packit 0848f5
        mat += 9;
Packit 0848f5
    }
Packit 0848f5
    return errs;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
int main(int argc, char *argv[])
Packit 0848f5
{
Packit 0848f5
    int errs = 0;
Packit 0848f5
    int size, rank;
Packit 0848f5
    int minsize = 2, count;
Packit 0848f5
    MPI_Comm comm;
Packit 0848f5
    int *buf, *bufout;
Packit 0848f5
    MPI_Op op;
Packit 0848f5
    MPI_Datatype mattype;
Packit 0848f5
    int i;
Packit 0848f5
Packit 0848f5
    MTest_Init(&argc, &argv);
Packit 0848f5
Packit 0848f5
    MPI_Op_create(matmult, 0, &op);
Packit 0848f5
Packit 0848f5
    /* A single rotation matrix (3x3, stored as 9 consequetive elements) */
Packit 0848f5
    MPI_Type_contiguous(9, MPI_INT, &mattype);
Packit 0848f5
    MPI_Type_commit(&mattype);
Packit 0848f5
Packit 0848f5
    /* Sanity check: test that our routines work properly */
Packit 0848f5
    {
Packit 0848f5
        int one = 1;
Packit 0848f5
        buf = (int *) malloc(4 * 9 * sizeof(int));
Packit 0848f5
        initMat(0, 4, 0, &buf[0]);
Packit 0848f5
        initMat(1, 4, 0, &buf[9]);
Packit 0848f5
        initMat(2, 4, 0, &buf[18]);
Packit 0848f5
        initMat(3, 4, 0, &buf[27]);
Packit 0848f5
        matmult(&buf[0], &buf[9], &one, &mattype);
Packit 0848f5
        matmult(&buf[9], &buf[18], &one, &mattype);
Packit 0848f5
        matmult(&buf[18], &buf[27], &one, &mattype);
Packit 0848f5
        checkResult(1, &buf[27], "Sanity Check");
Packit 0848f5
        free(buf);
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    while (MTestGetIntracommGeneral(&comm, minsize, 1)) {
Packit 0848f5
        if (comm == MPI_COMM_NULL)
Packit 0848f5
            continue;
Packit 0848f5
Packit 0848f5
        MPI_Comm_size(comm, &size);
Packit 0848f5
        MPI_Comm_rank(comm, &rank;;
Packit 0848f5
Packit 0848f5
        for (count = 1; count < size; count++) {
Packit 0848f5
Packit 0848f5
            /* Allocate the matrices */
Packit 0848f5
            buf = (int *) malloc(count * 9 * sizeof(int));
Packit 0848f5
            if (!buf) {
Packit 0848f5
                MPI_Abort(MPI_COMM_WORLD, 1);
Packit 0848f5
            }
Packit 0848f5
Packit 0848f5
            bufout = (int *) malloc(count * 9 * sizeof(int));
Packit 0848f5
            if (!bufout) {
Packit 0848f5
                MPI_Abort(MPI_COMM_WORLD, 1);
Packit 0848f5
            }
Packit 0848f5
Packit 0848f5
            for (i = 0; i < count; i++) {
Packit 0848f5
                initMat(rank, size, i, &buf[i * 9]);
Packit 0848f5
            }
Packit 0848f5
Packit 0848f5
            MPI_Allreduce(buf, bufout, count, mattype, op, comm);
Packit 0848f5
            errs += checkResult(count, bufout, "");
Packit 0848f5
Packit 0848f5
            /* Try the same test, but using MPI_IN_PLACE */
Packit 0848f5
            for (i = 0; i < count; i++) {
Packit 0848f5
                initMat(rank, size, i, &bufout[i * 9]);
Packit 0848f5
            }
Packit 0848f5
            MPI_Allreduce(MPI_IN_PLACE, bufout, count, mattype, op, comm);
Packit 0848f5
            errs += checkResult(count, bufout, "IN_PLACE");
Packit 0848f5
Packit 0848f5
            free(buf);
Packit 0848f5
            free(bufout);
Packit 0848f5
        }
Packit 0848f5
        MTestFreeComm(&comm);
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    MPI_Op_free(&op);
Packit 0848f5
    MPI_Type_free(&mattype);
Packit 0848f5
Packit 0848f5
    MTest_Finalize(errs);
Packit 0848f5
    MPI_Finalize();
Packit 0848f5
    return 0;
Packit 0848f5
}