/*****************************************************************************/
/* "NetPIPE" -- Network Protocol Independent Performance Evaluator.          */
/* Copyright 1997, 1998 Iowa State University Research Foundation, Inc.      */
/*                                                                           */
/* This program is free software; you can redistribute it and/or modify      */
/* it under the terms of the GNU General Public License as published by      */
/* the Free Software Foundation.  You should have received a copy of the     */
/* GNU General Public License along with this program; if not, write to the  */
/* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.   */
/*                                                                           */
/*     * MPI.c              ---- MPI calls source                            */
/*****************************************************************************/
#include    "netpipe.h"
#include    <mpi.h>

#ifdef BSEND
char *messbuff;
#define MAXBUFSIZE (10*1024*1024)
#endif

int Setup(ArgStruct * p)
{
	int nproc;

	MPI_Comm_rank(MPI_COMM_WORLD, &p->prot.iproc);
	MPI_Comm_size(MPI_COMM_WORLD, &nproc);
	{
		char s[255];
		gethostname(s, 253);
		printf("%d: %s\n", p->prot.iproc, s);
		fflush(stdout);
	}
	p->prot.nbor = !p->prot.iproc;

	if (nproc != 2) {
		printf("Need two processes\n");
		exit(-2);
	}

	if (p->prot.iproc == 0)
		p->tr = 1;
	else
		p->tr = 0;

#ifdef BSEND
	messbuff = (char *)malloc(MAXBUFSIZE * sizeof(char));
	if (messbuff == NULL) {
		printf("Can't allocate for message buffer\n");
		exit(-1);
	}
	MPI_Buffer_attach(messbuff, MAXBUFSIZE);
#endif

}

void Sync(ArgStruct * p)
{
	MPI_Barrier(MPI_COMM_WORLD);
}

static int recvPosted = 0;
static MPI_Request recvRequest;

void PrepareToReceive(ArgStruct * p)
{
	/*
	   Providing a buffer for reception of data in advance of
	   the sender sending the data provides a major performance
	   boost on some implementations of MPI, particularly shared
	   memory implementations on the Cray T3E and Intel Paragon.
	 */
	if (recvPosted) {
		printf("Can't prepare to receive: outstanding receive!\n");
		exit(-1);
	}
	MPI_Irecv(p->buff, p->bufflen, MPI_BYTE,
		  p->prot.nbor, 1, MPI_COMM_WORLD, &recvRequest);
	recvPosted = -1;
}

void SendData(ArgStruct * p)
{
#ifdef BSEND
	MPI_Bsend(p->buff, p->bufflen, MPI_BYTE, p->prot.nbor, 1,
		  MPI_COMM_WORLD);
#else
	MPI_Send(p->buff, p->bufflen, MPI_BYTE, p->prot.nbor, 1,
		 MPI_COMM_WORLD);
#endif
}

void RecvData(ArgStruct * p)
{
	MPI_Status status;
	if (recvPosted) {
		MPI_Wait(&recvRequest, &status);
		recvPosted = 0;
	} else {
		MPI_Recv(p->buff, p->bufflen, MPI_BYTE,
			 p->prot.nbor, 1, MPI_COMM_WORLD, &status);
	}
}

void SendTime(ArgStruct * p, double *t)
{
#ifdef BSEND
	MPI_Bsend(t, 1, MPI_DOUBLE, p->prot.nbor, 2, MPI_COMM_WORLD);
#else
	MPI_Send(t, 1, MPI_DOUBLE, p->prot.nbor, 2, MPI_COMM_WORLD);
#endif
}

void RecvTime(ArgStruct * p, double *t)
{
	MPI_Status status;

	MPI_Recv(t, 1, MPI_DOUBLE, p->prot.nbor, 2, MPI_COMM_WORLD, &status);
}

void SendRepeat(ArgStruct * p, int rpt)
{
#ifdef BSEND
	MPI_Bsend(&rpt, 1, MPI_INT, p->prot.nbor, 2, MPI_COMM_WORLD);
#else
	MPI_Send(&rpt, 1, MPI_INT, p->prot.nbor, 2, MPI_COMM_WORLD);
#endif
}

void RecvRepeat(ArgStruct * p, int *rpt)
{
	MPI_Status status;

	MPI_Recv(rpt, 1, MPI_INT, p->prot.nbor, 2, MPI_COMM_WORLD, &status);
}

int Establish(ArgStruct * p)
{
}

int CleanUp(ArgStruct * p)
{
	MPI_Finalize();
}
