/* s malymi upravami Februar 2000 */
/*
*	timing.c
*
*	Does a few communication timing tests on pvm.
*	Uses `timing_slave' to echo messages.
* ----------------------------------------------------------------------------
*     If this test is run over machines with differnet data formats
*     Then change 'ENCODING' to PvmDataDefault in timing and timing_slave
* ----------------------------------------------------------------------------
*
*	9 Dec 1991  Manchek
*  14 Oct 1992  Geist  - revision to pvm3
*   6 Mar 1994  Geist  - synch tasks and add direct route
*/

#ifdef HASSTDLIB
#include <stdlib.h>
#endif
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <math.h>
#include "pvm3.h"


//#define MXPKT 1000000
#define MXPKT 100000

#define ENCODING  PvmDataRaw
//#define ENCODING  PvmDataDefault

#define ROUTING PvmRouteDirect
//#define ROUTING PvmDontRoute

//#define VERBOSE

#define SLAVENAME "timing_slave"

main(argc, argv)
	int argc;
	char **argv;
{
	int mytid;                  /* my task id */
	int stid = 0;				/* slave task id */
	int reps = 20;				/* number of samples per test */
	struct timeval tv1, tv2;	/* for timing */
	int dt1, dt2;				/* time for one iter */
	int at1, at2;				/* accum. time */
	int numint;					/* message length */
	int n;
	int i;
	int *iarray = 0;

	/* enroll in pvm */

	if ((mytid = pvm_mytid()) < 0) {
		exit(1);
	}
	printf("i'm t%x\n", mytid);

	/* start up slave task */

	if (pvm_spawn(SLAVENAME, (char**)0, 0, "", 1, &stid) < 0 || stid < 0) {
		fputs("can't initiate slave\n", stderr);
		goto bail;
	}

    /* Wait for slave task to start up */
    pvm_setopt(PvmRoute, ROUTING);
    pvm_recv( stid, 0 );
	printf("slave is task t%x\n", stid);

	/*
	*  round-trip timing test
	*/

#ifdef VERBOSE
	puts("Doing Round Trip test, minimal message size\n");
#endif
	at1 = 0;

	/* pack buffer */

	pvm_initsend(ENCODING);
	pvm_pkint(&stid, 1, 1);

#ifdef VERBOSE
	puts(" N     uSec");
#endif
	for (n = 1; n <= reps; n++) {
		gettimeofday(&tv1, (struct timezone*)0);

		if (pvm_send(stid, 1)) {
			fprintf(stderr, "can't send to \"%s\"\n", SLAVENAME);
			goto bail;
		}

		if (pvm_recv(-1, -1) < 0) {
			fprintf(stderr, "recv error%d\n" );
			goto bail;
		}

		gettimeofday(&tv2, (struct timezone*)0);

		dt1 = (tv2.tv_sec - tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec;
#ifdef VERBOSE
		printf("%2d %8d\n", n, dt1);
#endif
		at1 += dt1;
	}
	printf("RTT Avg uSec %d\n", at1 / reps);

	/*
	*  bandwidth test for different message lengths
	*/

#ifdef VERBOSE
	puts("\nDoing Bandwidth tests\n");
#endif

	for (numint = 25; numint < MXPKT; numint *= 10) {
		printf("\nMessage size %d\n", numint * 4);
		at1 = at2 = 0;
		iarray = (int*)malloc(numint * sizeof(int));
#ifdef VERBOSE
		puts(" N  Pack uSec  Send uSec");
#endif
		for (n = 1; n <= reps; n++) {
			gettimeofday(&tv1, (struct timezone*)0);

			pvm_initsend(ENCODING);
			pvm_pkint(iarray, numint, 1);

			gettimeofday(&tv2, (struct timezone*)0);
			dt1 = (tv2.tv_sec - tv1.tv_sec) * 1000000
				+ tv2.tv_usec - tv1.tv_usec;

			gettimeofday(&tv1, (struct timezone*)0);

			if (pvm_send(stid, 1)) {
				fprintf(stderr, "can't send to \"%s\"\n", SLAVENAME);
				goto bail;
			}

			if (pvm_recv(-1, -1) < 0) {
				fprintf(stderr, "recv error%d\n" );
				goto bail;
			}

			gettimeofday(&tv2, (struct timezone*)0);
			dt2 = (tv2.tv_sec - tv1.tv_sec) * 1000000
				+ tv2.tv_usec - tv1.tv_usec;
#ifdef VERBOSE
			printf("%2d   %8d   %8d\n", n, dt1, dt2);
#endif
			at1 += dt1;
			at2 += dt2;
		}

		if (!(at1 /= reps))
			at1 = 1;
		if (!(at2 /= reps))
			at2 = 1;
#ifdef VERBOSE
		puts("Avg uSec");
		printf("     %8d   %8d\n", at1, at2);
		puts("Avg Byte/uSec");
#endif
		printf("     %8f   %8f\n",
			(numint * 4) / (double)at1,
			(numint * 4) / (double)at2);
	}

	/* we have to do this because the last message might be taking
	*  up all the shared memory pages.
	*/
	pvm_freebuf(pvm_getsbuf());

	puts("\ndone");

bail:
	if (stid > 0)
		pvm_kill(stid);
	pvm_exit();
	exit(1);
}


