more multiple int i.
[charm.git] / src / ck-ldb / TopoLB.C
1 /**************************************************************************
2 TopoLB: 
3 This is a topology-aware load balancer.
4  * First groups the objects into $p$ groups.
5  * places object-groups onto processors one-by-one
6  * Next object group to be placed is the one that gains maximum if placed now. It is placed at the processor that minimizes hop-bytes for it.
7  
8 Author: Tarun Agarwal (tarun)
9 Date: 04/19/2005
10 ***************************************************************************/
11 #include <math.h>
12 #include <stdlib.h>
13 #include "charm++.h"
14 #include "cklists.h"
15 #include "CentralLB.h"
16
17 #include "TopoLB.decl.h"
18
19 #include "TopoLB.h"
20
21 #define alpha PER_MESSAGE_SEND_OVERHEAD_DEFAULT  /*Startup time per message, seconds*/
22 #define beta PER_BYTE_SEND_OVERHEAD_DEFAULT     /*Long-message time per byte, seconds*/
23 #define DEG_THRES 0.50
24 #define EPSILON  -0.001
25
26 #define _lb_debug_on 0
27 #define _lb_debug2_on 1
28 #define _make_new_grouping_ 0
29
30 CreateLBFunc_Def(TopoLB,"TopoLB: Balance objects based on the network topology");
31
32
33 TopoLB::TopoLB(const CkLBOptions &opt) : CentralLB (opt)
34 {
35   lbname = "TopoLB";
36   if (CkMyPe () == 0) {
37     CkPrintf ("[%d] TopoLB created\n",CkMyPe());
38   }
39 }
40
41 CmiBool TopoLB::QueryBalanceNow (int _step)
42 {
43   return CmiTrue;
44 }
45
46 void TopoLB::freeDataStructures(int count)
47 {
48   for(int i=0;i<count;i++)
49   {
50     delete[] hopBytes[i];
51     delete[] dist[i];
52     delete[] comm[i];
53   }
54   delete[] comm;
55   delete[] hopBytes;
56   delete[] dist;
57   delete[] pfree;
58   delete[] cfree;
59   delete[] commUA;
60   delete[] assign;
61 }
62
63 void TopoLB::allocateDataStructures(int count )
64 {
65   int i;
66   //Allocating in separate loop to have somewhat contiguous memory allocation
67   hopBytes=new double*[count];
68   for(i=0;i<count;i++)
69   {
70     hopBytes[i]=new double[count+2];
71   }
72
73   dist=new double*[count];
74   for(i=0;i<count;i++)
75   {
76     dist[i]=new double[count+1];
77   }
78
79   comm=new double*[count];
80   for(i=0;i<count;i++)
81   {
82     comm[i]=new double[count];
83   }
84
85   commUA=new double[count];
86   pfree=new bool[count];
87   cfree=new bool[count];
88   assign=new int[count];
89 }
90
91
92 void TopoLB::computePartitions(CentralLB::LDStats *stats,int count,int *newmap)
93 {
94   int numobjs = stats->n_objs;
95         int i, j, m;
96
97   // allocate space for the computing data
98   double *objtime = new double[numobjs];
99   int *objwt = new int[numobjs];
100   int *origmap = new int[numobjs];
101   LDObjHandle *handles = new LDObjHandle[numobjs];
102   
103         for(i=0;i<numobjs;i++) {
104     objtime[i] = 0.0;
105     objwt[i] = 0;
106     origmap[i] = 0;
107   }
108
109   for (i=0; i<stats->n_objs; i++) {
110     LDObjData &odata = stats->objData[i];
111     if (!odata.migratable) 
112       CmiAbort("MetisLB doesnot dupport nonmigratable object.\n");
113     int frompe = stats->from_proc[i];
114     origmap[i] = frompe;
115     objtime[i] = odata.wallTime*stats->procs[frompe].pe_speed;
116     handles[i] = odata.handle;
117   }
118
119   // to convert the weights on vertices to integers
120   double max_objtime = objtime[0];
121   for(i=0; i<numobjs; i++) {
122     if(max_objtime < objtime[i])
123       max_objtime = objtime[i];
124   }
125         int maxobj=0;
126         int totalwt=0;
127   double ratio = 1000.0/max_objtime;
128   for(i=0; i<numobjs; i++) {
129       objwt[i] = (int)(objtime[i]*ratio);
130                         if(maxobj<objwt[i])
131                                 maxobj=objwt[i];
132                         totalwt+=objwt[i];
133   }
134         
135         //CkPrintf("\nmax obj wt :%d \n totalwt before :%d \n\n",maxobj,totalwt);
136         
137   int **comm = new int*[numobjs];
138   for (i=0; i<numobjs; i++) {
139     comm[i] = new int[numobjs];
140     for (j=0; j<numobjs; j++)  {
141       comm[i][j] = 0;
142     }
143   }
144
145   const int csz = stats->n_comm;
146   for(i=0; i<csz; i++) {
147       LDCommData &cdata = stats->commData[i];
148       //if(cdata.from_proc() || cdata.receiver.get_type() != LD_OBJ_MSG)
149         //continue;
150                         if(!cdata.from_proc() && cdata.receiver.get_type() == LD_OBJ_MSG){
151         int senderID = stats->getHash(cdata.sender);
152         int recverID = stats->getHash(cdata.receiver.get_destObj());
153         CmiAssert(senderID < numobjs);
154         CmiAssert(recverID < numobjs);
155         //comm[senderID][recverID] += (int)(cdata.messages*alpha + cdata.bytes*beta);
156         //comm[recverID][senderID] += (int)(cdata.messages*alpha + cdata.bytes*beta);
157                 //CkPrintf("in compute partitions...%d\n",comm[senderID][recverID]);
158                                 comm[senderID][recverID] += cdata.messages;
159         comm[recverID][senderID] += cdata.messages;
160
161                                 //Use bytes or messages -- do i include messages for objlist too...??
162                         }
163                         else if (cdata.receiver.get_type() == LD_OBJLIST_MSG) {
164                                 //CkPrintf("in objlist..\n");
165         int nobjs;
166         LDObjKey *objs = cdata.receiver.get_destObjs(nobjs);
167         int senderID = stats->getHash(cdata.sender);
168         for (j=0; j<nobjs; j++) {
169            int recverID = stats->getHash(objs[j]);
170            if((senderID == -1)||(recverID == -1))
171               if (_lb_args.migObjOnly()) continue;
172               else CkAbort("Error in search\n");
173            comm[senderID][recverID] += cdata.messages;
174            comm[recverID][senderID] += cdata.messages;
175         }
176                         }
177                 }
178
179 // ignore messages sent from an object to itself
180   for (i=0; i<numobjs; i++)
181     comm[i][i] = 0;
182
183   // construct the graph in CSR format
184   int *xadj = new int[numobjs+1];
185   int numedges = 0;
186   for(i=0;i<numobjs;i++) {
187     for(j=0;j<numobjs;j++) {
188       if(comm[i][j] != 0)
189         numedges++;
190     }
191   }
192   int *adjncy = new int[numedges];
193   int *edgewt = new int[numedges];
194         int factor = 10;
195   xadj[0] = 0;
196   int count4all = 0;
197   for (i=0; i<numobjs; i++) {
198     for (j=0; j<numobjs; j++) { 
199       if (comm[i][j] != 0) { 
200         adjncy[count4all] = j;
201         edgewt[count4all++] = comm[i][j]/factor;
202       }
203     }
204     xadj[i+1] = count4all;
205   }
206
207   /*if (_lb_args.debug() >= 2) {
208   CkPrintf("Pre-LDB Statistics step %d\n", step());
209   printStats(count, numobjs, objtime, comm, origmap);
210   }*/
211
212   int wgtflag = 3; // Weights both on vertices and edges
213   int numflag = 0; // C Style numbering
214   int options[5];
215   int edgecut;
216   int sameMapFlag = 1;
217
218         options[0] = 0;
219
220   if (count < 1) {
221     CkPrintf("error: Number of Pe less than 1!");
222   }
223   else if (count == 1) {
224         for(m=0;m<numobjs;m++) 
225                         newmap[i] = origmap[i];
226         sameMapFlag = 1;
227   }
228   else {
229         sameMapFlag = 0;
230                 /*
231         if (count > 8)
232                         METIS_PartGraphKway(&numobjs, xadj, adjncy, objwt, edgewt, 
233                             &wgtflag, &numflag, &count, options, 
234                             &edgecut, newmap);
235           else
236                         METIS_PartGraphRecursive(&numobjs, xadj, adjncy, objwt, edgewt, 
237                                  &wgtflag, &numflag, &count, options, 
238                                  &edgecut, newmap);
239                 */
240    //CkPrintf("before calling metis.\n");
241                 METIS_PartGraphRecursive(&numobjs, xadj, adjncy, objwt, edgewt,
242                                  &wgtflag, &numflag, &count, options,
243                                  &edgecut, newmap);
244          //CkPrintf("after calling Metis function.\n");
245   }
246          
247   /*if (_lb_args.debug() >= 2) {
248         CkPrintf("Post-LDB Statistics step %d\n", step());
249         printStats(count, numobjs, objtime, comm, newmap);
250   }*/
251
252   for(i=0;i<numobjs;i++)
253     delete[] comm[i];
254   delete[] comm;
255   delete[] objtime;
256   delete[] xadj;
257   delete[] adjncy;
258   delete[] objwt;
259   delete[] edgewt;
260
261         //CkPrintf("chking wts on each partition...\n");
262
263         /*int avg=0;
264         int *chkwt = new int[count];
265         for(i=0;i<count;i++)
266                 chkwt[i]=0;
267         //totalwt=0;
268         for(i=0;i<numobjs;i++){
269                 chkwt[newmap[i]] += objwt[i];
270                 avg += objwt[i];
271         }
272         
273         for(i=0;i<count;i++)
274                 CkPrintf("%d -- %d\n",i,chkwt[i]);
275         
276         //CkPrintf("totalwt after:%d avg is %d\n",avg,avg/count);
277 */
278   /*if(!sameMapFlag) {
279     for(i=0; i<numobjs; i++) {
280       if(origmap[i] != newmap[i]) {
281                                 CmiAssert(stats->from_proc[i] == origmap[i]);
282                                 ///Dont assign....wait........
283                                 stats->to_proc[i] =  newmap[i];
284                                 if (_lb_args.debug() >= 3)
285           CkPrintf("[%d] Obj %d migrating from %d to %d\n", CkMyPe(),i,stats->from_proc[i],stats->to_proc[i]);
286       }
287     }
288   }*/
289
290   delete[] origmap;
291 }
292
293 void TopoLB::initDataStructures(CentralLB::LDStats *stats,int count,int *newmap)
294 {
295   int i;
296   //init dist
297   if(_lb_debug_on)
298     CkPrintf("Before initing dist\n");
299  
300   topo->get_pairwise_hop_count(dist);
301   for(i=0;i<count;i++)
302   {
303     double totaldist=0;
304     for(int j=0;j<count;j++)
305     {
306       //dist[i][j]=topo->get_hop_count(i,j);
307       totaldist+=dist[i][j];
308     }
309     dist[i][count]=totaldist/(count-1);
310   }
311
312   //Init comm,commUA from stats
313   if(_lb_debug_on)
314     CkPrintf("Before initing comm\n");
315   for(i=0;i<count;i++)
316   {
317     for(int j=0;j<count;j++)
318     {
319       comm[i][j]=0;
320     }
321     commUA[i]=0;
322   }
323   bool *multicastAdded=new bool[count];
324   for(i=0;i<stats->n_comm;i++)
325   {
326     LDCommData &cdata=stats->commData[i];
327     if(!cdata.from_proc() && cdata.receiver.get_type() ==LD_OBJ_MSG)
328     {
329       int sender=stats->getHash(cdata.sender);
330       int receiver=stats->getHash(cdata.receiver.get_destObj());
331
332       CmiAssert(sender<stats->n_objs);
333       CmiAssert(receiver<stats->n_objs);
334
335       if(newmap[sender]==newmap[receiver])
336         continue;
337
338       int send_part=newmap[sender];
339       int recv_part=newmap[receiver];
340       comm[send_part][recv_part]+=cdata.bytes;
341       comm[recv_part][send_part]+=cdata.bytes;
342
343       commUA[send_part]+=cdata.bytes;
344       commUA[recv_part]+=cdata.bytes;
345     }
346     if(!cdata.from_proc() && cdata.receiver.get_type()==LD_OBJLIST_MSG)
347     {
348       int nobjs=0;
349       LDObjKey *receivers=cdata.receiver.get_destObjs(nobjs);
350       int sender=stats->getHash(cdata.sender);
351       int send_part=newmap[sender];
352       
353       CmiAssert(sender<stats->n_objs);
354
355       for(int i=0;i<count;i++)
356         multicastAdded[i]=false;
357       multicastAdded[send_part]=true;
358
359       for(int k=0;k<nobjs;k++)
360       {
361         int receiver=stats->getHash(receivers[k]);
362         CmiAssert ( receiver < stats->n_objs);
363
364         int recv_part=newmap[receiver];
365         if(!multicastAdded[recv_part])
366         {
367           comm[send_part][recv_part]+=cdata.bytes;
368           comm[recv_part][send_part]+=cdata.bytes;
369       
370           commUA[send_part]+=cdata.bytes;
371           commUA[recv_part]+=cdata.bytes;
372
373           multicastAdded[recv_part]=true;
374         }
375       }
376     }
377   }
378
379   /******Avg degree test *******/
380   total_comm=0;
381   if(_lb_debug2_on)
382   {
383     int avg_degree=0;
384     for(int i=0;i<count;i++)
385     {
386       double comm_i_total=0;
387       for(int j=0;j<count;j++)
388       {
389         //Just a test
390         //comm[i][j]=(rand()%10 ==0);
391         //comm[i][j]=(dist[i][j]>count/4);
392         avg_degree+=(comm[i][j]>0);
393         total_comm+=comm[i][j];
394         comm_i_total+=comm[i][j];
395       }
396       //Just a test
397       //commUA[i]=comm_i_total;
398     }
399     CkPrintf("Avg degree (%d nodes) : %d\n",count,avg_degree/count);
400   }
401   /***************************/
402
403   //Init hopBytes
404   //hopBytes[i][j]=hopBytes if partition i is placed at proc j
405   if(_lb_debug_on)
406     CkPrintf("Before initing hopBytes\n");
407   for(i=0;i<count;i++)
408   {
409     int hbminIndex=0;
410     double hbtotal=0;
411     for(int j=0;j<count;j++)
412     {
413       //Initialize by (total comm of i)*(avg dist from j);
414       hopBytes[i][j]=commUA[i]*dist[j][count];
415       //Just a test
416       //hopBytes[i][j]=0;
417       hbtotal+=hopBytes[i][j];
418       if(hopBytes[i][hbminIndex]>hopBytes[i][j])
419         hbminIndex=j;
420     }
421     hopBytes[i][count]=hbminIndex;
422     hopBytes[i][count+1]=hbtotal/count;
423   }
424   
425   //Init pfree, cfree, assign
426   if(_lb_debug_on)
427     CkPrintf("Before initing pfree cfree assign\n");
428   for(i=0;i<count;i++)
429   {
430     pfree[i]=true;
431     cfree[i]=true;
432     assign[i]=-1;
433   }
434 }
435
436 void TopoLB :: work(CentralLB::LDStats *stats,int count)
437 {
438   int i, j;
439   if (_lb_args.debug() >= 2) 
440   {
441     CkPrintf("In TopoLB Strategy...\n");
442   }
443   
444   /****Make sure that there is at least one available processor.***/
445   int proc;
446   for (proc = 0; proc < count; proc++) 
447   {
448     if (stats->procs[proc].available)  
449       break;
450   }
451         
452   if (proc == count) 
453   {
454     CmiAbort ("TopoLB: no available processors!");
455   }
456  
457   removeNonMigratable(stats,count);
458
459   if(_lb_debug_on)
460   {
461     CkPrintf("Num of procs: %d\n",count);
462     CkPrintf("Num of objs:  %d\n",stats->n_objs);
463   }
464
465   /**************Initialize Topology ****************************/
466   LBtopoFn topofn;
467   topofn = LBTopoLookup(_lbtopo);
468   if (topofn == NULL) 
469   {
470         char str[1024];
471     CmiPrintf("TopoLB> Fatal error: Unknown topology: %s. Choose from:\n", _lbtopo);
472     printoutTopo();
473     sprintf(str, "TopoLB> Fatal error: Unknown topology: %s", _lbtopo);
474     CmiAbort(str);
475   }
476   topo = topofn(count);
477
478   /*********** Compute Partitions *********************************/
479   if(_lb_debug_on)
480     CkPrintf("before computing partitions...\n");
481   
482   int *newmap = new int[stats->n_objs];
483   if(_make_new_grouping_)
484     computePartitions(stats,count,newmap);
485   else
486   {
487     for(i=0;i<stats->n_objs;i++)
488     {
489       newmap[i]=stats->from_proc[i];
490     }
491   }
492   /***************** Fill Data Structures *************************/
493   if(_lb_debug_on)
494     CkPrintf("before allocating dataStructures...\n");
495   allocateDataStructures(count);
496   if(_lb_debug_on)
497     CkPrintf("before initizlizing dataStructures...\n");
498   initDataStructures(stats,count,newmap);
499
500   if(_lb_debug_on)
501     printDataStructures(count, stats->n_objs,newmap);
502   
503   /****************** Perform Mapping *****************************/
504
505   if(_lb_debug_on)
506     CkPrintf("before performing mapping...\n");
507
508   double *distnew=new double[count];
509   for(i=0;i<count;i++)
510   {
511     //Assume i-1 partitions placed, 
512     //select and place the ith partition
513
514     //select the (c,p) pair
515     int part_index=-1;
516     int proc_index=-1;
517
518
519     double gainMax=-1;
520     for(int j=0;j<count;j++)
521     {
522       if(!cfree[j])
523         continue;
524       
525       int hb_j_minIndex=(int)hopBytes[j][count];
526       //CmiAssert(pfree[hb_j_minIndex]);
527       double gain=hopBytes[j][count+1]-hopBytes[j][hb_j_minIndex];
528
529       //CmiAssert(gain>=0);
530       //CmiAssert(gain>=EPSILON);
531       
532       if(_lb_debug_on)
533         CkPrintf("Gain is : %lf\n",gain);
534
535       if(gain>gainMax)
536       {
537         part_index=j;
538         proc_index=hb_j_minIndex;
539         gainMax=gain;
540       }
541     }
542     if(_lb_debug_on)
543         CkPrintf("GainMax is : %lf\n",gainMax);
544
545     CmiAssert(part_index!=-1);
546     CmiAssert(proc_index!=-1);
547
548     //Assign the selection
549     CmiAssert(assign[part_index]==-1);
550     CmiAssert(pfree[proc_index]);
551     assign[part_index]=proc_index;
552     
553     /*
554     if(i==0)
555     {
556       double  maxComm=-1;
557       int maxCommIndex=-1;
558       for(int l=0;l<count;l++)
559       {
560         if(commUA[l]>maxComm)
561         {
562           maxComm=commUA[l];
563           maxCommIndex=l;
564         }
565       }
566       CkPrintf("Max communicating : %d\n",maxCommIndex);
567       CkPrintf("First selection   : %d\n",part_index);
568     }
569     */
570
571     //CkPrintf("assign[%d]=%d\n",part_index,proc_index);
572     /*
573     if(_lb_debug2_on)
574     {
575       if(i%100 ==0)
576         CkPrintf("Assigned %d procs \n",i+1);
577     }
578     */
579     /*****Update Data Structures******************/
580     cfree[part_index]=false;
581     pfree[proc_index]=false;
582
583     //Dont need to update other data structures if this is last assignment
584     if(i == count-1)
585       continue;
586
587     int procs_left=count-i-1;
588
589     //Update hopBytes
590     
591     for(j=0;j<count;j++)
592     {
593       if(procs_left>1)
594         distnew[j]=(dist[j][count]*procs_left -dist[j][proc_index]) / (procs_left-1);
595       else
596         distnew[j]=0;
597     }
598     for(int cpart=0;cpart<count;cpart++)
599     {
600       if(!cfree[cpart]) //No need to update for assigned partitions
601         continue;    
602
603       if(commUA[cpart]==0 && hopBytes[cpart][count]!=proc_index)
604       {
605         if(procs_left>1)
606           hopBytes[cpart][count+1]=(hopBytes[cpart][count+1]*(procs_left+1) - hopBytes[cpart][proc_index])/(procs_left);
607         continue;
608       }
609
610       //double hbmin=INFTY;
611       double hbmin=-1;
612       double hbtotal=0;
613
614       double c1=commUA[cpart];
615       double c2=comm[cpart][part_index];
616
617       double h_updated=0;
618       int h_minindex=(int)hopBytes[cpart][count];
619
620       for(int proc=0;proc<count;proc++)
621       {
622         if(!pfree[proc]) // No need to update for assigned procs
623           continue;
624
625         /*
626         hopBytes[cpart][proc]-=commUA[cpart]*dist[proc][count];
627         hopBytes[cpart][proc]+=comm[cpart][part_index]*dist[proc][proc_index];
628         hopBytes[cpart][proc]+=(commUA[cpart]-comm[cpart][part_index])*distnew[proc];
629         */
630
631         hopBytes[cpart][proc]+=(c1-c2)*distnew[proc]+c2*dist[proc][proc_index]-c1*dist[proc][count];
632         //Just a test
633         //hopBytes[cpart][proc]+=c2*dist[proc][proc_index];
634         h_updated=hopBytes[cpart][proc];
635         
636         //CmiAssert((commUA[cpart]-comm[cpart][part_index]) >= EPSILON);
637         //CmiAssert(hopBytes[cpart][proc] >= EPSILON);
638         //CmiAssert(hopBytes[cpart][proc] >= EPSILON);
639
640         hbtotal+=h_updated;
641         if(hbmin==-1 || h_updated<hbmin)
642         {
643           hbmin=h_updated;
644           h_minindex=proc;
645         }
646       }
647       hopBytes[cpart][count]=h_minindex;
648       //CmiAssert(hbmin!=-1);
649       hopBytes[cpart][count+1]=hbtotal/(procs_left);
650     }
651
652     // d[j][count] is the average dist of proc j to unassigned procs
653     // Also update commUA[j]
654     for(j=0;j<count;j++)
655     {
656       if(procs_left>1)
657         dist[j][count]=(dist[j][count]*procs_left -dist[j][proc_index]) / (procs_left-1);
658       else
659         dist[j][count]=0;
660       commUA[j]-=comm[j][part_index];
661     }
662   }
663
664   /******************  Fill out final composition Mapping **************************/
665
666   for(i=0;i<stats->n_objs;i++)
667   {
668     stats->to_proc[i]= assign[newmap[i]];
669   }
670
671   if(_lb_debug2_on)
672   {
673     double hbval1=getHopBytes(stats,count,stats->from_proc);
674     CkPrintf("\n");
675     CkPrintf(" Original   hopBytes : %lf  Avg comm hops: %lf\n", hbval1,hbval1/total_comm);
676     double hbval2=getHopBytes(stats,count,stats->to_proc);
677     CkPrintf(" Resulting  hopBytes : %lf  Avg comm hops: %lf\n", hbval2,hbval2/total_comm);
678     CkPrintf("Percentage gain %.2lf\n",(hbval1-hbval2)*100/hbval1);
679     CkPrintf("\n");
680   }
681
682   freeDataStructures(count);
683   delete[] newmap;
684 }
685
686
687 void TopoLB::printDataStructures(int count,int n_objs,int *newmap)
688 {
689   int i;
690   /*
691   CkPrintf("Partition Results : \n");
692   for(int i=0;i<n_objs;i++)
693   {
694     CkPrintf("map[%d] = %d\n",i,newmap[i]);
695   }
696   */
697
698   CkPrintf("Dist : \n");
699   for(i=0;i<count;i++)
700   {
701     for(int j=0;j<count+1;j++)
702     {
703       CkPrintf("%lf ",dist[i][j]);
704     }
705     CkPrintf("\n");
706   }
707   CkPrintf("HopBytes: \n");
708   for(i=0;i<count;i++)
709   {
710     for(int j=0;j<count+2;j++)
711     {
712       CkPrintf("%lf ",hopBytes[i][j]);
713     }
714     CkPrintf("\n");
715   }
716 }
717 double TopoLB::getHopBytes(CentralLB::LDStats *stats,int count,CkVec<int>map)
718 {
719   int i;
720   double **comm1=new double*[count];
721   for(i=0;i<count;i++)
722     comm1[i]=new double[count];
723
724   for(i=0;i<count;i++)
725   {
726     for(int j=0;j<count;j++)
727     {
728       comm1[i][j]=0;
729     }
730   }
731
732   bool *multicastAdded=new bool[count];
733   for(i=0;i<stats->n_comm;i++)
734   {
735     LDCommData &cdata=stats->commData[i];
736     if(!cdata.from_proc() && cdata.receiver.get_type() ==LD_OBJ_MSG)
737     {
738       int sender=stats->getHash(cdata.sender);
739       int receiver=stats->getHash(cdata.receiver.get_destObj());
740
741       CmiAssert(sender<stats->n_objs);
742       CmiAssert(receiver<stats->n_objs);
743
744       if(map[sender]==map[receiver])
745         continue;
746
747       int send_part=map[sender];
748       int recv_part=map[receiver];
749       comm1[send_part][recv_part]+=cdata.bytes;
750       comm1[recv_part][send_part]+=cdata.bytes;
751     }
752     if(!cdata.from_proc() && cdata.receiver.get_type()==LD_OBJLIST_MSG)
753     {
754       int nobjs=0;
755       LDObjKey *receivers=cdata.receiver.get_destObjs(nobjs);
756       int sender=stats->getHash(cdata.sender);
757       int send_part=map[sender];
758       
759       CmiAssert(sender<stats->n_objs);
760
761       for(i=0;i<count;i++)
762         multicastAdded[i]=false;
763       multicastAdded[send_part]=true;
764
765       for(int k=0;k<nobjs;k++)
766       {
767         int receiver=stats->getHash(receivers[k]);
768         //CmiAssert ( (int)(receivers[k])< stats->n_objs);
769         CmiAssert ( receiver < stats->n_objs);
770
771         int recv_part=map[receiver];
772         if(!multicastAdded[recv_part])
773         {
774           comm1[send_part][recv_part]+=cdata.bytes;
775           comm1[recv_part][send_part]+=cdata.bytes;
776       
777           multicastAdded[recv_part]=true;
778         }
779       }
780     }
781   }
782   delete[] multicastAdded;
783
784   double totalHB=0;
785   int proc1,proc2;
786
787   for(i=0;i<count;i++)
788   {
789     proc1=map[i];
790     for(int j=0;j<count;j++)
791     {
792       proc2=map[j];
793       //totalHB+=dist[proc1][proc2]*comm1[i][j];
794       totalHB+=dist[i][j]*comm1[i][j];
795     }
796   }
797   for(i=0;i<count;i++)
798     delete[] comm1[i];
799   delete[] comm1;
800
801   return totalHB;
802 }
803
804
805 #include "TopoLB.def.h"