Blame MpiApps/apps/mpicheck/mpicheck.c

Packit 857059
/* BEGIN_ICS_COPYRIGHT7 ****************************************
Packit 857059
Packit 857059
Copyright (c) 2015, Intel Corporation
Packit 857059
Packit 857059
Redistribution and use in source and binary forms, with or without
Packit 857059
modification, are permitted provided that the following conditions are met:
Packit 857059
Packit 857059
    * Redistributions of source code must retain the above copyright notice,
Packit 857059
      this list of conditions and the following disclaimer.
Packit 857059
    * Redistributions in binary form must reproduce the above copyright
Packit 857059
      notice, this list of conditions and the following disclaimer in the
Packit 857059
      documentation and/or other materials provided with the distribution.
Packit 857059
    * Neither the name of Intel Corporation nor the names of its contributors
Packit 857059
      may be used to endorse or promote products derived from this software
Packit 857059
      without specific prior written permission.
Packit 857059
Packit 857059
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit 857059
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit 857059
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Packit 857059
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
Packit 857059
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 857059
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
Packit 857059
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
Packit 857059
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
Packit 857059
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 857059
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 857059
Packit 857059
** END_ICS_COPYRIGHT7   ****************************************/
Packit 857059
Packit 857059
/* [ICS VERSION STRING: unknown] */
Packit 857059
/* 
Packit 857059
 * The purpose of this application is to do some simple validations of MPI
Packit 857059
 * communications. Unlike other benchmark apps is is not intended to run
Packit 857059
 * quickly, but to validate the results of each transfer to ensure the
Packit 857059
 * correct operation of MPI.
Packit 857059
 *
Packit 857059
 * The code is deliberately written to be inefficient; in order to (hopefully)
Packit 857059
 * expose communication errors and memory corruption issues.
Packit 857059
 */
Packit 857059
Packit 857059
#include <stdio.h>
Packit 857059
#include <string.h>
Packit 857059
#include <stdlib.h>
Packit 857059
#include <unistd.h>
Packit 857059
#include <getopt.h>
Packit 857059
#include <mpi.h>
Packit 857059
#include <time.h>
Packit 857059
Packit 857059
/* 
Packit 857059
 * Defines used by randomize test.
Packit 857059
 */
Packit 857059
#define SHUFFLERATE 64
Packit 857059
#define MINRANDXFER 1024
Packit 857059
#define MAXRANDXFER 32768
Packit 857059
#define NUMRANDXFERS 65536
Packit 857059
#define RANDOMLEN() (MINRANDXFER + (random() % (MAXRANDXFER-MINRANDXFER)))
Packit 857059
Packit 857059
#define MAX(a,b) ((a>b)?a:b)
Packit 857059
#define MIN(a,b) ((a
Packit 857059
Packit 857059
/* 
Packit 857059
 * Prints the message if nodes rank is 0.
Packit 857059
 */
Packit 857059
#define ROOTPRINT(format,args...) { if (myid == 0) fprintf(stderr,format,##args); }
Packit 857059
Packit 857059
/* 
Packit 857059
 * Prints an error, including node rank and line of code.
Packit 857059
 */
Packit 857059
#define ERRPRINT(format,args...) { fprintf(stderr,"[%d/%d]: ERROR: ",myid,__LINE__); fprintf(stderr,format,##args); }
Packit 857059
Packit 857059
/* 
Packit 857059
 * Prints a message if and only if verbose mode is on. Includes
Packit 857059
 * rank and line of code.
Packit 857059
 */
Packit 857059
#define NODEPRINT(format,args...) if (verboseMode) { fflush(stdout); printf("[%d/%d]: ",myid,__LINE__); printf(format,##args); }
Packit 857059
Packit 857059
/* 
Packit 857059
 * Force a core dump.
Packit 857059
 */
Packit 857059
#define ERRABORT(retCode) if (retCode != MPI_SUCCESS) { fprintf(stderr,"MPI Failure: %d at line %d\n",retCode,__LINE__); abort(); }
Packit 857059
Packit 857059
/* 
Packit 857059
 * Padding used to look for corruption before or after a read
Packit 857059
 */
Packit 857059
#define BARRIERSIZE 4096
Packit 857059
unsigned int minSize = 16384;	/* Default smallest message size */
Packit 857059
unsigned int maxSize = 65536;	/* Default largest message size */
Packit 857059
unsigned int maxIters = 1000;	/* Default # of rounds */
Packit 857059
int useSendOffset = 0;	/* Default - don't do offest sends. */
Packit 857059
unsigned int rawBufferCount = 1;	
Packit 857059
unsigned int barrierSize = 4096;	/* Default - 4k protection areas. */
Packit 857059
Packit 857059
int verboseMode = 0;
Packit 857059
int doFast = 0;
Packit 857059
int doSlow = 1;
Packit 857059
int doRandom = 1;
Packit 857059
Packit 857059
struct option options[] = {
Packit 857059
	{"min", required_argument, NULL, '<'},
Packit 857059
	{"max", required_argument, NULL, '>'},
Packit 857059
	{"rounds", required_argument, NULL, 'i'},
Packit 857059
	{"buffers", required_argument, NULL, 'b'},
Packit 857059
	{"barrier", required_argument, NULL, 'B'},
Packit 857059
	{"verbose", no_argument, &verboseMode, 1},
Packit 857059
	{"fast", no_argument, &doFast, 1},
Packit 857059
	{"nofast", no_argument, &doFast, 0},
Packit 857059
	{"slow", no_argument, &doSlow, 1},
Packit 857059
	{"noslow", no_argument, &doSlow, 0},
Packit 857059
	{"random", no_argument, &doRandom, 1},
Packit 857059
	{"norandom", no_argument, &doRandom, 0},
Packit 857059
	{"sendoffset", no_argument, &useSendOffset, 1},
Packit 857059
	{NULL, 0, NULL, 0}
Packit 857059
};
Packit 857059
Packit 857059
void
Packit 857059
usage(  )
Packit 857059
{
Packit 857059
	int i = 0;
Packit 857059
Packit 857059
	fprintf( stderr, "Usage: mpicheck " );
Packit 857059
	for ( i = 0; options[i].name != NULL; i++ ) {
Packit 857059
		if ( options[i].has_arg == required_argument ) {
Packit 857059
			fprintf( stderr, "[--%s ###] ", options[i].name );
Packit 857059
		} else {
Packit 857059
			fprintf( stderr, "[--%s] ", options[i].name );
Packit 857059
		}
Packit 857059
	}
Packit 857059
	fprintf( stderr, "\n" );
Packit 857059
}
Packit 857059
Packit 857059
/* 
Packit 857059
 * Writes a transfer buffer to disk for post-mortem analysis.
Packit 857059
 */
