/****   Copyright (c) 2001-2003 Alexandros V. Gerbessiotis
 ****
 ****   Permission to use, copy, modify, and distribute this software,
 ****   and to incorporate it, in whole or in part, into other software,
 ****   is hereby granted without fee, provided that
 ****     (1) the above copyright notice and this permission notice appear in
 ****         all copies of the source code, and the above copyright notice
 ****         appear in clearly visible form on all supporting documentation
 ****         and distribution media, and
 ****     (2) any redistribution of the software, in original
 ****         or modified form, be without fee and subject to
 ****         these same conditions.
 ****   No guarantee is offered that the code works as
 ****   advertised or is absent of any, even damaging,
 ****   side-effects; use this code on your own personal risk
 ****/

#include "aimisc.h"

double __my_estimate_l = (double) 500;
double __my_estimate_g = (double) 0.5;
int    __my_estimate_nprocs = (int) 1;
int    __my_first_call=(int) 0;
int    __my_estimate_brd=(int) BRD_CUTOFF;
int    __my_estimate_ppf=(int) PPF_CUTOFF;

void check_if_null(void *x,char *s,char *t)
{
  if (NULL == x) {
     printf("%s:: Null pointer error (%s)\n",s,t);
     AIABORT("check_if_null");
  }
}

void __my_estimate_bsp_values()
{
        __my_estimate_l = AIL();
        __my_estimate_g = AIG();
        __my_estimate_nprocs = AINPROCS();
        __my_estimate_brd = BRD_CUTOFF;
        __my_estimate_ppf = PPF_CUTOFF;
}

/* One superstep broadcasting to communicate command line args */
void bspbroad(int fromp, char *from, char *to, int size)
{
 int pid;
 int nprocs;
 int i;

 pid=AIPID(); /* processor id */
 nprocs=AINPROCS(); /* number of processors */
 AIREGISTER(to,size);
 AIINIT();
 AICOMMIT();
 for (i = 0; i < nprocs;i++) {
   if (pid==fromp)
        AIHPPUT(i,from,to,0,size);
 }
 AISYNC();
 AIBARRIER();
 AIDEREGISTER((void*)to);
}

/* operators for bspfold */

void foldmax(double *z, double *x, double *y)
{
  *z=(((*x)>=(*y))?(*x):(*y));
}

void foldmin(double *z, double *x, double *y)
{
  *z=(((*x)<(*y))?(*x):(*y));
}



/* One superstep folding operation to compute global min/max of timing data */
void 
  bspfold(void (*oper)(void *,void*,void*),char *from,char *to,int size)
{
 int  pid; 
 int  nprocs; 
 int  i;
 char *list;
 int  lsize;

 pid=AIPID(); 
 nprocs=AINPROCS(); 
 if (1==nprocs)  /* if local, copy */
    memcpy(to,from,size*sizeof(char));
 else {    /* if global, allocate memory O(p) per processor */
    lsize = nprocs*size; 
    list=(char *) malloc(lsize*sizeof(char));
    check_if_null(list,"bspfold","list");
    AIREGISTER(list,lsize);
    AIINIT();
    AICOMMIT();
 }
 /* each proc sends its from to every other proc; results stored in list */
 for (i = 0; i < nprocs;i++) {  
   AIHPPUT(i,from,list,pid*size,size);
 }
 AISYNC();
 AIBARRIER();
 /* apply operator to local list */
 for (i = 0; i < nprocs-1;i++) {
  oper(to,(list+i*size),(list+(i+1)*size));
  memcpy((list+(i+1)*size),to,size);
 }
    /* free memory and deregister */
 
    AIDEREGISTER(list);
    free((void *)list);
}
