/*****************************
 * e2m test where m=all
 ****************************/
#include <stdlib.h>
#include "../common.h"

#define NUMMCAST 200
#define MAXIMPL 4
#define MAXSIZE 100
#define NUMPES  CmiNumPes()

CpvDeclare(int, MtestHandle);
CpvDeclare(int, RecvmsgHandle);
CpvDeclare(int, AllDoneHandle);
CpvDeclare(int, impl);
CpvDeclare(int, maxsize);
CpvDeclare(double, StartTime);

void DistribIds(int ity)
{
  	Msg *m=(Msg *)CmiAlloc(sizeof(Msg));
  	comID id=ComlibInstance(ity, NUMPES);
  	m->id=id;
	CmiSetHandler(m, CpvAccess(MtestHandle));
  	CmiSyncBroadcastAllAndFree(sizeof(Msg), m);
}

void all_done(Msg *m1)
{
  static int ad=0;
  double totaltime;

  if (CmiMyPe()) CsdExitScheduler();
  ad++;
  if (ad==NUMPES) {
  	totaltime=CmiWallTimer()-CpvAccess(StartTime);
  	//CmiPrintf("%d Msgsize = %d Time = %f\n",CpvAccess(impl), (sizeof(Msg)+CpvAccess(maxsize)*sizeof(int)), totaltime/NUMMCAST); 
  	CmiPrintf("%f\t",totaltime/NUMMCAST); 
	CpvAccess(impl)++;
	if (CpvAccess(impl) >MAXIMPL) {
		CmiPrintf("\n");
	CmiSetHandler(m1, CpvAccess(AllDoneHandle));
  	CmiSyncBroadcastAll(sizeof(Msg), m1);
		CsdExitScheduler();
	}
     	else {
        	ad=0;
		DistribIds(CpvAccess(impl));
        }		
  }
}

void recv_msg(Msg *m)
{
  static int mc=0;
  mc++; 
  comID id=m->id;

  //CmiPrintf("%d id.Impltype=%d\n",CmiMyPe(), id.ImplType);

  if (mc == NUMMCAST*(NUMPES-CmiMyPe())) {
  	Msg *m1=(Msg *)CmiAlloc(sizeof(Msg));
	CmiSetHandler(m1, CpvAccess(AllDoneHandle));
     	CmiSyncSendAndFree(0, sizeof(Msg), m1);
	mc=0;
  }
}

void Mtest(Msg *m)
{
  int i;
  if (CmiMyPe() >= NUMPES) {
  	CsdExitScheduler();
	return;
  }
  int *t=(int *)CmiAlloc(CmiNumPes()*sizeof(int));
  Msg *m1;

  for(i=0;i<(CmiNumPes());i++) t[i]=i;

  CpvAccess(StartTime)=CmiWallTimer();
  int msgsize=sizeof(Msg)+CpvAccess(maxsize)*sizeof(int);

  if (CmiMyPe()==0 && CpvAccess(impl)==0) CmiPrintf("%d\t",msgsize);
  for (i=0;i<NUMMCAST;i++) {
    NumDeposits(m->id, (CmiMyPe()+1));
    for (int j=0;j<CmiMyPe()+1;j++) {
  	m1=(Msg *)CmiAlloc(msgsize);
  	m1->id=m->id;
  	CmiSetHandler(m1, CpvAccess(RecvmsgHandle));
  	EachToManyMulticast(m1->id, msgsize, m1, 1, &(t[j]));
    }
  }
  CmiFree(t);
}


void Btest(int argc, char **argv)
{
  CpvInitialize(int, impl);
  CpvInitialize(int, maxsize);
  CpvInitialize(int, MtestHandle);
  CpvInitialize(int, RecvmsgHandle);
  CpvInitialize(int, AllDoneHandle);
  CpvInitialize(double, StartTime);

  CpvAccess(impl)=atoi(argv[1]);
  CpvAccess(maxsize)=atoi(argv[2]);

  CpvAccess(MtestHandle)=CmiRegisterHandler((CmiHandler)Mtest);
  CpvAccess(RecvmsgHandle)=CmiRegisterHandler((CmiHandler)recv_msg);
  CpvAccess(AllDoneHandle)=CmiRegisterHandler((CmiHandler)all_done);
  CpvAccess(StartTime)=CmiWallTimer();

  ComlibInit();

  if (CmiMyPe()==0) {
  	DistribIds(CpvAccess(impl));
  }
}



main(int argc, char ** argv)
{
  ConverseInit(argc, argv, Btest, 0,0);
}