Packit 857059
void
Packit 857059
dumpbuffer( int myid, char *name, char *buffer, int size )
Packit 857059
{
Packit 857059
	char fname[1024];
Packit 857059
	FILE *f;
Packit 857059
	size_t s;
Packit 857059
Packit 857059
	sprintf( fname, "%s.%03d", name, myid );
Packit 857059
Packit 857059
	f = fopen( fname, "w" );
Packit 857059
Packit 857059
	if ( !f ) {
Packit 857059
		ERRPRINT( "Failed to open %s\n", fname );
Packit 857059
		return;
Packit 857059
	}
Packit 857059
Packit 857059
	s = fwrite( buffer, 1, size, f );
Packit 857059
	if ( s != size ) {
Packit 857059
		ERRPRINT( "Failed to write %s\n", fname );
Packit 857059
	}
Packit 857059
Packit 857059
	fclose( f );
Packit 857059
}
Packit 857059
Packit 857059
typedef struct {
Packit 857059
	unsigned int start;
Packit 857059
	unsigned int length;
Packit 857059
} RandomRecord;
Packit 857059
Packit 857059
static void
Packit 857059
initrandom(  )
Packit 857059
{
Packit 857059
	unsigned int seed;
Packit 857059
	FILE *f = fopen( "/dev/random", "r" );
Packit 857059
Packit 857059
	if ( f ) {
Packit 857059
		fread( &seed, sizeof( seed ), 1, f );
Packit 857059
	}
Packit 857059
	fclose( f );
Packit 857059
	srandom( seed );
Packit 857059
}
Packit 857059
Packit 857059
/* 
Packit 857059
 * Randomize mode pairs up the nodes and performs a "drunkards" walk
Packit 857059
 * between them - it performs a large number of sends and receives
Packit 857059
 * designed to stress operations when asynchronous messages overlap.
Packit 857059
 *
Packit 857059
 * Note that randomize does not use the "rounds" setting that the
Packit 857059
 * other tests use.
Packit 857059
 */
