/************************************************************************/
/* file: pgtracelib.c                                                   */
/*                                                                      */
/* @(#)tracing library PGPVM Version 2 (June 1996)\                     */
/* @(#)PGPVM V2 (June 1996)\                                            */
/*                                                                      */
/************************************************************************/

#ifdef MAN
NAME
	pgtracelib - Augmented versions of the pvm library to produce tracefiles

SYNOPSIS of PGPVM V2:
        void pg_startadmin(char *outfile,char *host,int nbt_admin_max)
        char *outfile     outfile name, default is pgfile.<uid>
        char *host        host name
	int nbt_admin_max maximal number of tasks
        this function spawns pg_administrator.

	int pg_tids(char* option)
    	char* option	Y or y if the task wants to participate in the tracing.
			N or n if the task doesn t want to participate in
                        the tracing.
        pg_tids returns PvmOk if OK, < 0 otherwise.

        void pg_close(void)
        the tracing is suspended.

	All the other routines maintain the pvm_ calling sequence.
        Those available are:
        int pg_spawn(char *file,char **argv,int flags,char *where,int count,int *tids)
        int pg_exit()
        int pg_recv(int tid,int msgtag)
        int pg_nrecv(int tid,int msgtag)
        int pg_trecv(int tid,int msgtag,struct timeval *tmout)
        int pg_mcast (int *ttids,int ntid,int msgtag)
        int pg_send (int tid,int msgtag)
        int pg_psend (int tid,int msgtag, void *buf, int nitems, int dtype)
        int pg_precv(int tid,int msgtag,void *buf, int nitems,int dtype,int *rtid,int *rtag,int *rcnt)
	These routines return the same error codes as their
	corresponding pvm_ routines.

DESCRIPTION of PGPVM V2:
    pgtracelib augments the pvm system by having nodes produce tracefiles
    for use with ParaGraph. pgtracelib is based upon previous work done
    by Anders Alund.
	
        The major revisions made by Brad Topol for the first version
        are as follows:
    
    *runs with standard ParaGraph; No modifications are required
	 to ParaGraph source code

    *clocking: timestamps are done as offsets from when pg_tids is
	 called.  Hence, timestamps, now implicitly start from zero
	 Clock synchronization is now done by a new postprocessor,
	 clocksync.  clocksync follows Lamport s methods of combining
	 logical and physical clocks to synchronize clocks and preserve
	 causality

    *filtering: messages sent to or from tids not in the tids
	 array of the pg_administrator are not assumed to be from the
         host but are filtered out and not traced
	 
    *buffering: all nodes buffer writes with 10k buffers to minimize
	 perturbation

    *concatenation of files:  after all processes in the tids array
	 of the pg_administrator call pvm_exit, the trace files are
         concatenated and stored in /tmp on the host machine where
         the pg_administrator has been spawned, in the file pgfile.<uid>
		
    *a shell script is provided, PGSORT which performs all 
	 postprocessing/sorting and produce a <filename>.trf for use 
	 with standard ParaGraph

    *updated to support pvm3.3.3 communication routines

    Brad Topol / Georgia Institute of Technology	
	Revisions done while employed at Emory University, Summer 1994.

	The major revisions made by Stephane Bizard, Stephan Dalhem and
        Sebastien Veigneau for the second version are as follows:

    *clocking: timestamps are done as offsets from when pg_administrator is
	created. The reference starting time is now a global one.
	The tasks don t have to call pgtids() at the same time, this allows
	the user to spawn tasks as many times as he wants.

    *pg_tids(): A task that wishes to participate in the tracing does not need
	to know the tids of any other traced task. This allows the user not to
	know how many tasks his program will spawn.

    *outfile name: the functions pg_outfile() and pg_chprefix() have been removed
	from the library. It is still possible to choose the name of the output file
	by calling pg_startadmin(char *outfile,char *host,int nbt_admin_max).

IMPLEMENTATION
	Straight forward.
	Using PGPVM2 requires only three minor modifications to a PVM application:
	1==> First the application must include a new header file, pgpvm2.h.
	     This should go directly under the standard pvm3.h header file.
	2==> All tasks must call pg_tids(char *option).
	3==> The first spawned task must call
             pg_startadmin(char *outfile, char *host, int nbt_admin_max).

