/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ /* * (C) 2010 by Argonne National Laboratory. * See COPYRIGHT in top-level directory. */ #include "mpi.h" #include "stdio.h" #include "stdlib.h" #include "mpitest.h" /* * Tests for lock contention, including special cases within the MPICH code * (any MPI implementation should pass these tests; in the MPICH case, our * coverage analysis showed that the lockcontention.c test was not covering * all cases, and in fact, this test revealed a bug in the code). * * In all of these tests, each process writes (or accesses) the values * rank + i*size_of_world for NELM times. * * This test strives to avoid operations not strictly permitted by MPI RMA, * for example, it doesn't target the same locations with multiple put/get * calls in the same access epoch. */ #define NELM 200 #define NBLOCK 10 #define MAX_ERRS_REPORT 10 /* * Each process writes data into the rmabuf on the process with target rank * trank. The final result in rmabuf are the consecutive integers starting * from 0. Each process, however, does not write a consecutive block. * Instead, they write these locations: * * for i=0,...,NELM-1 * for j=0,...,NBLOCK-1 * j + NBLOCK * (rank + i * wsize) * * The value written is the location. * * In many cases, multiple RMA operations are needed. Where these must not * overlap, the above pattern is replicated at NBLOCK*NELM*wsize. * (NBLOCK is either 1 or NBLOCK in the code below, depending on use) */ static int toterrs = 0; int testValues(int, int, int, int *, const char *); int main(int argc, char *argv[]) { int rank, wsize, i, j, cnt; int *rmabuf, *localbuf, *localbuf2, *vals; MPI_Win win; int trank = 0; int windowsize; MTest_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &wsize); MPI_Comm_rank(MPI_COMM_WORLD, &rank); if (wsize < 2) { fprintf(stderr, "Run this program with at least 2 processes\n"); MPI_Abort(MPI_COMM_WORLD, 1); } windowsize = (2 * NBLOCK + 2) * NELM * wsize; rmabuf = (int *) malloc(windowsize * sizeof(int)); localbuf = (int *) malloc(NELM * sizeof(int)); localbuf2 = (int *) malloc(NELM * NBLOCK * sizeof(int)); vals = (int *) malloc(NELM * sizeof(int)); /* * Initialize the buffers */ for (i = 0; i < NELM; i++) { localbuf[i] = rank + i * wsize; } cnt = 0; for (i = 0; i < NELM; i++) { for (j = 0; j < NBLOCK; j++) { localbuf2[cnt++] = j + NBLOCK * (rank + i * wsize); } } for (i = 0; i < windowsize; i++) { rmabuf[i] = -1; } /* Create the window */ MPI_Win_create(rmabuf, windowsize * sizeof(int), sizeof(int), MPI_INFO_NULL, MPI_COMM_WORLD, &win); /* Multiple puts, with contention at trank */ MPI_Barrier(MPI_COMM_WORLD); for (i = 0; i < NELM; i++) { MPI_Win_lock(MPI_LOCK_EXCLUSIVE, trank, 0, win); MPI_Put(&localbuf[i], 1, MPI_INT, trank, rank + i * wsize, 1, MPI_INT, win); MPI_Put(&localbuf[i], 1, MPI_INT, trank, rank + (i + NELM) * wsize, 1, MPI_INT, win); MPI_Win_unlock(trank, win); } MPI_Barrier(MPI_COMM_WORLD); if (rank == trank) { MPI_Win_lock(MPI_LOCK_EXCLUSIVE, trank, 0, win); toterrs += testValues(1, NELM, wsize, rmabuf, "Multiple puts (1)"); toterrs += testValues(1, NELM, wsize, rmabuf + wsize * NELM, "Multiple puts (2)"); MPI_Win_unlock(trank, win); } MPI_Barrier(MPI_COMM_WORLD); /* Reinit the rmabuf */ for (i = 0; i < windowsize; i++) { rmabuf[i] = -1; } MPI_Barrier(MPI_COMM_WORLD); /* Single put with contention */ trank = 0; for (i = 0; i < NELM; i++) { MPI_Win_lock(MPI_LOCK_EXCLUSIVE, trank, 0, win); MPI_Put(&localbuf[i], 1, MPI_INT, trank, rank + i * wsize, 1, MPI_INT, win); MPI_Win_unlock(trank, win); } MPI_Barrier(MPI_COMM_WORLD); if (rank == trank) { MPI_Win_lock(MPI_LOCK_EXCLUSIVE, trank, 0, win); toterrs += testValues(1, NELM, wsize, rmabuf, "Single put"); MPI_Win_unlock(trank, win); } /* Reinit the rmabuf */ for (i = 0; i < windowsize; i++) { rmabuf[i] = -1; } /* Longer puts with contention at trank */ MPI_Barrier(MPI_COMM_WORLD); for (i = 0; i < NELM; i++) { MPI_Win_lock(MPI_LOCK_EXCLUSIVE, trank, 0, win); if (rank != trank) { MPI_Put(&localbuf2[i * NBLOCK], NBLOCK, MPI_INT, trank, NELM * wsize + NBLOCK * (rank + i * wsize), NBLOCK, MPI_INT, win); MPI_Put(&localbuf2[i * NBLOCK], NBLOCK, MPI_INT, trank, NELM * wsize + NBLOCK * (rank + (i + NELM) * wsize), NBLOCK, MPI_INT, win); } MPI_Put(&localbuf[i], 1, MPI_INT, trank, rank + i * wsize, 1, MPI_INT, win); MPI_Win_unlock(trank, win); } MPI_Barrier(MPI_COMM_WORLD); if (rank == trank) { /* For simplicity in testing, set the values that rank==trank * would have set. */ for (i = 0; i < NELM; i++) { for (j = 0; j < NBLOCK; j++) { rmabuf[NELM * wsize + NBLOCK * (trank + i * wsize) + j] = j + NBLOCK * (trank + i * wsize); rmabuf[NELM * wsize + NBLOCK * (trank + (i + NELM) * wsize) + j] = j + NBLOCK * (trank + i * wsize); } } MPI_Win_lock(MPI_LOCK_EXCLUSIVE, trank, 0, win); toterrs += testValues(1, NELM, wsize, rmabuf, "Long puts (1)"); toterrs += testValues(NBLOCK, NELM, wsize, rmabuf + NELM * wsize, "Long puts(2)"); toterrs += testValues(NBLOCK, NELM, wsize, rmabuf + NELM * wsize * (1 + NBLOCK), "Long puts(3)"); MPI_Win_unlock(trank, win); } /* Reinit the rmabuf */ for (i = 0; i < windowsize; i++) { rmabuf[i] = -1; } for (i = 0; i < NELM; i++) vals[i] = -2; /* Put mixed with Get */ MPI_Barrier(MPI_COMM_WORLD); for (i = 0; i < NELM; i++) { MPI_Win_lock(MPI_LOCK_EXCLUSIVE, trank, 0, win); if (rank != trank) { MPI_Put(&localbuf2[i], NBLOCK, MPI_INT, trank, NELM * wsize + NBLOCK * (rank + i * wsize), NBLOCK, MPI_INT, win); MPI_Put(&localbuf[i], 1, MPI_INT, trank, rank + i * wsize, 1, MPI_INT, win); } else { MPI_Get(&vals[i], 1, MPI_INT, trank, i, 1, MPI_INT, win); } MPI_Win_unlock(trank, win); } MPI_Barrier(MPI_COMM_WORLD); if (rank == trank) { /* Just test the Get */ for (i = 0; i < wsize; i++) { if (i == trank) { if (vals[i] != -1) { toterrs++; if (toterrs < MAX_ERRS_REPORT) { printf("put/get: vals[%d] = %d, expected -1\n", i, vals[i]); } } } else if (vals[i] != i && vals[i] != -1) { toterrs++; if (toterrs < MAX_ERRS_REPORT) { printf("put/get: vals[%d] = %d, expected -1 or %d\n", i, vals[i], i); } } } } /* Contention only with get */ for (i = 0; i < windowsize; i++) { rmabuf[i] = -i; } for (i = 0; i < NELM; i++) vals[i] = -2; MPI_Barrier(MPI_COMM_WORLD); for (i = 0; i < NELM; i++) { MPI_Win_lock(MPI_LOCK_EXCLUSIVE, trank, 0, win); MPI_Get(&vals[i], 1, MPI_INT, trank, i, 1, MPI_INT, win); MPI_Win_unlock(trank, win); } MPI_Barrier(MPI_COMM_WORLD); if (rank == trank) { for (i = 0; i < NELM; i++) { if (vals[i] != -i) { toterrs++; if (toterrs < MAX_ERRS_REPORT) { printf("single get: vals[%d] = %d, expected %d\n", i, vals[i], -i); } } } } /* Contention with accumulate */ MPI_Barrier(MPI_COMM_WORLD); for (i = 0; i < NELM * wsize; i++) { rmabuf[i] = 0; } MPI_Barrier(MPI_COMM_WORLD); for (i = 0; i < NELM; i++) { MPI_Win_lock(MPI_LOCK_EXCLUSIVE, trank, 0, win); MPI_Accumulate(&localbuf[i], 1, MPI_INT, trank, rank + i * wsize, 1, MPI_INT, MPI_SUM, win); MPI_Accumulate(&localbuf[i], 1, MPI_INT, trank, rank + i * wsize, 1, MPI_INT, MPI_SUM, win); MPI_Win_unlock(trank, win); } MPI_Barrier(MPI_COMM_WORLD); if (rank == trank) { MPI_Win_lock(MPI_LOCK_EXCLUSIVE, trank, 0, win); for (i = 0; i < NELM * wsize; i++) { if (rmabuf[i] != 2 * i) { toterrs++; if (toterrs < MAX_ERRS_REPORT) { printf("2 accumulate: rmabuf[%d] = %d, expected %d\n", i, rmabuf[i], 2 * i); } } } MPI_Win_unlock(trank, win); } MPI_Win_free(&win); free(rmabuf); free(localbuf); free(localbuf2); free(vals); MTest_Finalize(toterrs); MPI_Finalize(); return 0; } /* Test the values in the rmabuf against the expected values. Return the number of errors */ int testValues(int nb, int nelm, int wsize, int *rmabuf, const char *msg) { int i, errs = 0; for (i = 0; i < nb * nelm * wsize; i++) { if (rmabuf[i] != i) { if (toterrs + errs < MAX_ERRS_REPORT) { printf("%s:rmabuf[%d] = %d expected %d\n", msg, i, rmabuf[i], i); } errs++; } } return errs; }