#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>    
#include <pvm3.h>

#ifdef UNICAST
#define SLAVENAME "uni_spsum"
#else
#define SLAVENAME "spsum"
#endif
#define PROC 10
#define NELEM 1000

int
main(int argc, char **argv)
  {
  int mytid;                   /* my task id */
  int tids[PROC];              /* slave task ids */
  int n = NELEM;               /* number of data elements */
  int nproc = PROC;            /* number of processes */
  int numt, i, who, msgtype;
  int data[NELEM];             /* data array */
  int result[PROC];            /* array of partial sums from slaves */ 
  int tot = 0;                 /* total sum of data elements */
  char fn[255];                /* array used for path name */
  FILE *fp;                    /* pointer to the input file */
  struct timeval tv1, tv2;      /* for timing */
  int dt1, dt2;                 /* time for one iter */
  int at1, at2;                 /* accum. time */          
  int low, high, send_len;

  /* override default value; must be less than PROC! */
  if (argc >1) {
    nproc = atoi(argv[1]);

    if (nproc > PROC) {
      printf("Too many slaves requested, using only %d\n", PROC);
      nproc = PROC;
    }
  }

  /* Enroll In PVM */
  mytid = pvm_mytid();

  /* Start Slave Tasks */
  numt = 0;

  switch(nproc) {
  case 10:
    numt = pvm_spawn(SLAVENAME, (char**)0, 0, "", nproc, tids);
    break;
  case 6:
    numt += pvm_spawn(SLAVENAME, (char**)0, PvmTaskArch, "SGIMP64", 2, tids+4);
  case 4:
    numt += pvm_spawn(SLAVENAME, (char**)0, PvmTaskArch, "ALPHAMP", 2, tids+2);
  case 2:
    numt += pvm_spawn(SLAVENAME, (char**)0, PvmTaskArch, "SGI6", 2, tids);
    break;
  default:
    printf("Requested number of slaves not implemented\n");
  }
    
  if (numt < nproc)
    {
    printf("Trouble spawning slaves. Aborting. Error codes are: \n");
    for (i=numt; i<nproc; i++)
      printf("TID %d %d\n", i, tids[i]);
    for (i=0; i<numt; i++)
      pvm_kill(tids[i]);
    pvm_exit();
    exit(1);
    }

  /* Get Proper Path For Input File */
  strcpy(fn,getenv("HOME"));
  strcat(fn,"/pvm3/src/rand_data.txt");

  /* Open Input File and Initialize Data */
  if ((fp = fopen(fn,"r")) == NULL)
    {
    printf("Can't open the input file: %s\n\n", fn);
    exit(1);
    }
  for (i=0; i<n; i++)
    fscanf(fp,"%d", &data[i]);

 gettimeofday (&tv1, (struct timezone *) 0); /* start of send */


#ifdef UNICAST
  printf("Using unicast send\n");
  for (i=0; i<nproc; i++) {
    low = i *((n/nproc)+1);
    high = low +((n/nproc)+1);
    if (high > n) {
      high = n;
    }
    send_len = high-low;

    pvm_initsend(PvmDataDefault);
    pvm_pkint(&i, 1, 1);
    pvm_pkint(&send_len, 1, 1);
    pvm_pkint(data+low, send_len, 1);
    pvm_send(tids[i], 0);
  }
#else
  /* Broadcast Initial Data To Slaves */
  printf("Using multicast send\n");
  pvm_initsend(PvmDataDefault);
  pvm_pkint(&nproc, 1, 1);
  pvm_pkint(tids, nproc, 1);
  pvm_pkint(&n, 1, 1);
  pvm_pkint(data, n, 1);
  pvm_mcast(tids, nproc, 0);
#endif
  

/* Wait For Results From The Slaves */
  msgtype = 5;
  for (i=0; i<nproc; i++)
    {
    pvm_recv(-1, msgtype);
    pvm_upkint(&who, 1, 1);
    pvm_upkint(&result[who], 1, 1);
    printf("I got %d from %d\n", result[who], who);
    }

 gettimeofday (&tv2, (struct timezone *) 0);
    dt1 = (tv2.tv_sec - tv1.tv_sec) * 1000000
      + tv2.tv_usec - tv1.tv_usec;
    printf ("#Data values: %2d Elapsed Time %8d uSec\n", n, dt1);   

  /* Compute The Global Sum */
  for (i=0; i<nproc; i++)
    tot += result[i];
  printf ("Sum: %d.\n\n", tot);

  /* Program Finished. Exit PVM */
  pvm_exit();
  return(0);
  }