SEE ALSO
	PVM 3.3 users manual
AUTHORS
    Brad Topol / Georgia Institute of Technology	
	Revisions done while employed at Emory University, Summer 1994.

    Stephane Bizard, Stephan Dalhem, Sebastien Veigneau
        University of Marne-la-Vallee, France, june 1996.

#endif

/************************************************************************/
/* Include files */

#include <stdio.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "pvm3.h"
/************************************************************************/
/* useful Macros */

#define T_BYTE (sizeof(char))
#define T_CPLX (2*sizeof(float))
#define T_DCPLX (2*sizeof(double))
#define T_DOUBLE (sizeof(double))
#define T_FLOAT (sizeof(float))
#define T_INT (sizeof(int))
#define T_LONG (sizeof(long))
#define T_SHORT (sizeof(short))
#define TRACEBUFSIZ 1400


#define ADMINTAG  0x22cb173a
#define TRACETAG 0x22cb173b
#define ENDPROG 0x22cb173c
#define NEWTASKSNB 0x22cb173d
#define ADMINTID 0x22cb173d


/************************************************************************/
/* Static variables */

static int me=-1;

static int mytid=0;		/* My tid				*/
static int *tids=NULL;		/* Tids for all processes to monitor	*/
static int np=0;		/* Number of processes			*/
static FILE *logfile=stderr;	/* Log file name			*/
static struct timeval t0;	/* Reference timestamp			*/
static struct timeval tt;	/* Temp time variable			*/
static struct timeval tt1;	/* Temp time variable			*/
static struct timezone *tz=NULL;/* Temp timezone variable		*/
static struct timeval st0;	/* Time when last initsend was called	*/
static int registered=0;	/* Set once pg_tids is called		*/
static int adminstarted=0;
static int barriertotal=0;	/* count early bird barrier msgs */
static int barrierflag=1;       /* default to using barriers */
static char logname[256];
static char *outfilenm=NULL;    /*optional filename */
static char *prefixfilenm=NULL; /*optional prefix filename */
static int called_exit=0;       /*if pg_exit is called then called_exit=1 */
static unsigned long dif_sec;
static long dif_usec;


static int admintid;
static int first_time=1;
static int Iamnew=1;
static int Iamason=1;

static int *tablabel;
static int taille=0;

#ifdef __STDC__
void pg_veriflab(void);
#else
void pg_veriflab();
#endif


/**********************************************************************/
#ifdef __STDC__
void timestamp(struct timeval* t)
#else
void timestamp(t)
struct timeval *t;
#endif
{
struct timeval tx;
double m1, m2;

  gettimeofday(&tx,tz);
  if (tx.tv_usec >= t0.tv_usec) 
   {
       if ((tx.tv_usec-t0.tv_usec) >= dif_usec)
	   {
	       t->tv_usec = (tx.tv_usec-t0.tv_usec)-dif_usec;
	       t->tv_sec = (tx.tv_sec-t0.tv_sec)-dif_sec;
	   }
       else
	   {
	       /* borrow a second */
	       t->tv_usec = ((tx.tv_usec-t0.tv_usec)+1000000)-dif_usec;
	       t->tv_sec = ((tx.tv_sec-t0.tv_sec)-1)-dif_sec;
	   }
   }
  else 
   {
     /* borrow a second */
       if (((tx.tv_usec+1000000)-t0.tv_usec) >= dif_usec)
	   {
	       t->tv_usec = ((tx.tv_usec+1000000)-t0.tv_usec)-dif_usec;
	       t->tv_sec = ((tx.tv_sec-1)-t0.tv_sec)-dif_sec;
	   }
       else
	   {
	       /*borrow a second */
	       t->tv_usec = (((tx.tv_usec+1000000)-t0.tv_usec)+1000000)-dif_usec;
	       t->tv_sec = (((tx.tv_sec-1)-t0.tv_sec)-1)-dif_sec;
	   }
   }
}

