📄 pair.c
字号:
#include <stdio.h>
#include "mpi.h"
#include "mpptest.h"
#include "getopts.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if defined(HAVE_SHMALLOC) && !defined(HAVE_MPI_ALLOC_MEM)
#include <mpp/shmem.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
/*****************************************************************************
Each collection of test routines contains:
Initialization function (returns pointer to context to pass back to test
functions
Routine to change "distance"
Routine to return test function (and set parameters) based on command-line
arguments
Routine to output "help" text
*****************************************************************************/
/*****************************************************************************
Here begin the test functions. These all have the same format:
double NAME(reps, len, ctx)
Input Parameters:
. reps - number of times to perform operation
. len - length of message (in bytes)
. ctx - Pointer to structure containing ranks of participating processes
Return value:
Elapsed time for operation (not Elapsed time/reps), in seconds.
These are organized as:
head-to-head (each process sends to the other). The blocking version
can deadlock on systems with small amounts of buffering.
round-trip (a single message is sent back and fourth between two nodes)
In order to test both single and multiple senders and receivers, the
destination (partner) node is also set, and whether the node is a master or
a slave (it may also be a bystander)
*****************************************************************************/
#include "mpptest.h"
#if VARIABLE_TAG
#define MSG_TAG(iter) iter
#else
#define MSG_TAG(iter) 1
#endif
struct _PairData {
int proc1, proc2;
int source, destination, /* Source and destination. May be the
same as partner (for pair) or different
(for ring) */
partner; /* = source = destination if same */
int is_master, is_slave;
};
static int CacheSize = 1048576;
void PairChange( int, PairData);
void ConfirmTest( int, int, PairData );
PairData PairInit( int proc1, int proc2 )
{
PairData new;
new = (PairData)malloc(sizeof(struct _PairData));
if (!new)return 0;;
PairChange( 1, new );
return new;
}
void PairChange( int distance, PairData ctx )
{
int proc2;
if (__MYPROCID == 0) {
proc2 = GetNeighbor( 0, distance, 1 );
}
else {
proc2 = GetNeighbor( __MYPROCID, distance, 0 );
if (proc2 == 0) {
/* Then I'm the slave for the root */
proc2 = __MYPROCID;
}
else {
proc2 = NO_NBR;
}
}
ctx->proc1 = 0;
ctx->proc2 = proc2;
ctx->is_master = __MYPROCID == ctx->proc1;
ctx->is_slave = __MYPROCID == proc2;
if (ctx->is_master) {
ctx->partner = proc2;
ctx->destination = proc2;
ctx->source = proc2;
}
else if (ctx->is_slave) {
ctx->partner = ctx->proc1;
ctx->destination = ctx->proc1;
ctx->source = ctx->proc1;
}
else {
ctx->partner = NO_NBR;
ctx->source = NO_NBR;
ctx->destination = NO_NBR;
}
}
/* Bisection test can be done by involving all processes in the
communication.
In order to insure that we generate a valid pattern, I create an array
with an entry for each processor. Starting from position zero, I mark
masters, slaves, and ununsed. Each new entry is marked as a master,
with the destination partner marked as a slave.
*/
PairData BisectInit( int distance )
{
PairData new;
new = (PairData)malloc(sizeof(struct _PairData));
if (!new)return 0;;
BisectChange( distance, new );
return new;
}
void BisectChange( int distance, PairData ctx )
{
int i, np;
int *marks, curpos;
int partner;
np = __NUMNODES;
marks = (int *)malloc((unsigned)(np * sizeof(int) ));
if (!marks) MPI_Abort( MPI_COMM_WORLD, 1 );
for (i=0; i<np; i++) {
marks[i] = NO_NBR;
}
curpos = 0;
while (curpos < np) {
partner = GetNeighbor( curpos, distance, 1 );
if (marks[curpos] == NO_NBR && marks[partner] == NO_NBR) {
marks[curpos] = 1;
marks[partner] = 2;
}
curpos++;
}
ctx->proc1 = NO_NBR;
ctx->proc2 = NO_NBR;
ctx->is_master = marks[__MYPROCID] == 1;
ctx->is_slave = marks[__MYPROCID] == 2;
if (ctx->is_master) {
ctx->partner = GetNeighbor( __MYPROCID, distance, 1 );
ctx->destination = ctx->partner;
ctx->source = ctx->partner;
}
else if (ctx->is_slave) {
ctx->partner = GetNeighbor( __MYPROCID, distance, 0 );
ctx->destination = ctx->partner;
ctx->source = ctx->partner;
}
else {
ctx->partner = NO_NBR;
ctx->destination = NO_NBR;
ctx->source = NO_NBR;
}
free(marks);
}
/* Print information on the ctx */
void PrintPairInfo( PairData ctx )
{
MPE_Seq_begin(MPI_COMM_WORLD,1 );
fprintf( stdout, "[%d] sending to %d, %s\n", __MYPROCID, ctx->partner,
(ctx->is_master || ctx->is_slave) ?
( ctx->is_master ? "Master" : "Slave" ) : "Bystander" );
fflush( stdout );
MPE_Seq_end(MPI_COMM_WORLD,1 );
}
typedef enum { HEADtoHEAD, ROUNDTRIP } CommType;
typedef enum { Blocking, NonBlocking, ReadyReceiver, MPISynchronous,
Persistant, Vector, VectorType, Put, Get }
Protocol;
typedef enum { SpecifiedSource, AnySource } SourceType;
static SourceType source_type = AnySource;
static int MsgPending = 0;
double exchange_forcetype( int, int, PairData );
double exchange_async( int, int, PairData );
double exchange_sync( int, int, PairData );
double exchange_ssend( int, int, PairData );
double round_trip_sync( int, int, PairData );
double round_trip_force( int, int, PairData );
double round_trip_async( int, int, PairData );
double round_trip_ssend( int, int, PairData );
double round_trip_persis( int, int, PairData );
double round_trip_vector( int, int, PairData );
double round_trip_vectortype( int, int, PairData );
double round_trip_nc_sync( int, int, PairData );
double round_trip_nc_force( int, int, PairData );
double round_trip_nc_async( int, int, PairData );
#if ! defined(HAVE_MPI_PUT)
#define round_trip_put 0
#define round_trip_nc_put 0
#define exchange_put 0
#else
double exchange_put( int, int, PairData );
double round_trip_put( int, int, PairData );
double round_trip_nc_put( int, int, PairData );
#endif
#if ! defined(HAVE_MPI_GET)
#define round_trip_get 0
#define round_trip_nc_get 0
#define exchange_get 0
#else
double exchange_get( int, int, PairData );
double round_trip_get( int, int, PairData );
double round_trip_nc_get( int, int, PairData );
#endif
static void SetupTest( int );
static void FinishTest( void );
/* Determine the timing function */
double ((*GetPairFunction( int *argc, char *argv[], char *protocol_name )) ( int, int, void * ))
{
CommType comm_type = ROUNDTRIP;
Protocol protocol = Blocking;
double (*f)(int,int,PairData);
int use_cache;
f = round_trip_sync;
if (SYArgHasName( argc, argv, 1, "-force" )) {
protocol = ReadyReceiver;
strcpy( protocol_name, "ready receiver" );
}
if (SYArgHasName( argc, argv, 1, "-async" )) {
protocol = NonBlocking;
strcpy( protocol_name, "nonblocking" );
}
if (SYArgHasName( argc, argv, 1, "-sync" )) {
protocol = Blocking;
strcpy( protocol_name, "blocking" );
}
if (SYArgHasName( argc, argv, 1, "-ssend" )) {
protocol = MPISynchronous;
strcpy( protocol_name, "Ssend" );
}
if (SYArgHasName( argc, argv, 1, "-put" )) {
protocol = Put;
strcpy( protocol_name, "MPI_Put" );
}
if (SYArgHasName( argc, argv, 1, "-get" )) {
protocol = Get;
strcpy( protocol_name, "MPI_Get" );
}
if (SYArgHasName( argc, argv, 1, "-persistant" )) {
protocol = Persistant;
strcpy( protocol_name, "persistant" );
}
if (SYArgHasName( argc, argv, 1, "-vector" )) {
int stride;
protocol = Vector;
strcpy( protocol_name, "vector" );
if (SYArgGetInt( argc, argv, 1, "-vstride", &stride ))
set_vector_stride( stride );
}
if (SYArgHasName( argc, argv, 1, "-vectortype" )) {
int stride;
protocol = VectorType;
strcpy( protocol_name, "type_vector" );
if (SYArgGetInt( argc, argv, 1, "-vstride", &stride ))
set_vector_stride( stride );
}
if (SYArgHasName( argc, argv, 1, "-anysource" )) {
source_type = AnySource;
}
if (SYArgHasName( argc, argv, 1, "-specified" )) {
source_type = SpecifiedSource;
strcat( protocol_name, "(specified source)" );
}
if (SYArgHasName( argc, argv, 1, "-pending" )) {
MsgPending = 1;
strcat( protocol_name, "(pending recvs)" );
}
use_cache = SYArgGetInt( argc, argv, 1, "-cachesize", &CacheSize );
if (SYArgHasName( argc, argv, 1, "-head" )) comm_type = HEADtoHEAD;
if (SYArgHasName( argc, argv, 1, "-roundtrip" )) comm_type = ROUNDTRIP;
if (comm_type == ROUNDTRIP) {
if (use_cache) {
switch( protocol ) {
case ReadyReceiver: f = round_trip_nc_force; break;
case NonBlocking: f = round_trip_nc_async; break;
case Blocking: f = round_trip_nc_sync; break;
case Put: f = round_trip_nc_put; break;
case Get: f = round_trip_nc_get; break;
/* Rolling through the cache means using different buffers
for each op; not doable with persistent requests */
case Persistant: f = 0; break;
case Vector: f = 0; break;
case VectorType: f = 0; break;
default: f = 0; break;
}
}
else {
switch( protocol ) {
case ReadyReceiver: f = round_trip_force; break;
case NonBlocking: f = round_trip_async; break;
case Blocking: f = round_trip_sync; break;
case MPISynchronous:f = round_trip_ssend; break;
case Put: f = round_trip_put; break;
case Get: f = round_trip_get; break;
case Persistant: f = round_trip_persis; break;
case Vector: f = round_trip_vector; break;
case VectorType: f = round_trip_vectortype; break;
}
}
}
else {
switch( protocol ) {
case ReadyReceiver: f = exchange_forcetype; break;
case NonBlocking: f = exchange_async; break;
case Blocking: f = exchange_sync; break;
case MPISynchronous:f = exchange_ssend; break;
case Put: f = exchange_put; break;
case Get: f = exchange_get; break;
case Persistant: f = 0; break;
case Vector: f = 0; break;
case VectorType: f = 0; break;
}
}
if (!f) {
fprintf( stderr, "Option %s not supported\n", protocol_name );
MPI_Abort( MPI_COMM_WORLD, 1 );
}
return (double (*)(int,int,void*)) f;
}
/*****************************************************************************
Here are the actual routines
*****************************************************************************/
/*
Blocking exchange (head-to-head)
*/
double exchange_sync( int reps, int len, PairData ctx)
{
double elapsed_time;
int i, to = ctx->destination, from = ctx->source;
int recv_from;
char *sbuffer, *rbuffer;
double t0, t1;
MPI_Status status;
sbuffer = (char *)malloc(len);
rbuffer = (char *)malloc(len);
memset( sbuffer, 0, len );
memset( rbuffer, 0, len );
SetupTest( from );
ConfirmTest( reps, len, ctx );
elapsed_time = 0;
if(ctx->is_master){
recv_from = MPI_ANY_SOURCE;
if (source_type == SpecifiedSource) recv_from = to;
MPI_Recv(rbuffer,len,MPI_BYTE,recv_from,0,MPI_COMM_WORLD,&status);
t0=MPI_Wtime();
for(i=0;i<reps;i++){
MPI_Send(sbuffer,len,MPI_BYTE,to,MSG_TAG(i),MPI_COMM_WORLD);
MPI_Recv(rbuffer,len,MPI_BYTE,recv_from,MSG_TAG(i),
MPI_COMM_WORLD,&status);
}
t1 = MPI_Wtime();
elapsed_time = t1-t0;
}
if(ctx->is_slave){
recv_from = MPI_ANY_SOURCE;
if (source_type == SpecifiedSource) recv_from = to;
MPI_Send(sbuffer,len,MPI_BYTE,from,0,MPI_COMM_WORLD);
for(i=0;i<reps;i++){
MPI_Send(sbuffer,len,MPI_BYTE,to,MSG_TAG(i),MPI_COMM_WORLD);
MPI_Recv(rbuffer,len,MPI_BYTE,recv_from,MSG_TAG(i),
MPI_COMM_WORLD,&status);
}
}
FinishTest();
free(sbuffer);
free(rbuffer);
return(elapsed_time);
}
/*
Nonblocking exchange (head-to-head)
*/
double exchange_async( int reps, int len, PairData ctx)
{
double elapsed_time;
int i, to = ctx->destination, from = ctx->source;
int recv_from;
MPI_Request msg_id;
char *sbuffer,*rbuffer;
double t0, t1;
MPI_Status status;
sbuffer = (char *)malloc(len);
rbuffer = (char *)malloc(len);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -