#include <stdio.h> #include <stdlib.h> #include "mpi.h" #define NUMBER_OF_TESTS 10 /* This version of pingpong sends and receives from the processes p, p + n/2 If n is odd, leave out the "last" process */ int main( argc, argv ) int argc; char **argv; { double *buf; int rank, size; int n; double t1, t2, tmin = 0.0, tmin_local; int i, j, k, nloop; MPI_Status status; int source, dest; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size ); /* If odd, reduce number of processes */ if ((size & 0x1) != 0) { size--; } if (size < 2) { if (rank == 0) printf( "Must use at least 2 processes\n" ); MPI_Abort( MPI_COMM_WORLD, 1 ); } /* The rate printed by this program is the rate in the presense of contention */ if (rank == 0) printf( "Kind (np=%d)\tn\ttime (sec)\tRate (MB/sec)\n", size ); source = rank; dest = (rank + (size/2)) % size; for (n=1; n<1100000; n*=2) { if (n == 0) nloop = 1000; else nloop = 1000/n; if (nloop < 1) nloop = 1; buf = (double *) malloc( n * sizeof(double) ); if (!buf) { fprintf( stderr, "Could not allocate send/recv buffer of size %d\n", n ); MPI_Abort( MPI_COMM_WORLD, 1 ); } tmin = 1000; for (k=0; k<NUMBER_OF_TESTS; k++) { /* The barrier helps each link to start at about the same time */ MPI_Barrier( MPI_COMM_WORLD ); if (source < size/2) { /* Make sure both processes are ready */ MPI_Sendrecv( MPI_BOTTOM, 0, MPI_INT, dest, 14, MPI_BOTTOM, 0, MPI_INT, dest, 14, MPI_COMM_WORLD, &status ); t1 = MPI_Wtime(); for (j=0; j<nloop; j++) { MPI_Send( buf, n, MPI_DOUBLE, dest, k, MPI_COMM_WORLD ); MPI_Recv( buf, n, MPI_DOUBLE, dest, k, MPI_COMM_WORLD, &status ); } t2 = (MPI_Wtime() - t1) / nloop; if (t2 < tmin) tmin = t2; } else if (source < size) { /* If original size is odd, source == size on last process */ tmin = 0.0; /* Make sure both processes are ready */ MPI_Sendrecv( MPI_BOTTOM, 0, MPI_INT, dest, 14, MPI_BOTTOM, 0, MPI_INT, dest, 14, MPI_COMM_WORLD, &status ); for (j=0; j<nloop; j++) { MPI_Recv( buf, n, MPI_DOUBLE, dest, k, MPI_COMM_WORLD, &status ); MPI_Send( buf, n, MPI_DOUBLE, dest, k, MPI_COMM_WORLD ); } } } /* Convert to half the round-trip time */ tmin = tmin / 2.0; tmin_local = tmin; /* Get the WORST case for output (could use MPI_MAXLOC to get location as well) */ MPI_Reduce( &tmin_local, &tmin, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD ); if (rank == 0) { double rate; if (tmin > 0) rate = n * sizeof(double) * 1.0e-6 /tmin; else rate = 0.0; printf( "Send/Recv\t%d\t%f\t%f\n", n, tmin, rate ); } free( buf ); } MPI_Finalize( ); return 0; }