/************************************************************************/
#ifdef __STDC__
static int datasize(int dtype)
#else
static int datasize(dtype)
int dtype;
#endif
{

switch(dtype) 
    {
    case PVM_STR:
	return(T_BYTE);
    case PVM_BYTE:
	return(T_BYTE);
    case PVM_USHORT:
    case PVM_SHORT:
	return(T_SHORT);
    case PVM_UINT:
    case PVM_INT:
	return(T_INT);
    case PVM_ULONG:
    case PVM_LONG:
	return(T_LONG);
    case PVM_FLOAT:
	return(T_FLOAT);
    case PVM_DOUBLE:
	return(T_DOUBLE);
    case PVM_CPLX:
	return(T_CPLX);
    case PVM_DCPLX:
	return(T_DCPLX);
    }
  return -1;
}

/**********************************************************************/
#ifdef __STDC__
void pg_startadmin(char *outfile,char *host,int nbt_admin_max)
#else
void pg_startadmin(outfile,host,nbt_admin_max)
char *outfile;
char *host;
int nbt_admin_max;
#endif

{
    int numt;
    
    if (adminstarted)
	{
	    fprintf(stderr,"pg_startadmin already started");
	    return;
	}
    adminstarted=1;
    if (!strcmp(host, "") || !strcmp(host, "*")) {
      host = NULL;
      numt=pvm_spawn("pg_administrator", (char **)0, PvmTaskDefault, host, 1, &admintid );
    }
    else {
      numt=pvm_spawn("pg_administrator", (char **)0, 1, host, 1, &admintid );
    }
    Iamason=0;
    
    if (numt<1)
	{
	    fprintf(stderr,"error: pg_administrator not spawned !!!");
	    return;
	}


    pvm_initsend(PvmDataDefault);
    /* For Fortran ! */
    if (!strcmp(outfile, "*"))
        strcpy(outfile, "");

    pvm_pkstr(outfile);
    pvm_pkint(&nbt_admin_max,1,1);
    pvm_send(admintid,ADMINTID);
    

}

/**********************************************************************/
#ifdef __STDC__
int pg_spawn(char *file,char **argv,int flags,char *where,int count,int *tids)
#else
int pg_spawn(file,argv,flags,where,count,tids)
char *file; 
char **argv;
int flags;
char *where; 
int count; 
int *tids;
#endif

{
    int numt,info;
    numt=pvm_spawn(file, argv, flags, where, count, tids);
    if (numt < 0) return (numt); /* can't create task */
    pvm_initsend(PvmDataDefault);
    pvm_pkint(&numt, 1, 1);
    pvm_pkint(tids, numt, 1);
    pvm_send(admintid, NEWTASKSNB);
    pvm_initsend(PvmDataDefault);
    pvm_pkint(&admintid, 1, 1);
    info=pvm_mcast(tids, numt, ADMINTID);
    if (info < 0)
	fprintf(stderr,"pg_spawn error: pvm_cast error: %d \n",info);
    return(numt);
}


/************************************************************************/
#ifdef __STDC__
int pg_tids(char * option)
#else
int pg_tids(option)
char *option;
#endif

