Blame MpiApps/apps/groupstress/mpi_latencystress.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
/*
Packit 857059
 * Copyright (C) 2002-2005 the Network-Based Computing Laboratory
Packit 857059
 * (NBCL), The Ohio State University. 
Packit 857059
 *
Packit 857059
 * Contact: Dr. D. K. Panda (panda@cse.ohio-state.edu)
Packit 857059
 */
Packit 857059
Packit 857059
/*
Packit 857059
This program is available under BSD licensing.
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
Packit 857059
met:
Packit 857059
Packit 857059
(1) Redistributions of source code must retain the above copyright
Packit 857059
notice, this list of conditions and the following disclaimer.
Packit 857059
Packit 857059
(2) 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
Packit 857059
(3) Neither the name of The Ohio State University nor the names of
Packit 857059
their contributors may be used to endorse or promote products derived
Packit 857059
from this software without specific prior written permission.
Packit 857059
Packit 857059
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 857059
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 857059
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit 857059
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit 857059
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit 857059
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 857059
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 857059
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 857059
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 857059
(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
*/
Packit 857059
Packit 857059
/* mpi_latencystress
Packit 857059
Packit 857059
The purpose of this program is to stress links in a large IB fabric. 
Packit 857059
While it generates some basic numbers about how the links
Packit 857059
are performing, it is not intended as a benchmark.
Packit 857059
Packit 857059
*/
Packit 857059
Packit 857059
#include "mpi.h"
Packit 857059
#include <stdio.h>
Packit 857059
#include <unistd.h>
Packit 857059
#include <getopt.h>
Packit 857059
#include <stdlib.h>
Packit 857059
#include <string.h>
Packit 857059
#include <math.h>
Packit 857059
#include <time.h>
Packit 857059
Packit 857059
#define	 stringize(x) #x
Packit 857059
#define	 add_quotes(x) stringize(x)
Packit 857059
Packit 857059
#define	 DEBUG(X,...) if (verbose>2) printf(X, ## __VA_ARGS__ )
Packit 857059
#define	 VERBOSE(X,...) if (verbose>1) printf(X, ## __VA_ARGS__ )
Packit 857059
#define	 NORMAL(X,...) if (verbose>0) printf(X, ## __VA_ARGS__ )
Packit 857059
#define	 RANK0(X,...) if (verbose && my_id == 0) printf(X, ## __VA_ARGS__ )
Packit 857059
Packit 857059
#define	 MESSAGE_ALIGNMENT 64
Packit 857059
#define	 MIN_MSG_SIZE 0
Packit 857059
#define	 MAX_MSG_SIZE (1<<22)
Packit 857059
#define	 MY_BUF_SIZE (MAX_MSG_SIZE + MESSAGE_ALIGNMENT)
Packit 857059
#define  DEFAULT_MINUTES 5
Packit 857059
Packit 857059
#define  TAG_BASIC 1000
Packit 857059
#define  TAG_RSLT1 1001
Packit 857059
#define  TAG_RSLT2 1002
Packit 857059
Packit 857059
/*
Packit 857059
 * Command line args.
Packit 857059
 */
