|
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 |
}
|