{
    struct timeval t1;
    char hostname[100];
    FILE *fd;
    
    if ( (*option=='N') || (*option=='n') )
	{
	    if (Iamnew==0)
		{
		    fprintf(stderr,"Error: pg_tids already called !!\n");
		    return(-1);
		}
	    if (Iamason)
		{
		    pvm_recv(-1,ADMINTID);
		    pvm_upkint(&admintid,1,1);
		}
	    Iamnew=0;
	}
    else if ( (*option=='Y') || (*option=='y') )
	{
	    if (first_time)
		{
		    if (Iamnew)
			{ 
			    if (Iamason)
				{

				    pvm_recv(-1,ADMINTID);   
				    pvm_upkint(&admintid,1,1);
				}
			}
		    mytid=pvm_mytid();
		    if (mytid < 0)
			{
			    fprintf(stderr,"Error in pg_tids: Can't contact local daemon\n");
			    exit(-1);
			}
		    pvm_initsend(PvmDataDefault);
		    pvm_send(admintid,ADMINTAG);

		    pvm_recv(admintid,ADMINTAG);
		    gettimeofday(&tt,tz); /* local starting time */
		    pvm_upklong(&t0.tv_sec,1,1); /* global reference time */
		    pvm_upklong(&t0.tv_usec,1,1); 
		    pvm_upklong(&t1.tv_sec,1,1); /* global starting time */
		    pvm_upklong(&t1.tv_usec,1,1);
		    dif_sec=tt.tv_sec-t1.tv_sec;
		    dif_usec=tt.tv_usec-t1.tv_usec; 
		    first_time=0;
		    
		    gethostname(hostname,sizeof(hostname));
		    
		    if (prefixfilenm) 
			sprintf(logname, "/tmp/%s.pgfile.%d.%s.%d",prefixfilenm,getuid(),hostname,getpid());
		    else
			sprintf(logname, "/tmp/pgfile.%d.%s.%d",getuid(),hostname,getpid());
		    
		    fd = fopen (logname,  "w+");
		    if (fd!=0)
			{
			    logfile=fd;
			    setvbuf(logfile, NULL, _IOFBF, 10240);
			}
		    else 
			fprintf(stderr,"pg_tids: unable to open logfile\n");
		    
		    registered=1;
		    timestamp(&tt);
/* PG: trace_start */
		    fprintf (logfile, "1 %d %d %d 0 0 0\n",tt.tv_sec,tt.tv_usec,mytid);
		    printf("pg_tids: initialization completed  \n");
		    Iamnew=0;
		}
	    
	    else
		{
		    if (registered) 
			{
			    fprintf(stderr,"Error: Task %d called pg_tids(\"y\") two times \n",pvm_mytid());
			    return (-3);
			}   
		    fd = fopen (logname,  "w+");
		    if (fd!=0)
			{
			    logfile=fd;
			    setvbuf(logfile, NULL, _IOFBF, 10240);
			}
		    
		    else 
			fprintf(stderr, "pg_tids: unable to reopen logfile\n");
		    
		    registered=1;
		}
	}
    else
	{
	    fprintf(stderr,"Error: Task %d called pg_tids with a wrong argument\n",pvm_mytid());
	    return (-2);
	}
    return PvmOk;
}
    
/**********************************************************************/
#ifdef __STDC__
int pg_exit(void)
#else
int pg_exit()
#endif
{
    int f1,n,info,ntask,j;
    char buf[TRACEBUFSIZ];

    struct pvmtaskinfo ** taskp;
    int msg=1;
    if (called_exit==1) return 0; /* if pg_exit already called */
    called_exit=1;
    
    if(registered) 
	{
	    pg_veriflab();
	    timestamp(&tt);

	    fprintf (logfile, "19 %d %d %d 0\n", tt.tv_sec, tt.tv_usec, mytid);
  	    fclose(logfile);
	    
	    if ((f1 = open(logname,O_RDONLY,0)) == -1) 	
		fprintf(stderr,"pg_exit: can't reopen tracefile\n");
	    else 
		{
		    unlink(logname);
		    pvm_initsend(PvmDataDefault);
		    pvm_pkint(&msg,1,1);
		    pvm_send(admintid, TRACETAG);
		    while ((n = read(f1, buf, TRACEBUFSIZ)) > 0) 
			{
			    pvm_initsend(PvmDataDefault);
			    pvm_pkint(&n, 1, 1);
			    pvm_pkbyte(buf, n, 1);
			    pvm_send(admintid, TRACETAG);
			} 
		    n= -1;
		    pvm_initsend(PvmDataDefault);
		    pvm_pkint(&n, 1, 1);
		    pvm_send(admintid, TRACETAG);
		    close(f1);
		}

	    fprintf(stderr,"pg_exit: calling pvm_exit\n");
	}

    else if (first_time)
	{
	    pg_veriflab();
	    timestamp(&tt);
	    sprintf(buf,"19 %d %d %d 0\n", tt.tv_sec, tt.tv_usec, mytid);
	    pvm_initsend(PvmDataDefault);
	    pvm_pkint(&msg,1,1);
	    pvm_send(admintid, TRACETAG);
	    n=strlen(buf);
	    pvm_initsend(PvmDataDefault);
	    pvm_pkint(&n, 1, 1);
	    pvm_pkbyte(buf, n, 1);
	    pvm_send(admintid, TRACETAG);
	    n= -1;
	    pvm_initsend(PvmDataDefault);
	    pvm_pkint(&n, 1, 1);
	    pvm_send(admintid, TRACETAG);
	}
    else
	{
	    pvm_initsend(PvmDataDefault);
	    pvm_send(admintid, ENDPROG);
	}
		
    return pvm_exit();
}

/************************************************************************/
#ifdef __STDC__
void pg_close(void)
#else
void pg_close()
#endif