Packit 857059
static	 int minutes = DEFAULT_MINUTES; // how long the test should run.
Packit 857059
static	 int verbose = 0; // noisy output
Packit 857059
static	 int size = MIN_MSG_SIZE;
Packit 857059
static   int csv = 0; // generate CSV file
Packit 857059
Packit 857059
static	 int num_procs;	 // how many processes in the job?
Packit 857059
static	 int my_id;	   // my rank.
Packit 857059
Packit 857059
#define PATTERN_SIZE 80
Packit 857059
static u_int32_t pattern[] = {
Packit 857059
    0x63636363,
Packit 857059
    0xA3A3A3A3,
Packit 857059
    0x54545454,
Packit 857059
    0x47474747,
Packit 857059
    0x18181818,
Packit 857059
    0x63636363,
Packit 857059
    0xA3A3A3A3,
Packit 857059
    0x54545454,
Packit 857059
    0x47474747,
Packit 857059
    0x18181818,
Packit 857059
    0x63636363,
Packit 857059
    0xA3A3A3A3,
Packit 857059
    0x54545454,
Packit 857059
    0x47474747,
Packit 857059
    0x18181818,
Packit 857059
    0x63636363,
Packit 857059
    0xA3A3A3A3,
Packit 857059
    0x54545454,
Packit 857059
    0x47474747,
Packit 857059
    0x18181818,
Packit 857059
};
Packit 857059
Packit 857059
char	 s_buf1[MY_BUF_SIZE];
Packit 857059
char	 r_buf1[MY_BUF_SIZE];
Packit 857059
Packit 857059
struct	 partner {
Packit 857059
	int	 inuse;
Packit 857059
	int	 sender;
Packit 857059
	int	 receiver;
Packit 857059
};
Packit 857059
Packit 857059
#define	 MAX_HOST_LEN 32
Packit 857059
struct	 host { char name[MAX_HOST_LEN]; };
Packit 857059
Packit 857059
static	 struct partner *pair_list;
Packit 857059
static	 struct host *host_list;
Packit 857059
static	 short *checked;
Packit 857059
static	 double *latency;
Packit 857059
static	 unsigned long psize;
Packit 857059
static	 unsigned long csize;
Packit 857059
Packit 857059
static void
Packit 857059
dump_checked(int ranks)
Packit 857059
{
Packit 857059
	int i, j;
Packit 857059
	
Packit 857059
	printf("    ");
Packit 857059
	for (i = 0; i< ranks; i++) {
Packit 857059
		printf(":%4d",i);
Packit 857059
	}
Packit 857059
	printf("\n");
Packit 857059
	
Packit 857059
	for (j = 0; j < ranks; j++) {
Packit 857059
		printf("%4d",j);
Packit 857059
		for (i = 0; i < ranks; i++) {
Packit 857059
			if (checked[j*ranks+i]) {
Packit 857059
				printf(": %02u ", checked[j*ranks+i]);
Packit 857059
			} else {
Packit 857059
				printf(":    ");
Packit 857059
			}
Packit 857059
		}
Packit 857059
		printf("\n");
Packit 857059
	}
Packit 857059
}
Packit 857059
Packit 857059
static int
Packit 857059
calculate_pairs(int iteration, int ranks)
Packit 857059
{
Packit 857059
	int i,j, k, pairs_found, match_found;
Packit 857059
	
Packit 857059
	memset(pair_list,0,psize);
Packit 857059
	
Packit 857059
	pairs_found = 0;
Packit 857059
Packit 857059
	if (iteration > ranks) return 0;
Packit 857059
Packit 857059
	for (i=0; i
Packit 857059
		match_found = 0;
Packit 857059
		if (pair_list[i].inuse == 0) {
Packit 857059
			for (k=ranks-i-iteration; k>i-ranks; k--) {
Packit 857059
				j = (k>=0)?k:(k+ranks);
Packit 857059
				if (i == j) {
Packit 857059
					// Can't test against yourself.
Packit 857059
					break;
Packit 857059
				} else if ((pair_list[j].inuse == 0) &&
Packit 857059
					(checked[i*ranks+j]==0)) {
Packit 857059
					pair_list[i].inuse=1;
Packit 857059
					pair_list[i].sender=i;
Packit 857059
					pair_list[i].receiver=j;
Packit 857059
					pair_list[j]=pair_list[i];
Packit 857059
					match_found=1;
Packit 857059
					checked[i*ranks+j]=iteration;
Packit 857059
					checked[j*ranks+i]=iteration;
Packit 857059
					break;
Packit 857059
				} else if ((pair_list[j].inuse != 0))
Packit 857059
					DEBUG("collision on [%d,%d] (%d)\n",
Packit 857059
							i, j, k);
Packit 857059
Packit 857059
			}
Packit 857059
			if (!match_found) {
Packit 857059
				// This will happen if
Packit 857059
				// ranks is not a power of 2.
Packit 857059
				pair_list[i].sender=-1;
Packit 857059
				pair_list[i].receiver=-1;
Packit 857059
				pair_list[i].inuse=1;
Packit 857059
				VERBOSE("%d is idle this iteration.\n", i);
Packit 857059
			} else {
Packit 857059
				pairs_found++;
Packit 857059
			}
Packit 857059
		}
Packit 857059
	}	
Packit 857059
	
Packit 857059
	return pairs_found;
Packit 857059
}
Packit 857059
Packit 857059
/*
Packit 857059
 * Taken from osu_latency and converted to a function.
Packit 857059
 */