Packit 857059
int
Packit 857059
randomize( int myid, int numProcs, int minSize, int maxSize, int maxIters )
Packit 857059
{
Packit 857059
	int i, size, partner, sendMode, numRecords, iters;
Packit 857059
	int retCode = MPI_SUCCESS;
Packit 857059
	RandomRecord records[NUMRANDXFERS];
Packit 857059
	MPI_Request request[NUMRANDXFERS];
Packit 857059
	MPI_Status status[NUMRANDXFERS];
Packit 857059
	unsigned char *rawBuffer = NULL;	/* Array of buffer+barrier memory
Packit 857059
										 * regions. */
Packit 857059
	unsigned char *buffer = NULL;	/* Pointer into rawBuffer. */
Packit 857059
	unsigned int totalBufferSize = BARRIERSIZE * 2 + maxSize;
Packit 857059
Packit 857059
	ROOTPRINT( "Beginning Randomize Test Section\n" );
Packit 857059
	ROOTPRINT( "(Node sends random length messages to each other.)\n" );
Packit 857059
Packit 857059
	initrandom(  );
Packit 857059
Packit 857059
	memset( request, 0, sizeof( MPI_Request ) * NUMRANDXFERS );
Packit 857059
	memset( status, 0, sizeof( MPI_Status ) * NUMRANDXFERS );
Packit 857059
Packit 857059
	sendMode = ( myid % 2 ) == 0;
Packit 857059
Packit 857059
	if ( sendMode ) {
Packit 857059
		partner = myid + 1;
Packit 857059
	} else {
Packit 857059
		partner = myid - 1;
Packit 857059
	}
Packit 857059
Packit 857059
	rawBuffer = malloc( totalBufferSize );
Packit 857059
	if ( !rawBuffer ) {
Packit 857059
		ERRPRINT( "Failed to allocate buffers.\n" );
Packit 857059
		retCode = ~MPI_SUCCESS;
Packit 857059
		goto done;
Packit 857059
	}
Packit 857059
Packit 857059
	buffer = rawBuffer + BARRIERSIZE;
Packit 857059
	size = minSize;
Packit 857059
Packit 857059
	while ( size <= maxSize ) {
Packit 857059
		int round = 0;
Packit 857059
		iters = maxIters;
Packit 857059
		while ( iters > 0 ) {
Packit 857059
			/* Initialize the buffer to our rank as a pad value. */
Packit 857059
			memset( rawBuffer, myid, totalBufferSize );
Packit 857059
Packit 857059
			if ( sendMode ) {
Packit 857059
				/* Initialize the buffer with some random data. */
Packit 857059
				/* Every 4th byte is a check sum of the previous 3. */
Packit 857059
				for ( i = 0; i < ( size - 3 ); i += 4 ) {
Packit 857059
					buffer[i] = random(  ) % 256;
Packit 857059
					buffer[i + 1] = random(  ) % 256;
Packit 857059
					buffer[i + 2] = random(  ) % 256;
Packit 857059
					buffer[i + 3] =
Packit 857059
						( buffer[i] + buffer[i + 1] + buffer[i + 2] ) % 256;
Packit 857059
				}
Packit 857059
Packit 857059
				/* Build a list of randomly sized messages to send. */
Packit 857059
				/* Note that we effectively "null terminate" the list. */
Packit 857059
				memset( records, 0, sizeof( RandomRecord ) * NUMRANDXFERS );
Packit 857059
				i = 0;
Packit 857059
				numRecords = 0;
Packit 857059
				while ( i < size ) {
Packit 857059
					records[numRecords].start = i;
Packit 857059
					records[numRecords].length = RANDOMLEN(  );
Packit 857059
					if ( records[numRecords].length + i > size ) {
Packit 857059
						records[numRecords].length = size - i;
Packit 857059
					}
Packit 857059
					i += records[numRecords].length;
Packit 857059
					numRecords++;
Packit 857059
				}
Packit 857059
Packit 857059
				/* Note that numRecords is now the length of records. */
Packit 857059
Packit 857059
				/* Swap a few records, for extra evil. */
Packit 857059
				i = random(  ) % SHUFFLERATE;
Packit 857059
				while ( i < NUMRANDXFERS && records[i].length ) {
Packit 857059
					unsigned int j;
Packit 857059
Packit 857059
					j = i + ( random(  ) % SHUFFLERATE );
Packit 857059
					if ( ( j != i ) && ( j < NUMRANDXFERS )
Packit 857059
						 && ( records[j].length ) ) {
Packit 857059
						RandomRecord r;
Packit 857059
Packit 857059
						r.start = records[j].start;
Packit 857059
						r.length = records[j].length;
Packit 857059
						records[j].start = records[i].start;
Packit 857059
						records[j].length = records[i].length;
Packit 857059
						records[i].start = r.start;
Packit 857059
						records[i].length = r.length;
Packit 857059
					}
Packit 857059
					i = j;
Packit 857059
				}
Packit 857059
Packit 857059
				/* Dump a list of the records. */
Packit 857059
				if ( verboseMode ) {
Packit 857059
					for ( i = 0; ( i < NUMRANDXFERS ) && ( records[i].length );
Packit 857059
						  i++ ) {
Packit 857059
						NODEPRINT( "X %d - %d\n", records[i].start,
Packit 857059
								   records[i].length );
Packit 857059
					}
Packit 857059
				}
Packit 857059
Packit 857059
				/* Send the record list to our partner. */
Packit 857059
				retCode = MPI_Send( records,
Packit 857059
									NUMRANDXFERS * sizeof( RandomRecord ),
Packit 857059
									MPI_BYTE, partner, 0, MPI_COMM_WORLD );
Packit 857059
				ERRABORT( retCode );
Packit 857059
Packit 857059
				for ( i = 0; ( i < NUMRANDXFERS ) && ( records[i].length );
Packit 857059
					  i++ ) {
Packit 857059
					NODEPRINT( "S %d - %x\n", records[i].start,
Packit 857059
							   records[i].length );
Packit 857059
					retCode = MPI_Isend( &buffer[records[i].start], 
Packit 857059
										 records[i].length,
Packit 857059
								   		 MPI_BYTE, partner, i, MPI_COMM_WORLD,
Packit 857059
								   		 &request[i] );
Packit 857059
					ERRABORT( retCode );
Packit 857059
					round++;
Packit 857059
					if (!verboseMode && (round % 100) == 0)
Packit 857059
						ROOTPRINT(".");
Packit 857059
				}
Packit 857059
			} else {
Packit 857059
				/* Get the record list from our partner. */
Packit 857059
				retCode = MPI_Recv( records,
Packit 857059
									NUMRANDXFERS * sizeof( RandomRecord ),
Packit 857059
									MPI_BYTE,
Packit 857059
									partner, 0, MPI_COMM_WORLD, &status[0] );
Packit 857059
				ERRABORT( retCode );
Packit 857059
Packit 857059
				for ( i = 0; ( i < NUMRANDXFERS ) && ( records[i].length );
Packit 857059
					  i++ ) {
Packit 857059
					NODEPRINT( "R %d - %x\n", records[i].start,
Packit 857059
							   records[i].length );
Packit 857059
					retCode = MPI_Irecv( &buffer[records[i].start], 
Packit 857059
										 records[i].length,
Packit 857059
								   		 MPI_BYTE, partner, i, MPI_COMM_WORLD,
Packit 857059
								   		 &request[i] );
Packit 857059
					ERRABORT( retCode );
Packit 857059
				}
Packit 857059
				numRecords = i;	/* Save the # of records. */
Packit 857059
			}
Packit 857059
Packit 857059
			retCode = MPI_Waitall( numRecords, request, status );
Packit 857059
			ERRABORT( retCode );
Packit 857059
			for ( i = 0; i < numRecords; i++ ) {
Packit 857059
				ERRABORT( status[i].MPI_ERROR );
Packit 857059
			}
Packit 857059
Packit 857059
			/* Check for corruption. */
Packit 857059
			if ( !sendMode ) {
Packit 857059
				for ( i = 0; i < ( size - 3 ); i += 4 ) {
Packit 857059
					unsigned char c =
Packit 857059
						( buffer[i] + buffer[i + 1] + buffer[i + 2] ) % 256;
Packit 857059
					if ( c != buffer[i + 3] ) {
Packit 857059
						ERRPRINT( "Corruption in the buffer @ %d\n", i );
Packit 857059
						dumpbuffer( myid, "rawBuffer", (char*)rawBuffer,
Packit 857059
									size + 2 * BARRIERSIZE );
Packit 857059
						retCode = ~MPI_SUCCESS;
Packit 857059
						goto done;
Packit 857059
					}
Packit 857059
				}
Packit 857059
			}
Packit 857059
Packit 857059
			iters -= numRecords;
Packit 857059
Packit 857059
		}
Packit 857059
Packit 857059
		ROOTPRINT( "\t%8d\n", size );
Packit 857059
		size *= 2;
Packit 857059
	}
Packit 857059
Packit 857059
	MPI_Barrier( MPI_COMM_WORLD );
Packit 857059
	ROOTPRINT( "Completed Randomize Test Section.\n\n" );
Packit 857059
Packit 857059
  done:
Packit 857059
Packit 857059
	if ( rawBuffer )
Packit 857059
		free( rawBuffer );
Packit 857059
Packit 857059
	return retCode;
Packit 857059
}
Packit 857059
Packit 857059
/* 
Packit 857059
 * Calculate the average time to complete MPI_Init.
Packit 857059
 */