{
    int f1,n;
    char buf[TRACEBUFSIZ];
    int msg=0;
    
    if (called_exit) return;

    if(registered) 
	{
	    timestamp(&tt);
	    fprintf (logfile, "19 %d %d %d 0\n", tt.tv_sec, tt.tv_usec, mytid);

	    fclose(logfile);
	    
	    if ((f1 = open(logname,O_RDONLY,0)) == -1) 
		fprintf(stderr,"pg_exit: can't reopen tracefile\n");
	    else 
		{
		    unlink(logname);
		    pvm_initsend(PvmDataDefault);
		    pvm_pkint(&msg,1,1);
		    pvm_send(admintid, TRACETAG);
		    while ((n = read(f1, buf, TRACEBUFSIZ)) > 0) 
			{
			    pvm_initsend(PvmDataDefault);
			    pvm_pkint(&n, 1, 1);
			    pvm_pkbyte(buf, n, 1);
			    pvm_send(admintid, TRACETAG);
			} 
		    n= -1;
		    pvm_initsend(PvmDataDefault);
		    pvm_pkint(&n, 1, 1);
		    pvm_send(admintid, TRACETAG);
		    close(f1);
		}
	    fprintf(stderr, "pg_close: closing\n");
	}
    registered = 0;
}

/**********************************************************************/
#ifdef __STDC__
int pg_recv(int tid,int msgtag)
#else
int pg_recv(tid,msgtag)
int tid;
int msgtag;
#endif

{
    int info,bufinfo;
    int nb, rid, tag, bufid, who;

    if(registered) 
	{
	    timestamp(&tt);
	}
    info = bufid = pvm_recv(tid, msgtag);
    if(bufid>0) 
	{
	    if(registered) 
		{
		    timestamp(&tt1);
		    bufinfo=pvm_bufinfo(bufid, &nb, &tag, &rid);
		    if (bufinfo == 0)
			{
			    /**/
			    /* PG: recv_blocking */
			    /**/
			    fprintf (logfile, "7 %d %d %d %d\n", 
				     tt.tv_sec, tt.tv_usec, mytid, msgtag);
			    /**/
			    /* PG: recv_waking */
			    /**/
			    fprintf (logfile, "8 %d %d %d %d %d %d\n",
				     tt1.tv_sec, tt1.tv_usec, mytid, rid, tag, nb);
			}
		    else fprintf(stderr,"pg_recv Error: bufinfo error\n");
		}
	}
  return (info);
}

/************************************************************************/
#ifdef __STDC__
int pg_nrecv(int tid,int msgtag)
#else
int pg_nrecv(tid, msgtag)
int tid;
int msgtag;
#endif

{
    int info,bufinfo;
    int nb, rid, tag, bufid, who;
    if(registered) 
	{
    timestamp(&tt);
	}
    info = bufid = pvm_nrecv(tid, msgtag);
    if(bufid>0) 
	{
	    if(registered) 
		{
		    timestamp(&tt1);
		    bufinfo=pvm_bufinfo(bufid, &nb, &tag, &rid);
		    if (bufinfo==0) 
			{
			    /**/
			    /* PG: recv_blocking */
			    /**/
			    fprintf (logfile, "7 %d %d %d %d\n", 
				     tt.tv_sec, tt.tv_usec, mytid, msgtag);
			    /**/
			    /* PG: recv_waking */
			    /**/
			    fprintf (logfile, "8 %d %d %d %d %d %d\n",
				     tt1.tv_sec, tt1.tv_usec, mytid, rid, tag, nb);
			}
		    else fprintf(stderr,"pg_nrecv Error: bufinfo error\n");
		}
	}
    return info;
}

/************************************************************************/
#ifdef __STDC__
int pg_trecv(int tid,int msgtag,struct timeval *tmout)
#else
int pg_trecv(tid,msgtag, tmout)
int tid; 
int msgtag; 
struct timeval *tmout;
#endif