Packit 857059
int skip = 1000;
Packit 857059
int loop = 10000;
Packit 857059
int skip_large = 10;
Packit 857059
int loop_large = 100;
Packit 857059
int large_message_size = 8192;
Packit 857059
Packit 857059
static void 
Packit 857059
find_latency(int ranks, int size, char *s_buf, char *r_buf, 
Packit 857059
			double *min_lat, double *max_lat, double *avg_lat,
Packit 857059
			int *min_rank, int *max_rank)
Packit 857059
{
Packit 857059
	int i;
Packit 857059
	MPI_Status reqstat;
Packit 857059
	MPI_Comm mpi_comm_sender;
Packit 857059
	MPI_Request request1, request2;
Packit 857059
	int partner;
Packit 857059
	double lat;
Packit 857059
	double summary_f[3];
Packit 857059
	int	   summary_i[2];
Packit 857059
	int sender_id;
Packit 857059
Packit 857059
	double t_start = 0.0, t_end = 0.0;
Packit 857059
Packit 857059
	//VERBOSE("%d @ find_latency(%d, %d, %p, %p)\n",
Packit 857059
	//		my_id, ranks, size, s_buf, r_buf);
Packit 857059
			
Packit 857059
	if (pair_list[my_id].sender == my_id) {
Packit 857059
		partner = pair_list[my_id].receiver;
Packit 857059
		//VERBOSE("%d -> %d\n", my_id, partner);
Packit 857059
	} else if (pair_list[my_id].receiver == my_id) {
Packit 857059
		partner = pair_list[my_id].sender;
Packit 857059
		//VERBOSE("%d <- %d\n", my_id, partner);
Packit 857059
	} else {
Packit 857059
		//VERBOSE("%d IDLE\n",my_id);
Packit 857059
		partner = -1;
Packit 857059
	}
Packit 857059
	
Packit 857059
	//VERBOSE("%d @ buffers loaded.\n",my_id);
Packit 857059
	
Packit 857059
	if (size > large_message_size) {
Packit 857059
		loop = loop_large;
Packit 857059
		skip = skip_large;
Packit 857059
	}
Packit 857059
	
Packit 857059
//	VERBOSE("%d @ barrier.\n", my_id);
Packit 857059
	MPI_Barrier(MPI_COMM_WORLD);
Packit 857059
	
Packit 857059
	if (pair_list[my_id].sender == my_id) {
Packit 857059
//		VERBOSE("%d @ sending.\n", my_id);
Packit 857059
		MPI_Comm_split(MPI_COMM_WORLD, 1, my_id, &mpi_comm_sender);
Packit 857059
		for (i = 0; i < loop + skip; i++) {
Packit 857059
			if (i == skip)
Packit 857059
				t_start = MPI_Wtime();
Packit 857059
			MPI_Send(s_buf, 
Packit 857059
					 size, 
Packit 857059
					 MPI_CHAR, 
Packit 857059
					 partner, 
Packit 857059
					 TAG_BASIC, 
Packit 857059
					 MPI_COMM_WORLD);
Packit 857059
			MPI_Recv(r_buf, 
Packit 857059
					 size, 
Packit 857059
					 MPI_CHAR, 
Packit 857059
					 partner, 
Packit 857059
					 TAG_BASIC, 
Packit 857059
					 MPI_COMM_WORLD,
Packit 857059
					 &reqstat);
Packit 857059
		}
Packit 857059
		t_end = MPI_Wtime();
Packit 857059
	
Packit 857059
	} else if (pair_list[my_id].receiver == my_id) {
Packit 857059
//		VERBOSE("%d @ receiving.\n", my_id);
Packit 857059
		MPI_Comm_split(MPI_COMM_WORLD, 2, my_id, &mpi_comm_sender);
Packit 857059
		for (i = 0; i < loop + skip; i++) {
Packit 857059
			MPI_Recv(r_buf, 
Packit 857059
					 size, 
Packit 857059
					 MPI_CHAR, 
Packit 857059
					 partner, 
Packit 857059
					 TAG_BASIC, 
Packit 857059
					 MPI_COMM_WORLD,
Packit 857059
					 &reqstat);
Packit 857059
			MPI_Send(s_buf, 
Packit 857059
					 size, 
Packit 857059
					 MPI_CHAR, 
Packit 857059
					 partner, 
Packit 857059
					 TAG_BASIC, 
Packit 857059
					 MPI_COMM_WORLD);
Packit 857059
		}
Packit 857059
	} else {
Packit 857059
		MPI_Comm_split(MPI_COMM_WORLD, 3, my_id, &mpi_comm_sender);
Packit 857059
	}
Packit 857059
Packit 857059
//	VERBOSE("%d @ collectives.\n", my_id);
Packit 857059
	
Packit 857059
	if (pair_list[my_id].sender == my_id) {
Packit 857059
		lat = (t_end - t_start) * 1.0e6 / (2.0 * loop);
Packit 857059
Packit 857059
		VERBOSE("t_start = %f, t_end = %f, loop = %d, lat = %f\n", t_start, t_end, loop, lat);
Packit 857059
Packit 857059
		MPI_Reduce(&lat, &summary_f[0], 1, MPI_DOUBLE, MPI_MIN, 0, mpi_comm_sender);
Packit 857059
		MPI_Reduce(&lat, &summary_f[1], 1, MPI_DOUBLE, MPI_MAX, 0, mpi_comm_sender);
Packit 857059
		MPI_Reduce(&lat, &summary_f[2], 1, MPI_DOUBLE, MPI_SUM, 0, mpi_comm_sender);
Packit 857059
		MPI_Gather(&lat, 1, MPI_DOUBLE, latency, 1, MPI_DOUBLE, 0, mpi_comm_sender); 
Packit 857059
Packit 857059
		MPI_Comm_rank(mpi_comm_sender, &sender_id);
Packit 857059
	} else {
Packit 857059
		sender_id = -1;
Packit 857059
	} 
Packit 857059
	  
Packit 857059
	MPI_Barrier(MPI_COMM_WORLD);
Packit 857059
Packit 857059
	// It is possible for the root of the senders to be different from
Packit 857059
	// the global rank 0. So, the root of the senders will send 
Packit 857059
	// a summary of the results to rank 0, even though this is usually
Packit 857059
	// redundant.
Packit 857059
	if (sender_id == 0) {
Packit 857059
		int j=0;
Packit 857059
Packit 857059
		for (i=0;i
Packit 857059
			// note that ranks in mpi_comm_sender do NOT match
Packit 857059
			// ranks in MPI_COMM_WORLD. We need to only show
Packit 857059
			// the ranks that actually send data this iteration.
Packit 857059
			if (pair_list[i].sender == i) {
Packit 857059
				if (csv) {
Packit 857059
					printf("%s, %d, %s, %d, %0.2f\n",
Packit 857059
						host_list[pair_list[i].sender].name, pair_list[i].sender,
Packit 857059
						host_list[pair_list[i].receiver].name, pair_list[i].receiver,
Packit 857059
						latency[j]);
Packit 857059
					fflush(stdout);
Packit 857059
				}	
Packit 857059
				// The following bit of jiggery-pokery is so I can identify which rank was
Packit 857059
				// slowest and which was fastest.
Packit 857059
				if (latency[j] == summary_f[0]) {
Packit 857059
					summary_i[0] = i;
Packit 857059
				}
Packit 857059
				if (latency[j] == summary_f[1]) {
Packit 857059
					summary_i[1] = i;
Packit 857059
				}
Packit 857059
Packit 857059
				j++;
Packit 857059
			//} else if (pair_list[i].sender == -1) {
Packit 857059
			//	NORMAL("%"add_quotes(MAX_HOST_LEN)"s[%d] -> idle\n", host_list[i].name, i);
Packit 857059
			}
Packit 857059
		}
Packit 857059
Packit 857059
		summary_f[2] = (j)?(summary_f[2] / j):0.0;
Packit 857059
Packit 857059
		MPI_Isend(summary_f,
Packit 857059
				  3,
Packit 857059
				  MPI_DOUBLE,
Packit 857059
				  0,
Packit 857059
				  TAG_RSLT1,
Packit 857059
				  MPI_COMM_WORLD,
Packit 857059
				  &request1);
Packit 857059
		MPI_Isend(summary_i,
Packit 857059
				  2,
Packit 857059
				  MPI_INT,
Packit 857059
				  0,
Packit 857059
				  TAG_RSLT2,
Packit 857059
				  MPI_COMM_WORLD,
Packit 857059
				  &request2);
Packit 857059
	} 
Packit 857059
Packit 857059
	if (my_id == 0) {
Packit 857059
		MPI_Recv(summary_f, 
Packit 857059
				 3, 
Packit 857059
				 MPI_DOUBLE, 
Packit 857059
				 MPI_ANY_SOURCE, 
Packit 857059
				 TAG_RSLT1, 
Packit 857059
				 MPI_COMM_WORLD,
Packit 857059
				 &reqstat);
Packit 857059
		MPI_Recv(summary_i, 
Packit 857059
				 2, 
Packit 857059
				 MPI_INT, 
Packit 857059
				 MPI_ANY_SOURCE, 
Packit 857059
				 TAG_RSLT2, 
Packit 857059
				 MPI_COMM_WORLD,
Packit 857059
				 &reqstat);
Packit 857059
Packit 857059
		*min_lat = summary_f[0];
Packit 857059
		*max_lat = summary_f[1];
Packit 857059
		*avg_lat = summary_f[2];
Packit 857059
		*min_rank = summary_i[0];
Packit 857059
		*max_rank = summary_i[1];
Packit 857059
	}
Packit 857059
Packit 857059
	MPI_Barrier(MPI_COMM_WORLD);
Packit 857059
	MPI_Comm_free(&mpi_comm_sender);
Packit 857059
Packit 857059
	//VERBOSE("%d @ done.\n", my_id);
Packit 857059
}
Packit 857059
Packit 857059
static char *short_options = "s:vt:ch";
Packit 857059
static struct option long_options[] = {
Packit 857059
	{ .name = "verbose", .has_arg = 0, .val = 'v' },
Packit 857059
	{ .name = "size", .has_arg = 0, .val = 's' },
Packit 857059
	{ .name = "time", .has_arg = 1, .val = 't' },
Packit 857059
	{ .name = "csv", . has_arg = 0, .val = 'c' },
Packit 857059
	{ .name = "help", .has_arg = 0, .val = 'h' },
Packit 857059
	{ 0 }
Packit 857059
};
Packit 857059
Packit 857059
static char *usage_text[] = {
Packit 857059
	"Verbose. Outputs some debugging information. Use multiple times for more detailed information.",
Packit 857059
	"Message Size. Should be between " add_quotes(MIN_MSG_SIZE) " and " add_quotes(MAX_MSG_SIZE),
Packit 857059
	"The duration of the test, in minutes. Defaults to "
Packit 857059
		add_quotes(DEFAULT_MINUTES) " minutes or use -1 to run forever.",
Packit 857059
	"Outputs raw data in a CSV file format, suitable for use in Excel."
Packit 857059
	"Provides this help text.",
Packit 857059
	0
Packit 857059
};
Packit 857059
Packit 857059
static void 
Packit 857059
usage() 
Packit 857059
{
Packit 857059
	int i=0;
Packit 857059
	
Packit 857059
	if (my_id == 0) {
Packit 857059
		fprintf(stderr,"\nError processing command line arguments.\n\n");
Packit 857059
		fprintf(stderr,"USAGE:\n");
Packit 857059
		while (long_options[i].name != NULL) {
Packit 857059
			fprintf(stderr, "  -%c/--%-8s %s	 %s\n",
Packit 857059
				long_options[i].val,
Packit 857059
				long_options[i].name,
Packit 857059
				(long_options[i].has_arg)?"<arg>":"		",
Packit 857059
				usage_text[i]);
Packit 857059
			i++;
Packit 857059
		}
Packit 857059
		fprintf(stderr,"\n\n");
Packit 857059
	}
Packit 857059
}
Packit 857059
Packit 857059
int
Packit 857059
main(int argc, char *argv[])
Packit 857059
{
Packit 857059
	int done = 0;
Packit 857059
	int err = 0;
Packit 857059
	int c, i;
Packit 857059
	int align_size = MESSAGE_ALIGNMENT;
Packit 857059
	time_t done_time;
Packit 857059
Packit 857059
	//int DebugWait = 1; // used to attach gdb.
Packit 857059
Packit 857059
	char *s_buf = (char*)(((unsigned long)s_buf1 + (align_size - 1)) /
Packit 857059
					align_size * align_size);
Packit 857059
Packit 857059
	char *r_buf = (char*)(((unsigned long)s_buf1 + (align_size - 1)) /
Packit 857059
					align_size * align_size);
Packit 857059
Packit 857059
	memset(r_buf1,'a',MY_BUF_SIZE);
Packit 857059
Packit 857059
	for(c=0;c<(MAX_MSG_SIZE-PATTERN_SIZE);c+=PATTERN_SIZE)
Packit 857059
		memcpy(s_buf+c,pattern,PATTERN_SIZE);
Packit 857059
Packit 857059
	int min_rank, max_rank, num_pairs;
Packit 857059
	struct partner round_fastest, round_slowest;
Packit 857059
	int found_fastest = 0;
Packit 857059
	int found_slowest = 0;
Packit 857059
	double min_lat, max_lat;
Packit 857059
	double avg_lat = 0;
Packit 857059
	double final_min = 99999999.0, final_max = 0.0;
Packit 857059
	double round_min, round_max;
Packit 857059
Packit 857059
	MPI_Init(&argc, &argv);
Packit 857059
	MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
Packit 857059
	MPI_Comm_rank(MPI_COMM_WORLD, &my_id);
Packit 857059
Packit 857059
	//if (my_id == 0) while (DebugWait); // used to attach gdb.
Packit 857059
Packit 857059
	while ( -1 != (c = getopt_long(argc, argv, short_options, long_options, NULL))) {
Packit 857059
		switch (c) {
Packit 857059
			case 'v': 
Packit 857059
				verbose += 1; 
Packit 857059
				break;
Packit 857059
Packit 857059
			case 's':
Packit 857059
				size = strtoul(optarg, NULL, 0);
Packit 857059
				if (size < MIN_MSG_SIZE || size > MAX_MSG_SIZE) {
Packit 857059
					usage();
Packit 857059
					err = -1; 
Packit 857059
					goto exit;
Packit 857059
				}
Packit 857059
				break;
Packit 857059
Packit 857059
			case 't':
Packit 857059
				minutes = strtol(optarg, NULL, 0);
Packit 857059
				if (minutes == 0 && strcmp(optarg,"0")) {
Packit 857059
					usage();
Packit 857059
					err = -1; 
Packit 857059
					goto exit;
Packit 857059
				}
Packit 857059
Packit 857059
				break;
Packit 857059
Packit 857059
			case 'c': 
Packit 857059
				csv = 1;
Packit 857059
				break;
Packit 857059
			case 'h':
Packit 857059
			default:
Packit 857059
				usage();
Packit 857059
				err = -1; 
Packit 857059
				goto exit;
Packit 857059
		}
Packit 857059
	}
Packit 857059
Packit 857059
	MPI_Barrier(MPI_COMM_WORLD);
Packit 857059
Packit 857059
	RANK0("Allocating buffers.\n");
Packit 857059
	psize = sizeof (struct partner) * num_procs;
Packit 857059
	pair_list = malloc(psize);
Packit 857059
	csize = sizeof(short) * num_procs * num_procs;
Packit 857059
	checked = malloc(csize);
Packit 857059
	latency = malloc(sizeof(double)*num_procs);
Packit 857059
	host_list = malloc(sizeof(struct host)*num_procs);
Packit 857059
	
Packit 857059
	if (!pair_list || !checked || !latency || !host_list) {
Packit 857059
		fprintf(stderr,"malloc failed.\n");
Packit 857059
		err = -1;
Packit 857059
		goto exit;
Packit 857059
	}
Packit 857059
	
Packit 857059
	// Broadcast the hostnames.
Packit 857059
	{
Packit 857059
		struct host myname;
Packit 857059
		gethostname(myname.name, MAX_HOST_LEN-1);
Packit 857059
		myname.name[MAX_HOST_LEN-1]='\0';
Packit 857059
		//VERBOSE("%d hostname: %s\n",my_id,myname.name);
Packit 857059
		memset(host_list, 0, sizeof(struct host)*num_procs);
Packit 857059
		MPI_Allgather(&myname, sizeof(myname), MPI_CHAR, host_list, sizeof(myname), MPI_CHAR, MPI_COMM_WORLD); 
Packit 857059
	}
Packit 857059
	
Packit 857059
	if (my_id == 0) {
Packit 857059
		if (minutes > 0) {
Packit 857059
			done_time = time(NULL) + minutes*60;
Packit 857059
		} else {
Packit 857059
			done_time = (time_t)-1;
Packit 857059
		}
Packit 857059
	}
Packit 857059
Packit 857059
	do {
Packit 857059
		memset(checked,0,csize);
Packit 857059
		if ((my_id == 0) && !csv) {
Packit 857059
			printf("\n\nMPI HCA Latency Stress Test\n");
Packit 857059
			printf("Msg Size:\t%d\n",size);
Packit 857059
			if (minutes > 0) {
Packit 857059
				long rt = done_time-time(NULL);
Packit 857059
				if (rt > 3600) {
Packit 857059
					printf("Time Left:\t%ld hours and %ld minutes\n",
Packit 857059
						rt/3600,
Packit 857059
						rt/60 - (rt/3600)*60);
Packit 857059
				} else if (rt > 60) {
Packit 857059
					printf("Time Left:\t%ld minutes and %ld seconds\n",rt/60,
Packit 857059
						rt - (rt/60)*60);
Packit 857059
				} else {
Packit 857059
					printf("Time Left:\t%ld seconds\n",(rt > 0)?rt:0);
Packit 857059
				}
Packit 857059
			} else {
Packit 857059
				printf("Time Left:\ttil interrupted.\n");
Packit 857059
			}
Packit 857059
		}
Packit 857059
Packit 857059
		round_max = 0.0;
Packit 857059
		round_min = 99999999.0;
Packit 857059
		num_pairs = 1;
Packit 857059
Packit 857059
		for (i=1; num_pairs > 0; i++) {
Packit 857059
			if (my_id == 0) {
Packit 857059
				// Rank 0 calculates the pairs and distributes the
Packit 857059
				// info to other nodes.
Packit 857059
				int j;
Packit 857059
Packit 857059
				for (j=0;j
Packit 857059
					latency[j]=-1.0;
Packit 857059
Packit 857059
				NORMAL("Iteration #%d\n",i);
Packit 857059
				num_pairs = calculate_pairs(i, num_procs);
Packit 857059
			
Packit 857059
				// If we found no pairs to test, time to stop.
Packit 857059
				if (num_pairs == 0) {
Packit 857059
					NORMAL("No pairs left to test.\n");
Packit 857059
					pair_list[0].inuse = -2;
Packit 857059
					if (verbose>1) dump_checked(num_procs);
Packit 857059
				} else if (verbose>2) {
Packit 857059
					dump_checked(num_procs);
Packit 857059
				}
Packit 857059
			}
Packit 857059
Packit 857059
			MPI_Bcast(pair_list, 
Packit 857059
					  psize, 
Packit 857059
					  MPI_UNSIGNED_CHAR, 
Packit 857059
					  0, 
Packit 857059
					  MPI_COMM_WORLD);
Packit 857059
Packit 857059
			// If rank 0 says there are no pairs to test, 
Packit 857059
			// then it's time to stop.
Packit 857059
			if (pair_list[0].inuse == -2) {
Packit 857059
				break;
Packit 857059
			}
Packit 857059
Packit 857059
			find_latency(num_procs, 
Packit 857059
						 size, 
Packit 857059
						 s_buf, 
Packit 857059
						 r_buf, 
Packit 857059
						 &min_lat, 
Packit 857059
						 &max_lat, 
Packit 857059
						 &avg_lat, 
Packit 857059
						 &min_rank, 
Packit 857059
						 &max_rank);	
Packit 857059
			
Packit 857059
			
Packit 857059
			if (my_id == 0 && min_lat < round_min) {
Packit 857059
				round_min = min_lat;
Packit 857059
				round_fastest = pair_list[min_rank];
Packit 857059
				found_fastest=1;
Packit 857059
				if (round_min < final_min) final_min = round_min;
Packit 857059
			}
Packit 857059
			if (my_id == 0 && max_lat > round_max) {
Packit 857059
				round_max = max_lat;
Packit 857059
				round_slowest = pair_list[max_rank]; 
Packit 857059
				found_slowest = 1;
Packit 857059
				if (round_max > final_max) final_max = round_max;
Packit 857059
			}	
Packit 857059
		}
Packit 857059
	
Packit 857059
		MPI_Barrier(MPI_COMM_WORLD);
Packit 857059
Packit 857059
		if (my_id == 0) {
Packit 857059
			if (!csv) {
Packit 857059
				printf("Avg Latency:\t%0.2f\n",avg_lat);
Packit 857059
				if(found_fastest) {
Packit 857059
					printf("Fastest Pair:\n%"add_quotes(MAX_HOST_LEN)"s -> %"add_quotes(MAX_HOST_LEN)"s\t%0.2f\n",
Packit 857059
						host_list[round_fastest.sender].name,
Packit 857059
						host_list[round_fastest.receiver].name,
Packit 857059
						round_min);
Packit 857059
				}
Packit 857059
				if(found_slowest) {
Packit 857059
					printf("Slowest Pair:\n%"add_quotes(MAX_HOST_LEN)"s -> %"add_quotes(MAX_HOST_LEN)"s\t%0.2f\n",
Packit 857059
						host_list[round_slowest.sender].name,
Packit 857059
						host_list[round_slowest.receiver].name,
Packit 857059
						round_max);
Packit 857059
				}
Packit 857059
			} 
Packit 857059
			done = (minutes > 0) && (done_time < time(NULL));
Packit 857059
		}
Packit 857059
		MPI_Bcast(&done,1,MPI_INT,0,MPI_COMM_WORLD);
Packit 857059
	} while (!done);
Packit 857059
Packit 857059
	if (my_id == 0) {
Packit 857059
		fprintf(stderr,"\n\nMPI HCA Latency Stress Test\n");
Packit 857059
		fprintf(stderr,"Msg Size:\t%d\n",size);
Packit 857059
		fprintf(stderr,"Final Min:\t%0.2f\n",final_min);
Packit 857059
		fprintf(stderr,"Final Max:\t%0.2f\n",final_max);
Packit 857059
	}
Packit 857059
Packit 857059
exit:
Packit 857059
	//VERBOSE("%d at finalize.\n",my_id);
Packit 857059
	MPI_Finalize();
Packit 857059
	return err;
Packit 857059
}