Packit 857059
#define HOSTNAMELEN 32
Packit 857059
#define HOSTOFFSET  8
Packit 857059
int
Packit 857059
calc_init_time( int myid, int numProcs, time_t t_start, time_t t_end,
Packit 857059
				time_t * t_avg )
Packit 857059
{
Packit 857059
	time_t t_delta, t_min, t_max, t_temp;
Packit 857059
	int i, retCode = MPI_SUCCESS;
Packit 857059
Packit 857059
	if ( myid != 0 ) {
Packit 857059
		/* Send our time to init back to the 0 node. */
Packit 857059
		char mydata[HOSTNAMELEN + HOSTOFFSET];
Packit 857059
Packit 857059
		/* Build a buffer containing our host name and the elapsed time. */
Packit 857059
		t_delta = t_end - t_start;
Packit 857059
		*( ( time_t * ) mydata ) = t_delta;
Packit 857059
		gethostname( &mydata[HOSTOFFSET], HOSTNAMELEN );
Packit 857059
Packit 857059
		mydata[HOSTOFFSET + HOSTNAMELEN - 1] = 0;
Packit 857059
Packit 857059
		retCode = MPI_Send( mydata,
Packit 857059
							HOSTNAMELEN + HOSTOFFSET, MPI_CHAR, 0, 0,
Packit 857059
							MPI_COMM_WORLD );
Packit 857059
		ERRABORT( retCode );
Packit 857059
	} else {
Packit 857059
		/* Collect time to init data. */
Packit 857059
		MPI_Status status;
Packit 857059
		char curdata[HOSTNAMELEN + HOSTOFFSET];
Packit 857059
		char min_host[HOSTNAMELEN];
Packit 857059
		char max_host[HOSTNAMELEN];
Packit 857059
		double avg;
Packit 857059
Packit 857059
		/* Initially the root is both best and worst. */
Packit 857059
		gethostname( min_host, HOSTNAMELEN );
Packit 857059
		gethostname( max_host, HOSTNAMELEN );
Packit 857059
Packit 857059
		t_delta = t_end - t_start;
Packit 857059
		t_min = t_delta;
Packit 857059
		t_max = t_delta;
Packit 857059
Packit 857059
		/* 
Packit 857059
		 * We don't care what order the replies come in, 
Packit 857059
		 * as long as we get them all.
Packit 857059
		 */
Packit 857059
		for ( i = 0; i < numProcs - 1; i++ ) {
Packit 857059
			memset( &status, 0, sizeof( status ) );
Packit 857059
			retCode = MPI_Recv( curdata,
Packit 857059
								HOSTNAMELEN + HOSTOFFSET, MPI_CHAR,
Packit 857059
								MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, &status );
Packit 857059
			ERRABORT( retCode );
Packit 857059
			t_temp = *( ( time_t * ) curdata );
Packit 857059
			t_delta += t_temp;
Packit 857059
Packit 857059
			if ( t_temp < t_min ) {
Packit 857059
				t_min = t_temp;
Packit 857059
				strcpy( min_host, &curdata[HOSTOFFSET] );
Packit 857059
			} else if ( t_temp > t_max ) {
Packit 857059
				t_max = t_temp;
Packit 857059
				strcpy( max_host, &curdata[HOSTOFFSET] );
Packit 857059
			}
Packit 857059
		}
Packit 857059
Packit 857059
		avg = ( double ) t_delta / ( double ) numProcs;
Packit 857059
		ROOTPRINT( "Maximum time to init was: %8ld seconds (%s).\n",
Packit 857059
				   t_max, max_host );
Packit 857059
		ROOTPRINT( "Minimum time to init was: %8ld seconds (%s).\n",
Packit 857059
				   t_min, min_host );
Packit 857059
		ROOTPRINT( "Average time to init was: %8.2lf seconds.\n", avg );
Packit 857059
	}
Packit 857059
Packit 857059
	return retCode;
Packit 857059
}
Packit 857059
Packit 857059
/* 
Packit 857059
 * Simple whisper down the lane test. Rank 0 sends a message to rank 1,
Packit 857059
 * who passes it to 2, etc., till rank N returns it to rank 0. At that
Packit 857059
 * point, it is compared against what was sent.
Packit 857059
 *
Packit 857059
 * This code is made more complicated by the desire to mangle memory 
Packit 857059
 * usage in order to uncover possible corruption issues. If useSendOffset
Packit 857059
 * is specified, each successive round moves the buffer one byte higher
Packit 857059
 * in memory. In addition, if rawBufferCount is > 1, the code will use
Packit 857059
 * multiple buffers in a ring. This is primarily to cause an increase in
Packit 857059
 * total memory consumption to induce paging operations, which can affect
Packit 857059
 * memory transfers to/from the HCA.
Packit 857059
 *
Packit 857059
 */