{
    int info,bufinfo;
    int nb, rid, tag, bufid, who;
    timestamp(&tt);
    info = bufid = pvm_trecv(tid, msgtag, tmout);
    if(bufid>0) 
	{
	    if(registered) 
		{
		    timestamp(&tt1);
		    bufinfo=pvm_bufinfo(bufid, &nb, &tag, &rid);

		    if (bufinfo == 0) 
			{
			    /**/
			    /* PG: recv_blocking */
			    /**/
			    fprintf (logfile, "7 %d %d %d %d\n", 
				     tt.tv_sec, tt.tv_usec, mytid, msgtag);
			    /**/
			    /* PG: recv_waking */
			    /**/
			    fprintf (logfile, "8 %d %d %d %d %d %d\n",
				     tt1.tv_sec, tt1.tv_usec, mytid, rid, tag, nb);
			}
		    else fprintf(stderr,"pg_trecv Error: bufinfo error\n");
		}
	}
    return info;
}

/************************************************************************/
#ifdef __STDC__
int pg_mcast (int *ttids,int ntid,int msgtag)
#else
int pg_mcast (ttids, ntid, msgtag)
int *ttids; 
int ntid; 
int msgtag;
#endif

{
    int i, info, bufid, nb, idum, who,found_one=0;
    int bufinfo;
/**/
    if(registered) 
	{
	    timestamp(&tt);
	}
    info = pvm_mcast(ttids, ntid, msgtag);
    if(registered) 
	{
	    bufid=pvm_getsbuf();
	    (void)pvm_bufinfo(bufid, &nb, &idum, &idum);
	    for (i=0;i<ntid;i++) 
		{
		    /**/
		    /* PG: send */
		    /**/
		    fprintf (logfile, "4 %d %d %d %d %d %d\n",
			     tt.tv_sec, tt.tv_usec, mytid, ttids[i], msgtag, nb);
		}
	    /**/
	    /* PG: computation_stat */
	    /**/
	    fprintf (logfile, "11 %d %d %d %d %d\n",
		     tt.tv_sec, tt.tv_usec, mytid, 0, 0);
	    timestamp(&tt);
	    fprintf (logfile, "11 %d %d %d %d %d\n",
		     tt.tv_sec, tt.tv_usec, mytid, 0, 0);
	}
    return info;
}

/************************************************************************/
#ifdef __STDC__
int pg_send (int tid,int msgtag)
#else
int pg_send (tid,msgtag)
int tid; 
int msgtag;
#endif

{
    int info, who, bufid, nb, idum1, idum2;
/**/

    if(registered)
	{
	    timestamp(&tt);
	    if (tt.tv_usec < 0) fprintf(stderr,"problem in pg_send\n"); 
	}
    info = pvm_send(tid, msgtag);
    if(registered) 
	{
	    bufid=pvm_getsbuf();
	    (void)pvm_bufinfo(bufid, &nb, &idum1, &idum2);
	    /**/
	    /* PG: send */
	    /**/
	    fprintf (logfile, "4 %d %d %d %d %d %d\n",
		     tt.tv_sec, tt.tv_usec, mytid, tid, msgtag, nb);
	    /**/
	    /* PG: computation_stat */
	    /**/
	    fprintf (logfile, "11 %d %d %d %d %d\n",
		     tt.tv_sec, tt.tv_usec, mytid, 0, 0);
	    timestamp(&tt);
	    fprintf (logfile, "11 %d %d %d %d %d\n",
		     tt.tv_sec, tt.tv_usec, mytid, 0, 0);
	}
/**/
    return info;
}

/************************************************************************/
#ifdef __STDC__
int pg_psend (int tid,int msgtag,void *buf, int nitems, int dtype)
#else
int pg_psend (tid,msgtag,buf,nitems,dtype)
int tid; 
int msgtag; 
void* buf;
int nitems; 
int dtype; 
#endif

{
    int info, who;
    int nb = datasize(dtype)*nitems;
/**/
    if(registered) 
	{
	    timestamp(&tt);
	}
    info = pvm_psend(tid, msgtag, buf, nitems ,dtype);
    if(registered)
	{
	    /**/
	    /* PG: send */
	    /**/
	    fprintf (logfile, "4 %d %d %d %d %d %d\n",
		     tt.tv_sec, tt.tv_usec, mytid, tid, msgtag, nb);
	    /**/
	    /* PG: computation_stat */
	    /**/
	    fprintf (logfile, "11 %d %d %d %d %d\n",
		     tt.tv_sec, tt.tv_usec, mytid, 0, 0);
	    timestamp(&tt);
	    fprintf (logfile, "11 %d %d %d %d %d\n",
		     tt.tv_sec, tt.tv_usec, mytid, 0, 0);
	}
/**/
    return info;
}

/************************************************************************/
#ifdef __STDC__
int pg_precv(int tid,int msgtag,void *buf, int nitems,int dtype,int *rtid,int *rtag,int *rcnt)
#else
int pg_precv(tid,msgtag,buf,nitems,dtype,rtid,rtag,rcnt)
int tid; 
int msgtag; 
void* buf;
int nitems; 
int dtype; 
int *rtid; 
int *rtag; 
int *rcnt; 
#endif

{
    int info, nb, who;
    if(registered) 
	{
	    timestamp(&tt);
	}
    info = pvm_precv(tid, msgtag, buf, nitems, dtype, rtid, rtag, rcnt);
    if(registered) 
	{
	    
	    nb = (datasize(dtype))*(*rcnt);
	    
	    /**/
	    /* PG: recv_blocking */
	    /**/
	    fprintf (logfile, "7 %d %d %d %d\n",
		     tt.tv_sec, tt.tv_usec, mytid, msgtag);
	    timestamp(&tt1);
	    /**/
	    /* PG: recv_waking */
	    /**/
	    fprintf (logfile, "8 %d %d %d %d %d %d\n",
		     tt1.tv_sec, tt1.tv_usec, mytid, tid, *rtag, nb);
	    
	}
/**/
    return info;
}

/************************************************************************/
#ifdef __STDC__
int pg_beglab(int label)
#else
int pg_beglab(label)
int label;
#endif

{
struct timeval tt;

if (taille == 0)
    {
	taille=1024;
	tablabel=(int*)calloc(taille,sizeof(int));
    }
    if (registered)
    {
	if (tablabel[label]==1)
	    {
		fprintf(stderr,"pgpvm Warning: pg_beglab(%d) already called\n",label);
		return (1);
	    }
	tablabel[label]=1;

	timestamp(&tt);
	fprintf (logfile, "23 %d %d %d %d -1 0\n",
		 tt.tv_sec, tt.tv_usec, mytid, label);
    }
return PvmOk;    /* N.B : PvmOk=0*/
}

/************************************************************************/
#ifdef __STDC__
int pg_endlab(int label)
#else
int pg_endlab(label)
int label;
#endif

{
struct timeval tt;

if (registered)
    {
	if (tablabel[label]==0)
	    {
		fprintf(stderr,"pgpvm Warning: pg_endlab(%d) already called\n",label);
		return (1);
	    }
	tablabel[label]=0;

	timestamp(&tt);

	fprintf (logfile, "24 %d %d %d %d -1 0\n",
		 tt.tv_sec, tt.tv_usec, mytid, label);
    }
return PvmOk;
}

/************************************************************************/
#ifdef __STDC__
void pg_veriflab(void)
#else
void pg_veriflab()
#endif
{
    int i;

    for(i=0;i<taille;i++)
	if (tablabel[i]==1)
	    {
		timestamp(&tt);
		fprintf (logfile, "-4 %d %d %d %d -1 0\n",
			 i, tt.tv_sec, tt.tv_usec, mytid );
	    }
    
}

/**********************************************************************/

/*  BT left in for compatibility purposes */
#ifdef __STDC__
int pg_mytid(void)
#else
int pg_mytid()
#endif
{
        int t;
/**/
        mytid=pvm_mytid();
/**/
        return mytid;
}

/*  BT left in for compatibility purposes */
#ifdef __STDC__
int  pg_initsend(int type)
#else
int  pg_initsend(type)
int type;
#endif
{
        timestamp(&st0);
        return pvm_initsend(type);
}



/************************************************************************/
/*									*/
/*			 FORTRAN INTERFACES				*/
/*									*/
/************************************************************************/
#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfmytid (tid)
#else
void
pgfmytid_ (tid)
#endif
    int *tid;
{
	*tid = pg_mytid();
}
/************************************************************************/
#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfstartadmin(outfile, host, nbt_admin_max)
#else
void
pgfstartadmin_(outfile, host, nbt_admin_max)
#endif
    char *outfile;
    char *host;
    int *nbt_admin_max;
{
	pg_startadmin(outfile, host, *nbt_admin_max);
}
/************************************************************************/
#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgftids (opt, info)
#else
void
pgftids_ (opt, info)
#endif
   char *opt;
   int *info; 
{
	*info = pg_tids(opt);
}
/************************************************************************/
#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfbeglab (label, info)
#else
void
pgfbeglab_ (label, info)
#endif
   int *label;
   int *info; 
{
	*info = pg_beglab(*label);
}