Packit 857059
int
Packit 857059
slowRing( int myid, int numProcs, int minSize, int maxSize, int maxIters )
Packit 857059
{
Packit 857059
	unsigned int i, size, iters, round;
Packit 857059
	int retCode = MPI_SUCCESS;
Packit 857059
Packit 857059
	MPI_Request *request = NULL;
Packit 857059
	MPI_Status *status = NULL;
Packit 857059
Packit 857059
	char **rawSendBuffer = NULL;
Packit 857059
	char **rawRecvBuffer = NULL;
Packit 857059
	char *sendBuffer, *recvBuffer;
Packit 857059
Packit 857059
	request = malloc( sizeof( MPI_Request ) );
Packit 857059
	status = malloc( sizeof( MPI_Status ) );
Packit 857059
	if ( !request || !status ) {
Packit 857059
		ERRPRINT( "Failed to allocate requests and status.\n" );
Packit 857059
		retCode = ~MPI_SUCCESS;
Packit 857059
		goto done;
Packit 857059
	}
Packit 857059
Packit 857059
	memset( request, 0, sizeof( MPI_Request ) );
Packit 857059
	memset( status, 0, sizeof( MPI_Status ) );
Packit 857059
Packit 857059
	rawSendBuffer = malloc( sizeof( char * ) * rawBufferCount );
Packit 857059
	rawRecvBuffer = malloc( sizeof( char * ) * rawBufferCount );
Packit 857059
	memset( rawSendBuffer, 0, sizeof( char * ) * rawBufferCount );
Packit 857059
	memset( rawRecvBuffer, 0, sizeof( char * ) * rawBufferCount );
Packit 857059
Packit 857059
	ROOTPRINT( "Beginning Slow Ring Test Section\n" );
Packit 857059
	ROOTPRINT( "(This test passes messages from node to node in a ring\n"
Packit 857059
			   "and validates that the end result matches the original\n"
Packit 857059
			   "message.)\n" );
Packit 857059
Packit 857059
	size = minSize;
Packit 857059
	iters = maxIters;
Packit 857059
Packit 857059
	while ( size <= maxSize ) {
Packit 857059
Packit 857059
		for ( round = 0; round < iters; round++ ) {
Packit 857059
			size_t rawBufferSize =
Packit 857059
				( barrierSize * 2 ) + ( size + ( useSendOffset ? round : 0 ) );
Packit 857059
			char *currentRawSendBuffer;
Packit 857059
			char *currentRawRecvBuffer;
Packit 857059
Packit 857059
			/* 
Packit 857059
			 * If we already had a buffer here, we free it then
Packit 857059
			 * reallocate it. In a sane world, we will normally
Packit 857059
			 * get the same memory back again, but this could also
Packit 857059
			 * trigger various "optimizations" in malloc's handling
Packit 857059
			 * of the heap and the operating system's handling of 
Packit 857059
			 * the page table - and it stresses any malloc management
Packit 857059
			 * magic in MPI itself...
Packit 857059
			 */
Packit 857059
			if ( rawSendBuffer[round % rawBufferCount] != NULL ) {
Packit 857059
				free( rawSendBuffer[round % rawBufferCount] );
Packit 857059
			}
Packit 857059
			rawSendBuffer[round % rawBufferCount] = malloc( rawBufferSize );
Packit 857059
			if ( rawRecvBuffer[round % rawBufferCount] != NULL ) {
Packit 857059
				free( rawRecvBuffer[round % rawBufferCount] );
Packit 857059
			}
Packit 857059
			rawRecvBuffer[round % rawBufferCount] = malloc( rawBufferSize );
Packit 857059
			if ( !rawRecvBuffer[round % rawBufferCount]
Packit 857059
				 || !rawSendBuffer[round % rawBufferCount] ) {
Packit 857059
				ERRPRINT( "Failed to allocate buffers.\n" );
Packit 857059
				retCode = ~MPI_SUCCESS;
Packit 857059
				goto done;
Packit 857059
			}
Packit 857059
Packit 857059
			currentRawSendBuffer = rawSendBuffer[round % rawBufferCount];
Packit 857059
			currentRawRecvBuffer = rawRecvBuffer[round % rawBufferCount];
Packit 857059
Packit 857059
			sendBuffer =
Packit 857059
				currentRawSendBuffer + barrierSize +
Packit 857059
				( useSendOffset ? round : 0 );
Packit 857059
			recvBuffer =
Packit 857059
				currentRawRecvBuffer + barrierSize +
Packit 857059
				( useSendOffset ? round : 0 );
Packit 857059
Packit 857059
			/* 
Packit 857059
			 * Setting up guard areas to check for corruption.
Packit 857059
			 */
Packit 857059
			memset( currentRawSendBuffer, myid, rawBufferSize );
Packit 857059
			memset( currentRawRecvBuffer, myid, rawBufferSize );
Packit 857059
Packit 857059
			/* Create some data to send and validate against. */
Packit 857059
			for ( i = 0; i < size; i++ )
Packit 857059
				sendBuffer[i] = ( unsigned char ) ( i % 256 );
Packit 857059
Packit 857059
			if ( myid == 0 ) {
Packit 857059
				/* Root initiates the loop and vets the results. */
Packit 857059
				NODEPRINT( "S node 1\n" );
Packit 857059
Packit 857059
				retCode =
Packit 857059
					MPI_Send( sendBuffer, size, MPI_CHAR, 1, round,
Packit 857059
							  MPI_COMM_WORLD );
Packit 857059
				ERRABORT( retCode );
Packit 857059
Packit 857059
				NODEPRINT( "W node %d\n", numProcs - 1 );
Packit 857059
Packit 857059
				retCode = MPI_Recv( recvBuffer,
Packit 857059
									size,
Packit 857059
									MPI_CHAR,
Packit 857059
									numProcs - 1,
Packit 857059
									round, MPI_COMM_WORLD, status );
Packit 857059
				ERRABORT( retCode );
Packit 857059
Packit 857059
				if ( memcmp( currentRawSendBuffer,
Packit 857059
							 currentRawRecvBuffer, rawBufferSize ) ) {
Packit 857059
					ERRPRINT( "%d byte messages do not match!\n", size );
Packit 857059
					dumpbuffer( myid, "rawSendBuffer", currentRawSendBuffer,
Packit 857059
								rawBufferSize );
Packit 857059
					dumpbuffer( myid, "rawRecvBuffer", currentRawRecvBuffer,
Packit 857059
								rawBufferSize );
Packit 857059
					retCode = ~MPI_SUCCESS;
Packit 857059
					goto done;
Packit 857059
				}
Packit 857059
			} else {
Packit 857059
				/* Everyone else waits for a message and then repeats it to
Packit 857059
				 * their neighbor. */
Packit 857059
				NODEPRINT( "W node %d\n", myid - 1 );
Packit 857059
				retCode = MPI_Recv( recvBuffer,
Packit 857059
									size,
Packit 857059
									MPI_CHAR,
Packit 857059
									myid - 1, round, MPI_COMM_WORLD, status );
Packit 857059
				ERRABORT( retCode );
Packit 857059
				NODEPRINT( "S node %d\n", myid + 1 );
Packit 857059
				retCode = MPI_Send( recvBuffer,
Packit 857059
									size,
Packit 857059
									MPI_CHAR,
Packit 857059
									( myid + 1 ) % numProcs,
Packit 857059
									round, MPI_COMM_WORLD );
Packit 857059
				ERRABORT( retCode );
Packit 857059
Packit 857059
				/* 
Packit 857059
				 * Note that we never sent SendBuffer but it should still
Packit 857059
				 * be a correct model of what we actually received then 
Packit 857059
				 * sent.
Packit 857059
				 */
Packit 857059
				if ( memcmp( currentRawSendBuffer,
Packit 857059
							 currentRawRecvBuffer, rawBufferSize ) ) {
Packit 857059
					ERRPRINT( "%d byte messages do not match!\n", size );
Packit 857059
					dumpbuffer( myid, "rawSendBuffer", currentRawSendBuffer,
Packit 857059
								rawBufferSize );
Packit 857059
					dumpbuffer( myid, "rawRecvBuffer", currentRawRecvBuffer,
Packit 857059
								rawBufferSize );
Packit 857059
					retCode = ~MPI_SUCCESS;
Packit 857059
					goto done;
Packit 857059
				}
Packit 857059
			}
Packit 857059
Packit 857059
			if ( !verboseMode && ( round % 100 ) == 0 )
Packit 857059
				ROOTPRINT( "." );
Packit 857059
		}
Packit 857059
		ROOTPRINT( "\t%8d\n", size );
Packit 857059
Packit 857059
		size *= 2;
Packit 857059
		iters = ( iters > 1 ) ? iters / 2 : 1;
Packit 857059
	}
Packit 857059
Packit 857059
	ROOTPRINT( "Completed Slow Ring Test Section.\n\n" );
Packit 857059
Packit 857059
  done:
Packit 857059
	if ( rawRecvBuffer ) {
Packit 857059
		for ( i = 0; i < rawBufferCount; i++ ) {
Packit 857059
			if ( rawRecvBuffer[i] ) {
Packit 857059
				free( rawRecvBuffer[i] );
Packit 857059
			}
Packit 857059
		}
Packit 857059
Packit 857059
		free( rawRecvBuffer );
Packit 857059
	}
Packit 857059
Packit 857059
	if ( rawSendBuffer ) {
Packit 857059
		for ( i = 0; i < rawBufferCount; i++ ) {
Packit 857059
			if ( rawSendBuffer[i] ) {
Packit 857059
				free( rawSendBuffer[i] );
Packit 857059
			}
Packit 857059
		}
Packit 857059
Packit 857059
		free( rawSendBuffer );
Packit 857059
	}
Packit 857059
Packit 857059
	if ( request )
Packit 857059
		free( request );
Packit 857059
	if ( status )
Packit 857059
		free( status );
Packit 857059
	return retCode;
Packit 857059
}
Packit 857059
Packit 857059
/* 
Packit 857059
 * Fast whisper down the lane test. Rank 0 sends many messages to rank 1,
Packit 857059
 * who passes them to 2, etc., till rank N returns them to rank 0. At that
Packit 857059
 * point, the messages are compared against what was sent.
Packit 857059
 */