/************************************************************************/
#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfendlab (label, info)
#else
void
pgfendlab_ (label, info)
#endif
   int *label;
   int *info; 
{
	*info = pg_endlab(*label);
}

#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfveriflab ()
#else
void
pgfveriflab_ ()
#endif
{
	pg_veriflab();
}




/************************************************************************/
#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfexit (info)
#else
void
pgfexit_ (info)
#endif
    int *info;
{
	*info = pg_exit();
}


#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfclose (info)
#else
void
pgfclose_ (info)
#endif
    int *info;
{
	pg_close();
}
/************************************************************************/
#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfrecv (tid, msgtag, info)
#else
void
pgfrecv_ (tid, msgtag, info)
#endif
    int *tid, *msgtag, *info;
{
	*info = pg_recv(*tid, *msgtag);
}
/************************************************************************/
#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfnrecv (tid, msgtag, info)
#else
void
pgfnrecv_ (tid, msgtag, info)
#endif
    int *tid, *msgtag, *info;
{
	*info = pg_nrecv(*tid, *msgtag);
}
/************************************************************************/
/************************************************************************/
#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgftrecv (tid, msgtag, sec, usec, info)
#else
void
pgftrecv_ (tid, msgtag, sec, usec, info)
#endif
    int *tid, *msgtag, *sec, *usec, *info;
{
    struct timeval temp;
	temp.tv_sec = *sec;
	temp.tv_usec = *usec;
	*info = pg_trecv(*tid, *msgtag, &temp);
}
/************************************************************************/
#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfmcast (ntid, ttids, msgtag, info)
#else
void
pgfmcast_ (ntid, ttids, msgtag, info)
#endif
    int *ntid, *ttids, *msgtag, *info;
{
	*info = pg_mcast(ttids, *ntid, *msgtag);
}
/************************************************************************/
#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfsend (tid, msgtag, info)
#else
void
pgfsend_ (tid, msgtag, info)
#endif
    int *tid, *msgtag, *info;
{
	*info = pg_send(*tid, *msgtag);
}
/************************************************************************/
#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfinitsend (type, info)
#else
void
pgfinitsend_ (type, info)
#endif
    int *type, *info;
{
	*info = pg_initsend(*type);
}
/************************************************************************/
#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfpsend(tid, msgtag,  buf, nitems, dtype,  info)
#else
void
pgfpsend_(tid, msgtag, buf, nitems, dtype, info)
#endif
    int* tid;
    int* msgtag;
    void* buf;
    int* nitems;
    int* dtype;
    int* info;
{
	*info = pg_psend(*tid, *msgtag, buf, *nitems, *dtype);
}
/************************************************************************/
#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfprecv(tid, msgtag, buf, nitems, dtype, rtid, rtag, rcnt, info)
#else
void
pgfprecv_(tid, msgtag, buf, nitems, dtype, rtid, rtag, rcnt, info)
#endif
    int* tid;
    int* msgtag;
    void* buf;
    int* nitems;
    int* dtype;
    int* rtid;
    int* rtag;
    int* rcnt;
    int* info;
{
   *info =  pg_precv(*tid, *msgtag, buf, *nitems, *dtype, rtid, rtag, rcnt);
}
/************************************************************************/


#if(defined(IMA_HPPA) || defined(IMA_RS6K))
void
pgfspawn (aout_ptr, flag, where_ptr, count, tids, info)
#else
void 
pgfspawn_ (aout_ptr, flag, where_ptr, count, tids, info)
#endif
char * aout_ptr; 
char * where_ptr; 
	int *flag, *count, *tids, *info;
{

	/*
	 * if the where parameter is '*', pass a NULL pointer to
	 * initiate which will allow execution on any machine.
	 */
	if (*(where_ptr) == '*') {
		*info = pg_spawn(aout_ptr, (char**)0, *flag, "", *count, tids);

	} else {
		*info = pg_spawn(aout_ptr, (char**)0, *flag, where_ptr, *count, tids);
	}
}