Packit 857059
int
Packit 857059
fastRing( int myid, int numProcs, int minSize, int maxSize, int maxIters )
Packit 857059
{
Packit 857059
	unsigned int i, j, size, iters, round;
Packit 857059
	int retCode = MPI_SUCCESS;
Packit 857059
Packit 857059
	MPI_Request *request = NULL;
Packit 857059
	MPI_Status *status = NULL;
Packit 857059
Packit 857059
	char **rawSendBuffer = NULL;
Packit 857059
	char **rawRecvBuffer = NULL;
Packit 857059
	char *sendBuffer, *recvBuffer;
Packit 857059
	size_t rawBufferSize =
Packit 857059
		( barrierSize * 2 ) + ( maxSize + ( useSendOffset ? maxIters : 0 ) );
Packit 857059
Packit 857059
	request = malloc( (rawBufferCount+maxIters) * sizeof( MPI_Request ) );
Packit 857059
	status = malloc( (rawBufferCount+maxIters) * sizeof( MPI_Status ) );
Packit 857059
	if ( !request || !status ) {
Packit 857059
		ERRPRINT( "Failed to allocate requests and status.\n" );
Packit 857059
		retCode = ~MPI_SUCCESS;
Packit 857059
		goto done;
Packit 857059
	}
Packit 857059
Packit 857059
	memset( request, 0, (rawBufferCount+maxIters) * sizeof( MPI_Request ) );
Packit 857059
	memset( status, 0, (rawBufferCount+maxIters) * sizeof( MPI_Status ) );
Packit 857059
Packit 857059
	rawSendBuffer = malloc( sizeof( char * ) * rawBufferCount );
Packit 857059
	rawRecvBuffer = malloc( sizeof( char * ) * rawBufferCount );
Packit 857059
	memset( rawSendBuffer, 0, sizeof( char * ) * rawBufferCount );
Packit 857059
	memset( rawRecvBuffer, 0, sizeof( char * ) * rawBufferCount );
Packit 857059
Packit 857059
	for ( i = 0; i < rawBufferCount; i++ ) {
Packit 857059
		rawSendBuffer[i] = malloc( rawBufferSize );
Packit 857059
		rawRecvBuffer[i] = malloc( rawBufferSize );
Packit 857059
Packit 857059
		if ( !rawRecvBuffer[i] || !rawSendBuffer[i] ) {
Packit 857059
			ERRPRINT( "Failed to allocate buffers.\n" );
Packit 857059
			retCode = ~MPI_SUCCESS;
Packit 857059
			goto done;
Packit 857059
		}
Packit 857059
	}
Packit 857059
Packit 857059
	ROOTPRINT( "Beginning Fast Ring Test Section\n" );
Packit 857059
	ROOTPRINT( "(This test passes multiple messages from node to node in a\n"
Packit 857059
			   "ring and validates that the end result matches the original\n"
Packit 857059
			   "message.)\n" );
Packit 857059
Packit 857059
	size = minSize;
Packit 857059
	iters = maxIters;
Packit 857059
Packit 857059
	while ( size <= maxSize ) {
Packit 857059
Packit 857059
		if ( myid == 0 ) {
Packit 857059
			for ( j = 0; j < rawBufferCount; j++) {
Packit 857059
				char *currentRawSendBuffer = rawSendBuffer[j];
Packit 857059
				char *currentRawRecvBuffer = rawRecvBuffer[j];
Packit 857059
Packit 857059
				/* 
Packit 857059
				 * Setting up guard areas to check for corruption.
Packit 857059
				 */
Packit 857059
				memset( currentRawSendBuffer, myid, rawBufferSize );
Packit 857059
				memset( currentRawRecvBuffer, myid, rawBufferSize );
Packit 857059
Packit 857059
				sendBuffer = currentRawSendBuffer + barrierSize;
Packit 857059
Packit 857059
				/* Create some data to send and validate against. */
Packit 857059
				for ( i = 0; i < size; i++ )
Packit 857059
					sendBuffer[i] = ( unsigned char ) ( i % 256 );
Packit 857059
			}
Packit 857059
Packit 857059
			for ( round = 0; round < iters; round+= rawBufferCount ) {
Packit 857059
Packit 857059
				/* Fire in the hole! */
Packit 857059
				for (j = 0; j
Packit 857059
					char *currentRawSendBuffer = rawSendBuffer[j];
Packit 857059
Packit 857059
					sendBuffer = currentRawSendBuffer + barrierSize;
Packit 857059
Packit 857059
					NODEPRINT( "S node 1\n" );
Packit 857059
Packit 857059
					retCode = MPI_Isend( sendBuffer, size, MPI_CHAR, 1, 
Packit 857059
										 round + j,
Packit 857059
							   			 MPI_COMM_WORLD, 
Packit 857059
										 &request[round+j] );
Packit 857059
					ERRABORT( retCode );
Packit 857059
				}
Packit 857059
Packit 857059
Packit 857059
				/* Process the messages as they come home. */
Packit 857059
				for ( j = 0; j < rawBufferCount; j++ ) {
Packit 857059
					char *currentRawRecvBuffer = rawRecvBuffer[j];
Packit 857059
					char *currentRawSendBuffer = rawSendBuffer[j];
Packit 857059
Packit 857059
					recvBuffer = currentRawRecvBuffer + barrierSize +
Packit 857059
								 ( useSendOffset ? (round + j) : 0 );
Packit 857059
Packit 857059
					NODEPRINT( "W node %d / %p \n", numProcs - 1, recvBuffer );
Packit 857059
Packit 857059
					retCode = MPI_Recv( recvBuffer,
Packit 857059
										size,
Packit 857059
										MPI_CHAR,
Packit 857059
										numProcs - 1,
Packit 857059
										round+j, 
Packit 857059
										MPI_COMM_WORLD, 
Packit 857059
										&(status[round+j]) );
Packit 857059
					ERRABORT( retCode );
Packit 857059
Packit 857059
					if ( memcmp( currentRawSendBuffer, currentRawRecvBuffer,
Packit 857059
							 rawBufferSize ) ) {
Packit 857059
						ERRPRINT( "%d byte messages do not match!\n", size );
Packit 857059
						dumpbuffer( myid, "rawSendBuffer", currentRawSendBuffer,
Packit 857059
									rawBufferSize );
Packit 857059
						dumpbuffer( myid, "rawRecvBuffer", currentRawRecvBuffer,
Packit 857059
									rawBufferSize );
Packit 857059
						retCode = ~MPI_SUCCESS;
Packit 857059
						goto done;
Packit 857059
					}
Packit 857059
Packit 857059
					if ( !verboseMode && ( (round+j) % 100 ) == 0 )
Packit 857059
							ROOTPRINT( "." );
Packit 857059
Packit 857059
				}
Packit 857059
			}
Packit 857059
Packit 857059
		} else {
Packit 857059
			unsigned iters2 = iters;
Packit 857059
			if ((iters % rawBufferCount) != 0) 
Packit 857059
				iters2 += (rawBufferCount - (iters % rawBufferCount));
Packit 857059
Packit 857059
			/* Everyone else waits for a message and then repeats it to their
Packit 857059
			 * neighbor. */
Packit 857059
			for ( round = 0; round < iters2; round++ ) {
Packit 857059
				char *currentRawSendBuffer =
Packit 857059
					rawSendBuffer[round % rawBufferCount];
Packit 857059
				char *currentRawRecvBuffer =
Packit 857059
					rawRecvBuffer[round % rawBufferCount];
Packit 857059
Packit 857059
				sendBuffer = currentRawSendBuffer + barrierSize;
Packit 857059
				recvBuffer = currentRawRecvBuffer + barrierSize;
Packit 857059
Packit 857059
				/* 
Packit 857059
				 * Setting up guard areas to check for corruption.
Packit 857059
				 */
Packit 857059
				memset( currentRawSendBuffer, myid, rawBufferSize );
Packit 857059
				memset( currentRawRecvBuffer, myid, rawBufferSize );
Packit 857059
Packit 857059
				/* Create some data to send and validate against. */
Packit 857059
				for ( i = 0; i < size; i++ )
Packit 857059
					sendBuffer[i] = ( unsigned char ) ( i % 256 );
Packit 857059
Packit 857059
				NODEPRINT( "W node %d\n", myid - 1 );
Packit 857059
				retCode = MPI_Recv( recvBuffer,
Packit 857059
									size,
Packit 857059
									MPI_CHAR,
Packit 857059
									myid - 1, round, MPI_COMM_WORLD, status );
Packit 857059
				ERRABORT( retCode );
Packit 857059
				NODEPRINT( "S node %d\n", myid + 1 );
Packit 857059
				retCode = MPI_Send( recvBuffer,
Packit 857059
									size,
Packit 857059
									MPI_CHAR,
Packit 857059
									( myid + 1 ) % numProcs,
Packit 857059
									round, MPI_COMM_WORLD );
Packit 857059
				ERRABORT( retCode );
Packit 857059
Packit 857059
				/* 
Packit 857059
				 * Note that we never sent SendBuffer but it should still
Packit 857059
				 * be a correct model of what we actually received then 
Packit 857059
				 * sent.
Packit 857059
				 */
Packit 857059
				if ( memcmp( currentRawSendBuffer,
Packit 857059
							 currentRawRecvBuffer, rawBufferSize ) ) {
Packit 857059
					ERRPRINT( "%d byte messages do not match!\n", size );
Packit 857059
					dumpbuffer( myid, "rawSendBuffer", currentRawSendBuffer,
Packit 857059
								rawBufferSize );
Packit 857059
					dumpbuffer( myid, "rawRecvBuffer", currentRawRecvBuffer,
Packit 857059
								rawBufferSize );
Packit 857059
					retCode = ~MPI_SUCCESS;
Packit 857059
					goto done;
Packit 857059
				}
Packit 857059
			}
Packit 857059
		}
Packit 857059
		ROOTPRINT( "\t%8d\n", size );
Packit 857059
Packit 857059
		size *= 2;
Packit 857059
		iters = ( iters > 1 ) ? iters / 2 : 1;
Packit 857059
	}
Packit 857059
Packit 857059
	ROOTPRINT( "Completed Fast Ring Test Section.\n\n" );
Packit 857059
Packit 857059
  done:
Packit 857059
	if ( rawRecvBuffer ) {
Packit 857059
		for ( i = 0; i < rawBufferCount; i++ ) {
Packit 857059
			if ( rawRecvBuffer[i] ) {
Packit 857059
				free( rawRecvBuffer[i] );
Packit 857059
			}
Packit 857059
		}
Packit 857059
Packit 857059
		free( rawRecvBuffer );
Packit 857059
	}
Packit 857059
Packit 857059
	if ( rawSendBuffer ) {
Packit 857059
		for ( i = 0; i < rawBufferCount; i++ ) {
Packit 857059
			if ( rawSendBuffer[i] ) {
Packit 857059
				free( rawSendBuffer[i] );
Packit 857059
			}
Packit 857059
		}
Packit 857059
Packit 857059
		free( rawSendBuffer );
Packit 857059
	}
Packit 857059
Packit 857059
	if ( request )
Packit 857059
		free( request );
Packit 857059
	if ( status )
Packit 857059
		free( status );
Packit 857059
	return retCode;
Packit 857059
}
Packit 857059
Packit 857059
int
Packit 857059
main( int argc, char *argv[] )
Packit 857059
{
Packit 857059
	int retCode, myid, numProcs, i;
Packit 857059
	time_t t1, t2, t3;
Packit 857059
Packit 857059
	t1 = time( NULL );
Packit 857059
	MPI_Init( &argc, &argv );
Packit 857059
	MPI_Comm_size( MPI_COMM_WORLD, &numProcs );
Packit 857059
	MPI_Comm_rank( MPI_COMM_WORLD, &myid );
Packit 857059
	t2 = time( NULL );
Packit 857059
Packit 857059
	while ( -1 !=
Packit 857059
			( retCode = getopt_long_only( argc, argv, "", options, &i ) ) ) {
Packit 857059
		switch ( retCode ) {
Packit 857059
		case '<':
Packit 857059
			minSize = strtoul( optarg, NULL, 0 );
Packit 857059
			break;
Packit 857059
		case '>':
Packit 857059
			maxSize = strtoul( optarg, NULL, 0 );
Packit 857059
			break;
Packit 857059
		case 'i':
Packit 857059
			maxIters = strtoul( optarg, NULL, 0 );
Packit 857059
			break;
Packit 857059
		case 'b':
Packit 857059
			rawBufferCount = strtoul( optarg, NULL, 0 );
Packit 857059
			break;
Packit 857059
		case 'B':
Packit 857059
			barrierSize = strtoul( optarg, NULL, 0 );
Packit 857059
			break;
Packit 857059
		case '?':
Packit 857059
			usage(  );
Packit 857059
			goto done;
Packit 857059
		default:
Packit 857059
			break;
Packit 857059
		}
Packit 857059
	}
Packit 857059
Packit 857059
	ROOTPRINT( "-----------------------------\n" );
Packit 857059
	ROOTPRINT( "-----------------------------\n" );
Packit 857059
	ROOTPRINT( "Initialization complete.\n" );
Packit 857059
	MPI_Barrier( MPI_COMM_WORLD );
Packit 857059
	retCode = calc_init_time( myid, numProcs, t1, t2, &t3 );
Packit 857059
	ERRABORT( retCode );
Packit 857059
Packit 857059
	ROOTPRINT( "--------------------------\n" );
Packit 857059
	ROOTPRINT( "--------------------------\n" );
Packit 857059
	ROOTPRINT( "Number of nodes      = %d\n", numProcs );
Packit 857059
	ROOTPRINT( "Minimum message size = %d\n", minSize );
Packit 857059
	ROOTPRINT( "Maximum message size = %d\n", maxSize );
Packit 857059
	ROOTPRINT( "Maximum # of rounds  = %d\n\n", maxIters );
Packit 857059
	ROOTPRINT( "Use Message Send Offset = %s\n", useSendOffset ? "ON" : "OFF" );
Packit 857059
	ROOTPRINT( "Message Buffer Count    = %d\n", rawBufferCount );
Packit 857059
	ROOTPRINT( "Message Barrier Size    = %d\n\n", barrierSize );
Packit 857059
Packit 857059
	if ( doSlow ) {
Packit 857059
		MPI_Barrier( MPI_COMM_WORLD );
Packit 857059
		retCode = slowRing( myid, numProcs, minSize, maxSize, maxIters );
Packit 857059
		ERRABORT( retCode );
Packit 857059
	}
Packit 857059
	if ( doFast ) {
Packit 857059
		MPI_Barrier( MPI_COMM_WORLD );
Packit 857059
		retCode = fastRing( myid, numProcs, minSize, maxSize, maxIters );
Packit 857059
		ERRABORT( retCode );
Packit 857059
	}
Packit 857059
	if ( doRandom ) {
Packit 857059
		MPI_Barrier( MPI_COMM_WORLD );
Packit 857059
		retCode = randomize( myid, numProcs, minSize, maxSize, maxIters );
Packit 857059
		ERRABORT( retCode );
Packit 857059
	}
Packit 857059
Packit 857059
	ROOTPRINT( "--------------------------\n" );
Packit 857059
	ROOTPRINT( "--------------------------\n" );
Packit 857059
Packit 857059
  done:
Packit 857059
	MPI_Finalize(  );
Packit 857059
	return retCode;
Packit 857059
}