scheme for checkpoint group data
[charm.git] / src / ck-ldb / HybridBaseLB.C
1 /**
2  * \addtogroup CkLdb
3 */
4 /*@{*/
5
6 #include "HybridBaseLB.h"
7 #include "LBDBManager.h"
8 #include "GreedyLB.h"
9 #include "GreedyCommLB.h"
10 #include "RefineCommLB.h"
11 #include "RefineLB.h"
12
13 #define  DEBUGF(x)     // CmiPrintf x;
14
15 CreateLBFunc_Def(HybridBaseLB, "HybridBase load balancer")
16
17 class DummyMsg: public CMessage_DummyMsg 
18 {
19 };
20
21 void HybridBaseLB::staticMigrated(void* data, LDObjHandle h, int waitBarrier)
22 {
23   HybridBaseLB *me = (HybridBaseLB*)(data);
24
25   me->Migrated(h, waitBarrier);
26 }
27
28 void HybridBaseLB::staticAtSync(void* data)
29 {
30 #if CMK_MEM_CHECKPOINT  
31   CkSetInLdb();
32 #endif
33   HybridBaseLB *me = (HybridBaseLB*)(data);
34
35   me->AtSync();
36 }
37
38 HybridBaseLB::HybridBaseLB(const CkLBOptions &opt): BaseLB(opt)
39 {
40 #if CMK_LBDB_ON
41   lbname = (char *)"HybridBaseLB";
42   thisProxy = CProxy_HybridBaseLB(thisgroup);
43   receiver = theLbdb->
44     AddLocalBarrierReceiver((LDBarrierFn)(staticAtSync),
45                             (void*)(this));
46   notifier = theLbdb->getLBDB()->
47     NotifyMigrated((LDMigratedFn)(staticMigrated), (void*)(this));
48
49   statsStrategy = FULL;
50
51   // defines topology
52   if (CkNumPes() <= 4)  {
53     tree = new TwoLevelTree;
54   }
55   else {
56     tree = new ThreeLevelTree;
57     if (CkNumPes() >= 4096) statsStrategy = SHRINK;
58     //statsStrategy = SHRINK;
59
60   }
61   //tree = new FourLevelTree;
62   if (CkMyPe() == 0)
63     CkPrintf("%s: %s is created.\n", lbname, tree->name());
64
65   // decide which load balancer to call
66 //  greedy = (CentralLB *)AllocateGreedyLB();
67 //  refine = (CentralLB *)AllocateRefineLB();
68
69   currentLevel = 0;
70   foundNeighbors = 0;
71   future_migrates_expected = -1;
72
73   vector_n_moves = 0;
74
75   maxLoad = 0.0;
76   maxCpuLoad = 0.0;
77   totalLoad = 0.0;
78   maxCommCount = 0;
79   maxCommBytes = 0.0;
80   maxMem = 0.0;
81
82   if (_lb_args.statsOn()) theLbdb->CollectStatsOn();
83
84   group1_created = 0;             // base class need to call initTree()
85 #endif
86 }
87
88 void HybridBaseLB::initTree()
89 {
90 #if CMK_LBDB_ON
91 #if ! CMK_BIGSIM_CHARM
92     // create a multicast group to optimize level 1 multicast
93   if (tree->isroot(CkMyPe(), 1)) {
94     int npes = tree->numChildren(CkMyPe(), 1);
95     if (npes >= 128) {                          // only when the group is big
96       int *pes = new int[npes];
97       tree->getChildren(CkMyPe(), 1, pes, npes);
98       group1 = CmiEstablishGroup(npes, pes);
99       group1_created = 1;
100       delete [] pes;
101     }
102   }
103 #endif
104 #endif
105 }
106
107 HybridBaseLB::~HybridBaseLB()
108 {
109 #if CMK_LBDB_ON
110   theLbdb = CProxy_LBDatabase(_lbdb).ckLocalBranch();
111   if (theLbdb) {
112     theLbdb->getLBDB()->
113       RemoveNotifyMigrated(notifier);
114     //theLbdb->
115     //  RemoveStartLBFn((LDStartLBFn)(staticStartLB));
116   }
117   delete tree;
118 #endif
119 }
120
121 // get tree information
122 void HybridBaseLB::FindNeighbors()
123 {
124   if (foundNeighbors == 0) { // Neighbors never initialized, so init them
125                            // and other things that depend on the number
126                            // of neighbors
127
128     int nlevels = tree->numLevels();
129     int mype = CkMyPe();
130     for (int level=0; level<nlevels; level++) 
131     {
132       LevelData *data = new LevelData;
133       data->parent = tree->parent(mype, level);
134       if (tree->isroot(mype, level)) {
135         data->nChildren = tree->numChildren(mype, level);
136         data->children = new int[data->nChildren];
137         tree->getChildren(mype, level, data->children, data->nChildren);
138         data->statsMsgsList = new CLBStatsMsg*[data->nChildren];
139         for(int i=0; i < data->nChildren; i++)
140            data->statsMsgsList[i] = NULL;
141         data->statsData = new LDStats(data->nChildren+1, 0);  // incomplete
142         //  a fake processor
143         ProcStats &procStat = data->statsData->procs[data->nChildren];
144         procStat.available = CmiFalse;
145       }
146       levelData.push_back(data);
147       DEBUGF(("[%d] level: %d nchildren:%d - %d %d\n", CkMyPe(), level, data->nChildren, data->nChildren>0?data->children[0]:-1, data->nChildren>1?data->children[1]:-1));
148     }
149     
150     foundNeighbors = 1;
151   }   // end if
152 }
153
154 void HybridBaseLB::AtSync()
155 {
156 #if CMK_LBDB_ON
157   //  CkPrintf("[%d] HybridBaseLB At Sync step %d!!!!\n",CkMyPe(),mystep);
158
159   FindNeighbors();
160
161   // if num of processor is only 1, nothing should happen
162   if (!QueryBalanceNow(step()) || CkNumPes() == 1) {
163     MigrationDone(0);
164     return;
165   }
166
167   thisProxy[CkMyPe()].ProcessAtSync();
168 #endif
169 }
170
171 void HybridBaseLB::ProcessAtSync()
172 {
173 #if CMK_LBDB_ON
174   start_lb_time = 0;
175
176   if (CkMyPe() == 0) {
177     start_lb_time = CkWallTimer();
178     if (_lb_args.debug())
179       CkPrintf("[%s] Load balancing step %d starting at %f\n",
180                lbName(), step(), CkWallTimer());
181   }
182
183   // assemble LB database
184   CLBStatsMsg* msg = AssembleStats();
185
186   CkMarshalledCLBStatsMessage marshmsg(msg);
187   // send to parent
188   thisProxy[levelData[0]->parent].ReceiveStats(marshmsg, 0);
189
190   DEBUGF(("[%d] Send stats to myself\n", CkMyPe()));
191 #endif
192 }
193
194 // only called on leaves
195 CLBStatsMsg* HybridBaseLB::AssembleStats()
196 {
197 #if CMK_LBDB_ON
198   // build and send stats
199   const int osz = theLbdb->GetObjDataSz();
200   const int csz = theLbdb->GetCommDataSz();
201
202   CLBStatsMsg* msg = new CLBStatsMsg(osz, csz);
203   msg->from_pe = CkMyPe();
204
205   // Get stats
206 #if CMK_LB_CPUTIMER
207   theLbdb->GetTime(&msg->total_walltime,&msg->total_cputime,
208                    &msg->idletime, &msg->bg_walltime,&msg->bg_cputime);
209 #else
210   theLbdb->GetTime(&msg->total_walltime,&msg->total_walltime,
211                    &msg->idletime, &msg->bg_walltime,&msg->bg_walltime);
212 #endif
213 //  msg->pe_speed = myspeed;
214   // number of pes
215   msg->pe_speed = 1;
216
217   msg->n_objs = osz;
218   theLbdb->GetObjData(msg->objData);
219   msg->n_comm = csz;
220   theLbdb->GetCommData(msg->commData);
221
222   return msg;
223 #else
224   return NULL;
225 #endif
226 }
227
228 void HybridBaseLB::ReceiveStats(CkMarshalledCLBStatsMessage &data, int fromlevel)
229 {
230 #if CMK_LBDB_ON
231   FindNeighbors();
232
233   // store the message
234   CLBStatsMsg *m = data.getMessage();
235   int atlevel = fromlevel + 1;
236   CmiAssert(tree->isroot(CkMyPe(), atlevel));
237
238   depositLBStatsMessage(m, atlevel);
239
240   int &stats_msg_count = levelData[atlevel]->stats_msg_count;
241   stats_msg_count ++;
242
243   DEBUGF(("[%d] ReceiveStats at level: %d %d/%d\n", CkMyPe(), atlevel, stats_msg_count, levelData[atlevel]->nChildren));
244   if (stats_msg_count == levelData[atlevel]->nChildren)  
245   {
246     // build LDStats
247     buildStats(atlevel);
248     stats_msg_count = 0;
249     int parent = levelData[atlevel]->parent;
250     if (parent != -1) {
251       // combine and shrink message
252       // build a new message based on our LDStats
253       CLBStatsMsg* cmsg = buildCombinedLBStatsMessage(atlevel);
254
255       // send to parent
256       CkMarshalledCLBStatsMessage marshmsg(cmsg);
257       thisProxy[parent].ReceiveStats(marshmsg, atlevel);
258     }
259     else {
260       // root of all processors, calls top-level strategy (refine)
261       thisProxy[CkMyPe()].Loadbalancing(atlevel);
262     }
263   }
264
265 #endif  
266 }
267
268 // store stats message in a level data
269 void HybridBaseLB::depositLBStatsMessage(CLBStatsMsg *m, int atlevel)
270 {
271   int pe = m->from_pe;
272   int neighborIdx = NeighborIndex(pe, atlevel);
273
274   CLBStatsMsg **statsMsgsList = levelData[atlevel]->statsMsgsList;
275   LDStats *statsData = levelData[atlevel]->statsData;
276   CmiAssert(statsMsgsList && statsData);
277
278   if (statsMsgsList[neighborIdx] != 0) {
279     CkPrintf("*** Unexpected CLBStatsMsg in ReceiveStats from PE %d-%d ***\n", pe,neighborIdx);
280     CkAbort("HybridBaseLB> Abort!");
281   }
282
283   // replace real pe to relative pe number in preparation for calling Strategy()
284   for (int i=0; i<m->n_comm; i++) {
285      LDCommData &commData = m->commData[i];
286      // modify processor to be this local pe
287      if (commData.from_proc()) m->commData[i].src_proc = neighborIdx;
288      if (commData.receiver.get_type() == LD_PROC_MSG) m->commData[i].receiver.setProc(neighborIdx);
289   }
290
291   statsMsgsList[neighborIdx] = m;
292       // store per processor data right away
293   struct ProcStats &procStat = statsData->procs[neighborIdx];
294   procStat.pe = pe;     // real PE
295   procStat.total_walltime = m->total_walltime;
296   procStat.idletime = m->idletime;
297   procStat.bg_walltime = m->bg_walltime;
298 #if CMK_LB_CPUTIMER
299   procStat.total_cputime = m->total_cputime;
300   procStat.bg_cputime = m->bg_cputime;
301 #endif
302   procStat.pe_speed = m->pe_speed;              // important
303   procStat.available = CmiTrue;
304   procStat.n_objs = m->n_objs;
305
306   statsData->n_objs += m->n_objs;
307   statsData->n_comm += m->n_comm;
308 }
309
310 // assmebly all stats messages from children
311 void HybridBaseLB::buildStats(int atlevel)
312 {
313 #if CMK_LBDB_ON
314   // build LDStats
315   LevelData *lData = levelData[atlevel];
316   LDStats *statsData = lData->statsData;
317   CLBStatsMsg **statsMsgsList = lData->statsMsgsList;
318   int stats_msg_count = lData->stats_msg_count;
319
320   // statsMsgsList
321   DEBUGF(("[%d] buildStats for %d nobj:%d\n", CkMyPe(), stats_msg_count, statsData->n_objs));
322   statsData->nprocs() = stats_msg_count;
323   statsData->objData.resize(statsData->n_objs);
324   statsData->commData.resize(statsData->n_comm);
325   statsData->from_proc.resize(statsData->n_objs);
326   statsData->to_proc.resize(statsData->n_objs);
327   int nobj = 0;
328   int nmigobj = 0;
329   int ncom = 0;
330   for (int n=0; n<stats_msg_count; n++) {
331      int i;
332      CLBStatsMsg *msg = statsMsgsList[n];
333      int pe = msg->from_pe;
334      for (i=0; i<msg->n_objs; i++) {
335          // need to map index to relative index
336          statsData->from_proc[nobj] = statsData->to_proc[nobj] = NeighborIndex(pe, atlevel);
337          statsData->objData[nobj] = msg->objData[i];
338          if (msg->objData[i].migratable) nmigobj++;
339          nobj++;
340      }
341      for (i=0; i<msg->n_comm; i++) {
342          statsData->commData[ncom] = msg->commData[i];
343          ncom++;
344      }
345      // free the message
346      delete msg;
347      statsMsgsList[n]=0;
348   }
349   if (_lb_args.debug()>1) {
350       CmiPrintf("[%d] n_obj:%d migratable:%d ncom:%d at level %d at %f.\n", CkMyPe(), nobj, nmigobj, ncom, atlevel, CkWallTimer());
351   }
352   CmiAssert(statsData->n_objs == nobj);
353   CmiAssert(statsData->n_comm == ncom);
354   statsData->n_migrateobjs = nmigobj;
355 #endif
356 }
357
358 // build a message based on our LDStats for sending to parent
359 // shrink if neccessary
360 CLBStatsMsg * HybridBaseLB::buildCombinedLBStatsMessage(int atlevel)
361 {
362 #if CMK_LBDB_ON
363   int i;
364   double obj_walltime, obj_nmwalltime;
365 #if CMK_LB_CPUTIMER 
366   double obj_cputime, obj_nmcputime;
367 #endif
368
369   LDStats *statsData = levelData[atlevel]->statsData;
370   CmiAssert(statsData);
371
372   CLBStatsMsg* cmsg;
373
374   int osz = statsData->n_objs;
375   int csz = statsData->n_comm;
376
377   int shrink = 0;
378   if ((statsStrategy == SHRINK || statsStrategy == SHRINK_NULL) && atlevel == tree->numLevels()-2) 
379   {
380     shrink = 1;
381     obj_walltime = obj_nmwalltime = 0.0;
382 #if CMK_LB_CPUTIMER
383     obj_cputime = obj_nmcputime = 0.0;
384 #endif
385     for (i=0; i<osz; i++)  {
386       if (statsData->objData[i].migratable) {
387         obj_walltime += statsData->objData[i].wallTime;
388 #if CMK_LB_CPUTIMER
389         obj_cputime += statsData->objData[i].cpuTime;
390 #endif
391       }
392       else {
393         obj_nmwalltime += statsData->objData[i].wallTime;
394 #if CMK_LB_CPUTIMER
395         obj_nmcputime += statsData->objData[i].cpuTime;
396 #endif
397       }
398     }
399       // skip obj and comm data
400     osz = csz = 0;
401   }
402
403   cmsg = new CLBStatsMsg(osz, csz);
404   int mype = CkMyPe();
405   cmsg->from_pe = mype; // real PE
406
407   // Get stats
408   cmsg->pe_speed = 0;
409   cmsg->total_walltime = 0.0;
410   cmsg->idletime = 0.0;
411   cmsg->bg_walltime = 0.0;
412 #if CMK_LB_CPUTIMER
413   cmsg->total_cputime = 0.0;
414   cmsg->bg_cputime = 0.0;
415 #endif
416
417   for (int pe=0; pe<statsData->nprocs(); pe++) {
418         struct ProcStats &procStat = statsData->procs[pe];
419         cmsg->pe_speed += procStat.pe_speed;            // important
420         cmsg->total_walltime += procStat.total_walltime;
421         cmsg->idletime += procStat.idletime;
422         cmsg->bg_walltime += procStat.bg_walltime;
423 #if CMK_LB_CPUTIMER
424         cmsg->total_cputime += procStat.total_cputime;
425         cmsg->bg_cputime += procStat.bg_cputime;
426 #endif
427   }
428 /*
429   cmsg->idletime = 0.0;
430   cmsg->bg_walltime = 0.0;
431   cmsg->bg_cputime = 0.0;
432 */
433
434   // copy obj data
435   cmsg->n_objs = osz;
436   for (i=0; i<osz; i++)  {
437      cmsg->objData[i] = statsData->objData[i];
438   }
439   // copy comm data
440   cmsg->n_comm = csz;
441   for (i=0; i<csz; i++) {
442      LDCommData &commData = statsData->commData[i];
443      cmsg->commData[i] = commData;
444      // modify processor to be this real pe
445      if (commData.from_proc()) cmsg->commData[i].src_proc = mype;
446      if (commData.receiver.get_type() == LD_PROC_MSG) cmsg->commData[i].receiver.setProc(mype);
447   }
448
449   if (shrink) {
450     cmsg->total_walltime = obj_walltime;
451     cmsg->bg_walltime += obj_nmwalltime;
452 #if CMK_LB_CPUTIMER
453     cmsg->total_cputime = obj_cputime;
454     cmsg->bg_cputime += obj_nmcputime;
455 #endif
456   }
457
458   return cmsg;
459 #else
460   return NULL;
461 #endif
462 }
463
464 //  LDStats data sent to parent contains real PE
465 //  LDStats in parent should contain relative PE
466 void HybridBaseLB::Loadbalancing(int atlevel)
467 {
468   int i;
469
470   CmiAssert(atlevel >= 1);
471   CmiAssert(tree->isroot(CkMyPe(), atlevel));
472
473   LevelData *lData = levelData[atlevel];
474   LDStats *statsData = lData->statsData;
475   CmiAssert(statsData);
476
477   // at this time, all objects processor location is relative, and 
478   // all incoming objects from outside group belongs to the fake root proc.
479
480   // clear background load if needed
481   if (_lb_args.ignoreBgLoad()) statsData->clearBgLoad();
482
483   currentLevel = atlevel;
484   int nclients = lData->nChildren;
485
486   DEBUGF(("[%d] Calling Strategy ... \n", CkMyPe()));
487   double start_lb_time, strat_end_time;
488   start_lb_time = CkWallTimer();
489
490   if ((statsStrategy == SHRINK || statsStrategy == SHRINK_NULL) && atlevel == tree->numLevels()-1) {
491     // no obj and comm data
492     LBVectorMigrateMsg* migrateMsg = VectorStrategy(statsData);
493     strat_end_time = CkWallTimer();
494
495     // send to children 
496     thisProxy.ReceiveVectorMigration(migrateMsg, nclients, lData->children);
497   }
498   else {
499     LBMigrateMsg* migrateMsg = Strategy(statsData);
500     strat_end_time = CkWallTimer();
501
502     // send to children 
503     //CmiPrintf("[%d] level: %d nclients:%d children: %d %d\n", CkMyPe(), atlevel, nclients, lData->children[0], lData->children[1]);
504     if (!group1_created)
505       thisProxy.ReceiveMigration(migrateMsg, nclients, lData->children);
506     else {
507         // send in multicast tree
508       thisProxy.ReceiveMigration(migrateMsg, group1);
509       //CkSendMsgBranchGroup(CkIndex_HybridBaseLB::ReceiveMigration(NULL),  migrateMsg, thisgroup, group1);
510     }
511     // CkPrintf("[%d] ReceiveMigration takes %f \n", CkMyPe(), CkWallTimer()-strat_end_time);
512   }
513
514   if (_lb_args.debug()>0){
515     CkPrintf("[%d] Loadbalancing Level %d (%d children) started at %f, elapsed time %f\n", CkMyPe(), atlevel, lData->nChildren, start_lb_time, strat_end_time-start_lb_time);
516     if (atlevel == tree->numLevels()-1) {
517         CkPrintf("[%d] %s memUsage: %.2fKB\n", CkMyPe(), lbName(), (1.0*useMem())/1024);
518     }
519   }
520
521   // inform new objects that are from outside group
522   if (atlevel < tree->numLevels()-1) {
523     for (i=0; i<statsData->n_objs; i++) {
524       CmiAssert(statsData->from_proc[i] != -1);   // ???
525       if (statsData->from_proc[i] == nclients)  {    // from outside
526         CmiAssert(statsData->to_proc[i] < nclients);
527         int tope = lData->children[statsData->to_proc[i]];
528         // comm data
529         CkVec<LDCommData> comms;
530 //        collectCommData(i, comms, atlevel);
531         thisProxy[tope].ObjMigrated(statsData->objData[i], comms.getVec(), comms.size(), atlevel-1);
532       }
533     }
534   }
535 }
536
537 LBMigrateMsg* HybridBaseLB::Strategy(LDStats* stats)
538 {
539 #if CMK_LBDB_ON
540   work(stats);
541
542   if (_lb_args.debug()>2)  {
543     CkPrintf("Obj Map:\n");
544     for (int i=0; i<stats->n_objs; i++) CkPrintf("%d ", stats->to_proc[i]);
545     CkPrintf("\n");
546   }
547
548   return createMigrateMsg(stats);
549 #else
550   return NULL;
551 #endif
552 }
553
554 // migrate only object LDStat in group
555 // leaf nodes actually migrate objects
556 void HybridBaseLB::ReceiveMigration(LBMigrateMsg *msg)
557 {
558 #if CMK_LBDB_ON
559 #if CMK_MEM_CHECKPOINT
560   CkResetInLdb();
561 #endif
562   FindNeighbors();
563
564   int atlevel = msg->level - 1;
565
566   DEBUGF(("[%d] ReceiveMigration\n", CkMyPe()));
567
568   LevelData *lData = levelData[atlevel];
569
570   // only non NULL when level > 0
571   LDStats *statsData = lData->statsData;
572
573   // do LDStats migration
574   const int me = CkMyPe();
575   lData->migrates_expected = 0;
576   for(int i=0; i < msg->n_moves; i++) {
577     MigrateInfo& move = msg->moves[i];
578     // incoming
579     if (move.from_pe != me && move.to_pe == me) {
580       // I can not be the parent node
581       DEBUGF(("[%d] expecting LDStats object from %d\n",me,move.from_pe));
582       // will receive a ObjData message
583       lData->migrates_expected ++;
584     }
585     else if (move.from_pe == me) {   // outgoing
586       if (statsData) {          // this is inner node
587         // send objdata
588         int obj;
589         int found = 0;
590         for (obj = 0; obj<statsData->n_objs; obj++) {
591           if (move.obj.omID() == statsData->objData[obj].handle.omID() && 
592             move.obj.objID() == statsData->objData[obj].handle.objID())
593           {
594             DEBUGF(("[%d] level: %d sending objData %d to %d. \n", CkMyPe(), atlevel, obj, move.to_pe));
595             found = 1;
596             // TODO send comm data
597             CkVec<LDCommData> comms;
598             collectCommData(obj, comms, atlevel);
599             if (move.to_pe != -1) {
600               // this object migrates to another PE of the parent domain
601               thisProxy[move.to_pe].ObjMigrated(statsData->objData[obj], comms.getVec(), comms.size(), atlevel);
602             }
603             lData->outObjs.push_back(MigrationRecord(move.obj, lData->children[statsData->from_proc[obj]], -1));
604             statsData->removeObject(obj);
605             break;
606           }
607         }
608         CmiAssert(found == 1);
609       }
610       else {            // this is leave node
611         if (move.to_pe == -1) {
612           lData->outObjs.push_back(MigrationRecord(move.obj, CkMyPe(), -1));
613         }
614         else {
615           // migrate the object
616           theLbdb->Migrate(move.obj,move.to_pe);
617         }
618       }
619     }   // end if
620   }
621
622   if (lData->migrationDone())
623     StatsDone(atlevel);
624 #endif
625 }
626
627 extern LBVectorMigrateMsg * VectorStrategy(BaseLB::LDStats *stats);
628
629 LBVectorMigrateMsg* HybridBaseLB::VectorStrategy(LDStats* stats)
630 {
631 #if CMK_LBDB_ON
632   LBVectorMigrateMsg* msg;
633   if (statsStrategy == SHRINK_NULL) {
634     msg = new(0,0) LBVectorMigrateMsg;
635     msg->n_moves = 0;
636     msg->level = currentLevel;
637   }
638   else {
639     msg = ::VectorStrategy(stats);
640     msg->level = currentLevel;
641
642     // translate pe number
643     LevelData *lData = levelData[currentLevel];
644     for(int i=0; i < msg->n_moves; i++) {
645       VectorMigrateInfo* move = &msg->moves[i];
646       move->from_pe = lData->children[move->from_pe];
647       move->to_pe = lData->children[move->to_pe];
648     }
649   }
650   return msg;
651 #else
652   return NULL;
653 #endif
654 }
655
656 void HybridBaseLB::ReceiveVectorMigration(LBVectorMigrateMsg *msg)
657 {
658 #if CMK_LBDB_ON
659   FindNeighbors();
660
661   int atlevel = msg->level - 1;
662
663   DEBUGF(("[%d] ReceiveMigration\n", CkMyPe()));
664
665   LevelData *lData = levelData[atlevel];
666   LDStats *statsData = lData->statsData;
667
668   // pick objects for required load migration, first fit
669   lData->vector_expected  = 0;
670   for (int i=0; i<msg->n_moves; i++)  {
671     VectorMigrateInfo &move = msg->moves[i];
672     CkVec<LDObjData> objs;
673     CkVec<LDCommData> comms;
674     if (move.from_pe == CkMyPe()) {
675       int toPe = move.to_pe;
676       double load = move.load;
677       int count = 0;
678       // TODO: sort max => low
679       for (int obj=statsData->n_objs-1; obj>=0; obj--) {
680         LDObjData &objData = statsData->objData[obj];
681         if (!objData.migratable) continue;
682         if (objData.wallTime <= load) {
683           if (_lb_args.debug()>2)
684             CkPrintf("[%d] send obj: %d to PE %d (load: %f).\n", CkMyPe(), obj, toPe, objData.wallTime);
685           objs.push_back(objData);
686           // send comm data
687           collectCommData(obj, comms, atlevel);
688           lData->outObjs.push_back(MigrationRecord(objData.handle, lData->children[statsData->from_proc[obj]], -1));
689           load -= objData.wallTime; 
690           statsData->removeObject(obj);
691           count ++;
692           if (load <= 0.0) break;
693         }
694       }
695       if (_lb_args.debug()>1)
696         CkPrintf("[%d] sending %d objects to %d at %f.\n", CkMyPe(), count, toPe, CkWallTimer());
697       if (objs.size() > 0)
698         thisProxy[toPe].ObjsMigrated(objs.getVec(), objs.size(), comms.getVec(), comms.size(), atlevel);
699       thisProxy[toPe].TotalObjMigrated(count, atlevel);
700     }
701     else if (move.to_pe == CkMyPe()) {
702       // expecting objects
703       lData->vector_expected ++;
704     }
705   }
706
707   if (_lb_args.debug()>1)
708     CkPrintf("[%d] expecting %d vectors. \n", CkMyPe(), lData->vector_expected);
709   if (lData->vectorReceived()) {
710     VectorDone(atlevel);
711     if (lData->migrationDone())
712       StatsDone(atlevel);
713   }
714
715   delete msg;
716 #endif
717 }
718
719 // objects arrives with only objdata
720 void HybridBaseLB::ObjsMigrated(LDObjData *datas, int m, LDCommData *cdata, int n, int atlevel)
721 {
722   int i;
723   LevelData *lData = levelData[atlevel];
724   LDStats *statsData = lData->statsData;
725
726   if (statsData != NULL) {
727     CkVec<LDObjData> &oData = statsData->objData;
728
729     for (i=0; i<m; i++)
730     {
731       // copy into LDStats
732       LDObjData &data = datas[i];
733       oData.push_back(data);
734       statsData->n_objs++;
735       if (data.migratable) statsData->n_migrateobjs++;
736       // an incoming object to the root
737       // pretend this object belongs to it
738       statsData->from_proc.push_back(lData->nChildren);
739       statsData->to_proc.push_back(lData->nChildren);
740     }
741
742     // copy into comm data
743     if (n) {
744       CkVec<LDCommData> &cData = statsData->commData;
745       for (int i=0; i<n; i++)
746         cData.push_back(cdata[i]);
747       statsData->n_comm += n;
748       statsData->deleteCommHash();
749     }
750   }
751   else {        // leaf node, from which proc is unknown at this time
752     for (i=0; i<m; i++) {
753       LDObjData &data = datas[i];
754       LDObjKey key;
755       key.omID() = data.omID();
756       key.objID() = data.objID();
757       newObjs.push_back(Location(key, -1));
758     }
759   }
760
761   lData->obj_completed+=m;
762   if (lData->migrationDone()) {
763     StatsDone(atlevel);
764   }
765 }
766
767 void HybridBaseLB::VectorDone(int atlevel)
768 {
769   LevelData *lData = levelData[atlevel];
770   lData->vector_expected = -1;
771   lData->vector_completed = 0;
772     // update the migration expected
773   lData->migrates_expected = vector_n_moves;
774   vector_n_moves = 0;
775   if (_lb_args.debug()>1)
776     CkPrintf("[%d] VectorDone %d %d at %f.\n", CkMyPe(), lData->vector_expected, lData->migrates_expected, CkWallTimer());
777 }
778
779 // one processor is going to send "count" objects to this processor
780 void HybridBaseLB::TotalObjMigrated(int count, int atlevel)
781 {
782   LevelData *lData = levelData[atlevel];
783   lData->vector_completed ++;
784   vector_n_moves += count;
785   if (_lb_args.debug()>1)
786     CkPrintf("[%d] TotalObjMigrated receive %d objects at %f.\n", CkMyPe(), count, CkWallTimer());
787   if (lData->vectorReceived()) {
788     VectorDone(atlevel);
789     if (lData->migrationDone())
790       StatsDone(atlevel);
791   }
792 }
793
794 void HybridBaseLB::Migrated(LDObjHandle h, int waitBarrier)
795 {
796   LevelData *lData = levelData[0];
797
798   lData->migrates_completed++;
799   DEBUGF(("[%d] An object migrated! %d %d\n", CkMyPe(),lData->migrates_completed,lData->migrates_expected));
800   if (lData->migrationDone()) {
801     if (!lData->resumeAfterMigration) {
802       StatsDone(0);
803     }
804     else {
805       // migration done finally
806       MigrationDone(1);
807     }
808   }
809 }
810
811 // find sender comms
812 void HybridBaseLB::collectCommData(int objIdx, CkVec<LDCommData> &comms, int atlevel)
813 {
814   LevelData *lData = levelData[atlevel];
815   LDStats *statsData = lData->statsData;
816
817   LDObjData &objData = statsData->objData[objIdx];
818
819   for (int com=0; com<statsData->n_comm; com++) {
820     LDCommData &cdata = statsData->commData[com];
821     if (cdata.from_proc()) continue;
822     if (cdata.sender.objID() == objData.objID() && cdata.sender.omID() == objData.omID())
823       comms.push_back(cdata);
824   }
825 }
826
827 // an object arrives with only objdata
828 void HybridBaseLB::ObjMigrated(LDObjData data, LDCommData *cdata, int n, int atlevel)
829 {
830   LevelData *lData = levelData[atlevel];
831   LDStats *statsData = lData->statsData;
832
833   if (statsData != NULL) {
834     CkVec<LDObjData> &oData = statsData->objData;
835
836     // copy into LDStats
837     oData.push_back(data);
838     statsData->n_objs++;
839     if (data.migratable) statsData->n_migrateobjs++;
840     // an incoming object to the root
841     // pretend this object belongs to it
842     statsData->from_proc.push_back(lData->nChildren);
843     statsData->to_proc.push_back(lData->nChildren);
844
845     // copy into comm data
846     if (n) {
847       CkVec<LDCommData> &cData = statsData->commData;
848       for (int i=0; i<n; i++) 
849         cData.push_back(cdata[i]);
850       statsData->n_comm += n;
851       statsData->deleteCommHash();
852     }
853   }
854   else {        // leaf node, from which proc is unknown at this time
855     LDObjKey key;
856     key.omID() = data.omID();
857     key.objID() = data.objID();
858     newObjs.push_back(Location(key, -1));
859   }
860
861   lData->obj_completed++;
862   if (lData->migrationDone()) {
863     StatsDone(atlevel);
864   }
865 }
866
867
868 void HybridBaseLB::StatsDone(int atlevel)
869 {
870
871   LevelData *lData = levelData[atlevel];
872   lData->obj_expected = -1;
873   lData->migrates_expected = -1;
874   lData->obj_completed = 0;
875   lData->migrates_completed = 0;
876
877   CmiAssert(lData->parent!=-1);
878
879   thisProxy[lData->parent].NotifyObjectMigrationDone(atlevel);
880 }
881
882 // called on a parent node
883 void HybridBaseLB::NotifyObjectMigrationDone(int fromlevel)
884 {
885
886   int atlevel = fromlevel + 1;
887   LevelData *lData = levelData[atlevel];
888
889   lData->mig_reported ++;
890   if (lData->mig_reported == lData->nChildren) {
891     lData->mig_reported = 0;
892     // start load balancing at this level
893     if (atlevel > 1) {
894       // I am done at the level, propagate load balancing to next level
895       thisProxy.Loadbalancing(atlevel-1, lData->nChildren, lData->children);
896     }
897     else {  // atlevel = 1
898       if (_lb_args.debug() > 1)
899          CkPrintf("[%d] NotifyObjectMigrationDone at level %d started at %f\n",
900                 CkMyPe(), atlevel, CkWallTimer());
901       DummyMsg *m = new (8*sizeof(int)) DummyMsg;
902       *((int *)CkPriorityPtr(m)) = -100-atlevel;
903       CkSetQueueing(m, CK_QUEUEING_IFIFO);
904       thisProxy.StartCollectInfo(m, lData->nChildren, lData->children);
905     }
906   }
907 }
908
909 // start from leaves of a domain, all processors in the domain start a 
910 // tree reduction to fill pending from/to proc pairs.
911 void HybridBaseLB::StartCollectInfo(DummyMsg *m)
912 {
913   int i;
914   delete m;
915   LevelData *lData = levelData[0];
916       // we are leaf, start a tree reduction to find from/to proc pairs
917       // set this counter
918   lData->resumeAfterMigration =  1;
919
920       // Locations
921   int migs = lData->outObjs.size() + newObjs.size();
922   Location *locs = new Location[migs];
923   int count=0;
924   int me = CkMyPe();
925   for (i=0; i<newObjs.size(); i++) {
926         locs[count] = newObjs[i];
927         locs[count].loc = me;
928         count++;
929   }
930   for (i=0; i<lData->outObjs.size(); i++) {
931         LDObjKey key;
932         key.omID() = lData->outObjs[i].handle.omID();
933         key.objID() = lData->outObjs[i].handle.objID();
934         locs[count].key = key;
935         locs[count].loc = -1;           // unknown
936         count++;
937   }
938     // assuming leaf must have a parent
939   DEBUGF(("[%d] level 0 has %d unmatched (out)%d+(new)%d. \n", CkMyPe(), migs, lData->outObjs.size(), newObjs.size()));
940   thisProxy[lData->parent].CollectInfo(locs, migs, 0);
941   delete [] locs;
942 }
943
944 void HybridBaseLB::CollectInfo(Location *loc, int n, int fromlevel)
945 {
946    int atlevel = fromlevel + 1;
947    LevelData *lData = levelData[atlevel];
948    lData->info_recved++;
949
950    CkVec<Location> &matchedObjs = lData->matchedObjs;
951    std::map<LDObjKey, int> &unmatchedObjs = lData->unmatchedObjs;
952
953    // sort into matched and unmatched list
954 #if 0
955    for (int i=0; i<n; i++) {
956      // search and see if we have answer, put to matched
957      // store in unknown
958      int found = 0;
959      for (int obj=0; obj<unmatchedObjs.size(); obj++) {
960        if (loc[i].key == unmatchedObjs[obj].key) {
961          // answer must exist
962          CmiAssert(unmatchedObjs[obj].loc != -1 || loc[i].loc != -1);
963          if (unmatchedObjs[obj].loc == -1) unmatchedObjs[obj].loc = loc[i].loc;
964          matchedObjs.push_back(unmatchedObjs[obj]);
965          unmatchedObjs.remove(obj);
966          found = 1;
967          break;
968        }
969      }
970      if (!found) unmatchedObjs.push_back(loc[i]);
971    }
972 #else
973    for (int i=0; i<n; i++) {
974      std::map<LDObjKey, int>::iterator iter = unmatchedObjs.find(loc[i].key);
975      if (iter != unmatchedObjs.end()) {
976        CmiAssert(iter->second != -1 || loc[i].loc != -1);
977        if (loc[i].loc == -1) loc[i].loc = iter->second;
978        matchedObjs.push_back(loc[i]);
979        unmatchedObjs.erase(iter);
980      }
981      else
982        unmatchedObjs[loc[i].key] = loc[i].loc;
983    }
984 #endif
985
986   DEBUGF(("[%d] level %d has %d unmatched and %d matched. \n", CkMyPe(), atlevel, unmatchedObjs.size(), matchedObjs.size()));
987
988    if (lData->info_recved == lData->nChildren) {
989      lData->info_recved = 0;
990      if (_lb_args.debug() > 1)
991          CkPrintf("[%d] CollectInfo at level %d started at %f\n",
992                 CkMyPe(), atlevel, CkWallTimer());
993      if (lData->parent != -1) {
994        // send only unmatched ones up the tree
995        CkVec<Location> unmatchedbuf;
996        for(std::map<LDObjKey, int>::const_iterator it = unmatchedObjs.begin(); it != unmatchedObjs.end(); ++it)
997        {
998          unmatchedbuf.push_back(Location(it->first, it->second));
999        }
1000
1001        thisProxy[lData->parent].CollectInfo(unmatchedbuf.getVec(), unmatchedbuf.size(), atlevel);
1002      }
1003      else { // root
1004        // we should have all answers now
1005        CmiAssert(unmatchedObjs.size() == 0);
1006        // start send match list down
1007        thisProxy.PropagateInfo(matchedObjs.getVec(), matchedObjs.size(), atlevel, lData->nChildren, lData->children);
1008        lData->statsData->clear();
1009      }
1010    }
1011 }
1012
1013 void HybridBaseLB::PropagateInfo(Location *loc, int n, int fromlevel)
1014 {
1015 #if CMK_LBDB_ON
1016   int i, obj;
1017   int atlevel = fromlevel - 1;
1018   LevelData *lData = levelData[atlevel];
1019   CkVec<Location> &matchedObjs = lData->matchedObjs;
1020   //CkVec<Location> &unmatchedObjs = lData->unmatchedObjs;
1021   std::map<LDObjKey, int> &unmatchedObjs = lData->unmatchedObjs;
1022
1023   if (atlevel > 0) {
1024     if (_lb_args.debug() > 1)
1025       CkPrintf("[%d] PropagateInfo at level %d started at %f\n",
1026                 CkMyPe(), atlevel, CkWallTimer());
1027     // search in unmatched
1028 #if 0
1029     for (i=0; i<n; i++) {
1030        // search and see if we have answer, put to matched
1031        // store in unknown
1032        for (obj=0; obj<unmatchedObjs.size(); obj++) {
1033          if (loc[i].key == unmatchedObjs[obj].key) {
1034            // answer must exist now
1035            CmiAssert(unmatchedObjs[obj].loc != -1 || loc[i].loc != -1);
1036            if (unmatchedObjs[obj].loc == -1) unmatchedObjs[obj].loc = loc[i].loc;
1037            matchedObjs.push_back(unmatchedObjs[obj]);
1038            unmatchedObjs.remove(obj);
1039            break;
1040          }
1041        }
1042     }
1043 #else
1044    for (int i=0; i<n; i++) {
1045        // search and see if we have answer, put to matched
1046      const LDObjKey key = loc[i].key;
1047      std::map<LDObjKey, int>::iterator iter = unmatchedObjs.find(key);
1048      if (iter != unmatchedObjs.end()) {
1049        // answer must exist now
1050        CmiAssert(iter->second != -1 || loc[i].loc != -1);
1051        if (loc[i].loc == -1) loc[i].loc = iter->second;
1052        matchedObjs.push_back(loc[i]);
1053        unmatchedObjs.erase(iter);
1054      }
1055    }
1056 #endif
1057     CmiAssert(unmatchedObjs.size() == 0);
1058     DEBUGF(("[%d] level %d PropagateInfo had %d matchedObjs. \n", CkMyPe(), atlevel, matchedObjs.size()));
1059
1060       // send down
1061     thisProxy.PropagateInfo(matchedObjs.getVec(), matchedObjs.size(), atlevel, lData->nChildren, lData->children);
1062
1063     lData->statsData->clear();
1064     matchedObjs.free();
1065   }
1066   else {  // leaf node
1067       // now start to migrate
1068     CkVec<MigrationRecord> & outObjs = lData->outObjs;
1069     int migs = outObjs.size() + newObjs.size();
1070     for (i=0; i<outObjs.size(); i++) {
1071       if (outObjs[i].toPe == -1) {
1072         for (obj=0; obj<n; obj++) {
1073           if (loc[obj].key.omID() == outObjs[i].handle.omID() &&
1074               loc[obj].key.objID() == outObjs[i].handle.objID()) {
1075             outObjs[i].toPe = loc[obj].loc;
1076             break;
1077           }
1078         }
1079         CmiAssert(obj < n);
1080       }
1081       CmiAssert(outObjs[i].toPe != -1);
1082         // migrate now!
1083       theLbdb->Migrate(outObjs[i].handle,outObjs[i].toPe);
1084     }   // end for out
1085     // incoming
1086     lData->migrates_expected = 0;
1087     future_migrates_expected = 0;
1088     for (i=0; i<newObjs.size(); i++) {
1089       if (newObjs[i].loc == -1) {
1090         for (obj=0; obj<n; obj++) {
1091           if (loc[obj].key == newObjs[i].key) {
1092             newObjs[i].loc = loc[obj].loc;
1093             break;
1094           }
1095         }
1096         CmiAssert(obj < n);
1097       }
1098       CmiAssert(newObjs[i].loc != -1);
1099       lData->migrates_expected++;
1100     }   // end of for
1101     DEBUGF(("[%d] expecting %d\n", CkMyPe(), lData->migrates_expected));
1102     if (lData->migrationDone()) {
1103       MigrationDone(1);
1104     }
1105   }
1106 #endif
1107 }
1108
1109 void HybridBaseLB::MigrationDone(int balancing)
1110 {
1111 #if CMK_LBDB_ON
1112   LevelData *lData = levelData[0];
1113
1114   DEBUGF(("[%d] HybridBaseLB::MigrationDone!\n", CkMyPe()));
1115
1116   theLbdb->incStep();
1117
1118   // reset 
1119   for (int i=0; i<tree->numLevels(); i++) 
1120     levelData[i]->clear();
1121   newObjs.free();
1122
1123   DEBUGF(("[%d] calling ResumeClients.\n", CkMyPe()));
1124   if (balancing && _lb_args.syncResume()) {
1125     // max load of all
1126     CkCallback cb(CkIndex_HybridBaseLB::ResumeClients((CkReductionMsg*)NULL),
1127                   thisProxy);
1128     contribute(sizeof(double), &maxLoad, CkReduction::max_double, cb);
1129   }
1130   else
1131     thisProxy[CkMyPe()].ResumeClients(balancing);
1132
1133   maxLoad = 0.0;
1134 #endif
1135 }
1136
1137 void HybridBaseLB::ResumeClients(CkReductionMsg *msg)
1138 {
1139 /*
1140   if (CkMyPe() == 0 && _lb_args.printSummary()) {
1141     double mload = *(double *)msg->getData();
1142     CkPrintf("[%d] MAX Load: %f at step %d.\n", CkMyPe(), mload, step()-1);
1143   }
1144 */
1145   ResumeClients(1);
1146   delete msg;
1147 }
1148
1149 void HybridBaseLB::ResumeClients(int balancing)
1150 {
1151 #if CMK_LBDB_ON
1152   DEBUGF(("[%d] ResumeClients. \n", CkMyPe()));
1153
1154   if (CkMyPe() == 0 && balancing) {
1155     double end_lb_time = CkWallTimer();
1156     if (_lb_args.debug())
1157       CkPrintf("[%s] Load balancing step %d finished at %f duration %f\n",
1158                 lbName(), step()-1,end_lb_time,end_lb_time - start_lb_time);
1159   }
1160
1161   // zero out stats
1162   theLbdb->ClearLoads();
1163
1164   theLbdb->ResumeClients();
1165 #endif
1166 }
1167
1168 void HybridBaseLB::work(LDStats* stats)
1169 {
1170 #if CMK_LBDB_ON
1171   CkPrintf("[%d] HybridBaseLB::work called!\n", CkMyPe());
1172 #endif
1173 }
1174   
1175 LBMigrateMsg * HybridBaseLB::createMigrateMsg(LDStats* stats)
1176 {
1177 #if CMK_LBDB_ON
1178   int i;
1179
1180   LevelData *lData = levelData[currentLevel];
1181
1182   CkVec<MigrateInfo*> migrateInfo;
1183
1184   // stats contains all objects that belong to this group
1185   // outObjs contains objects that are migrated out
1186   for (i=0; i<stats->n_objs; i++) {
1187     LDObjData &objData = stats->objData[i];
1188     int frompe = stats->from_proc[i];
1189     int tope = stats->to_proc[i];
1190     CmiAssert(tope != -1);
1191     if (frompe != tope) {
1192       //      CkPrintf("[%d] Obj %d migrating from %d to %d\n",
1193       //         CkMyPe(),obj,pe,dest);
1194 #if 0
1195       // delay until a summary is printed
1196       if (frompe == lData->nChildren)  {
1197         frompe = -1;
1198         CmiAssert(tope != -1 && tope != lData->nChildren);
1199       }
1200       else
1201         frompe = lData->children[frompe];
1202       if (tope != -1) {
1203         CmiAssert(tope < lData->nChildren);
1204         tope = lData->children[tope];
1205       }
1206 #endif
1207       MigrateInfo *migrateMe = new MigrateInfo;
1208       migrateMe->obj = objData.handle;
1209       migrateMe->from_pe = frompe;
1210       migrateMe->to_pe = tope;
1211       migrateMe->async_arrival = objData.asyncArrival;
1212       migrateInfo.insertAtEnd(migrateMe);
1213     }
1214     else 
1215       CmiAssert(frompe != lData->nChildren);
1216   }
1217
1218   // merge outgoing objs
1219   CkVec<MigrationRecord> &outObjs = lData->outObjs;
1220   for (i=0; i<outObjs.size(); i++) {
1221     MigrateInfo *migrateMe = new MigrateInfo;
1222     migrateMe->obj = outObjs[i].handle;
1223     migrateMe->from_pe = outObjs[i].fromPe;
1224     migrateMe->to_pe = -1;
1225 //    migrateMe->async_arrival = objData.asyncArrival;
1226     migrateInfo.insertAtEnd(migrateMe);
1227   }
1228
1229   // construct migration message
1230   int migrate_count=migrateInfo.length();
1231   DEBUGF(("[%d] level: %d has %d migrations. \n", CkMyPe(), currentLevel, migrate_count));
1232   // ignore avail_vector, etc for now
1233   //LBMigrateMsg * msg = new(migrate_count,count,count,0) LBMigrateMsg;
1234   LBMigrateMsg * msg = new(migrate_count,0,0,0) LBMigrateMsg;
1235   msg->level = currentLevel;
1236   msg->n_moves = migrate_count;
1237   for(i=0; i < migrate_count; i++) {
1238     MigrateInfo* item = (MigrateInfo*) migrateInfo[i];
1239     msg->moves[i] = *item;
1240     delete item;
1241     migrateInfo[i] = 0;
1242     DEBUGF(("[%d] obj (%d %d %d %d) migrate from %d to %d\n", CkMyPe(), item->obj.objID().id[0], item->obj.objID().id[1], item->obj.objID().id[2], item->obj.objID().id[3], item->from_pe, item->to_pe));
1243   }
1244
1245   if (_lb_args.printSummary())  printSummary(stats, stats->nprocs());
1246
1247   // translate relative pe number to its real number
1248   for(i=0; i < migrate_count; i++) {
1249     MigrateInfo* move = &msg->moves[i];
1250     if (move->to_pe != -1) {
1251       if (move->from_pe == lData->nChildren)  {
1252           // an object from outside group
1253         move->from_pe = -1;
1254         CmiAssert(move->to_pe != -1 && move->to_pe != lData->nChildren);
1255       }
1256       else
1257         move->from_pe = lData->children[move->from_pe];
1258       CmiAssert(move->to_pe < lData->nChildren);
1259       move->to_pe = lData->children[move->to_pe];
1260     }
1261   }
1262
1263   return msg;
1264 #else
1265   return NULL;
1266 #endif
1267 }
1268
1269 // function used for any application that uses Strategy() instead of work()
1270 LBMigrateMsg * HybridBaseLB::createMigrateMsg(CkVec<MigrateInfo *> &migrateInfo,int count)
1271 {
1272   int i;
1273
1274   // merge outgoing objs
1275   LevelData *lData = levelData[currentLevel];
1276   CkVec<MigrationRecord> &outObjs = lData->outObjs;
1277   for (i=0; i<outObjs.size(); i++) {
1278     MigrateInfo *migrateMe = new MigrateInfo;
1279     migrateMe->obj = outObjs[i].handle;
1280     migrateMe->from_pe = outObjs[i].fromPe;
1281     migrateMe->to_pe = -1;
1282     migrateInfo.insertAtEnd(migrateMe);
1283   }
1284
1285   if (_lb_args.printSummary())  printSummary(NULL, count);
1286
1287   int migrate_count=migrateInfo.length();
1288   // ignore avail_vector, etc for now
1289   //LBMigrateMsg * msg = new(migrate_count,count,count,0) LBMigrateMsg;
1290   LBMigrateMsg* msg = new(migrate_count,0,0,0) LBMigrateMsg;
1291   msg->level = currentLevel;
1292   msg->n_moves = migrate_count;
1293   for(i=0; i < migrate_count; i++) {
1294     MigrateInfo* item = migrateInfo[i];
1295     msg->moves[i] = *item;
1296     delete item;
1297     migrateInfo[i] = 0;
1298   } 
1299   return msg;
1300 }
1301
1302 int HybridBaseLB::NeighborIndex(int pe, int atlevel)
1303 {
1304     int peslot = -1;
1305     for(int i=0; i < levelData[atlevel]->nChildren; i++) {
1306       if (pe == levelData[atlevel]->children[i]) {
1307         peslot = i;
1308         break;
1309       }
1310     }
1311     return peslot;
1312 }
1313
1314 void HybridBaseLB::printSummary(LDStats *stats, int count)
1315 {
1316   double stime = CkWallTimer();
1317 #if 1
1318   if (currentLevel == 1 && stats!=NULL) {
1319       LBInfo info(count);
1320       info.getInfo(stats, count, 1);    // no comm cost
1321       double mLoad, mCpuLoad, totalLoad;
1322       info.getSummary(mLoad, mCpuLoad, totalLoad);
1323       int nmsgs, nbytes;
1324       stats->computeNonlocalComm(nmsgs, nbytes);
1325       //CkPrintf("[%d] Load Summary: max (with comm): %f max (obj only): %f total: %f on %d processors at step %d useMem: %fKB nonlocal: %d %dKB.\n", CkMyPe(), maxLoad, mCpuLoad, totalLoad, count, step(), (1.0*useMem())/1024, nmsgs, nbytes/1024);
1326       thisProxy[0].reportLBQulity(mLoad, mCpuLoad, totalLoad, nmsgs, nbytes/1024);
1327   }
1328 #endif
1329
1330   if (currentLevel == tree->numLevels()-2) {
1331       double mem = (1.0*useMem())/1024;
1332       thisProxy[0].reportLBMem(mem);
1333   }
1334   CkPrintf("[%d] Print Summary takes %f seconds. \n", CkMyPe(), CkWallTimer()-stime);
1335 }
1336
1337 // only called on PE 0
1338 void HybridBaseLB::reportLBQulity(double mload, double mCpuLoad, double totalload, int nmsgs, double bytes)
1339 {
1340   static int pecount=0;
1341   CmiAssert(CkMyPe() == 0);
1342   if (mload > maxLoad) maxLoad = mload;
1343   if (mCpuLoad > maxCpuLoad) maxCpuLoad = mCpuLoad;
1344   totalLoad += totalload;
1345   maxCommCount += nmsgs;
1346   maxCommBytes += bytes;   // KB
1347   pecount++;
1348   if (pecount == tree->numNodes(1)) {
1349     CkPrintf("[%d] Load Summary: max (with comm): %f max (obj only): %f total: %f at step %d nonlocal: %d msgs, %.2fKB reported from %d PEs.\n", CkMyPe(), maxLoad, maxCpuLoad, totalLoad, step(), maxCommCount, maxCommBytes, pecount);
1350     maxLoad = 0.0;
1351     maxCpuLoad = 0.0;
1352     totalLoad = 0.0;
1353     maxCommCount = 0;
1354     maxCommBytes = 0.0;
1355     pecount = 0;
1356   }
1357 }
1358
1359 // only called on PE 0
1360 void HybridBaseLB::reportLBMem(double mem)
1361 {
1362   static int pecount=0;
1363   CmiAssert(CkMyPe() == 0);
1364   if (mem > maxMem) maxMem = mem;
1365   pecount++;
1366   if (pecount == tree->numNodes(tree->numLevels()-2)) {
1367     CkPrintf("[%d] Load Summary: maxMem: %fKB reported at step %d from %d PEs.\n", CkMyPe(), maxMem, step(), pecount);
1368     maxMem = 0.0;
1369     pecount = 0;
1370   }
1371 }
1372
1373 int HybridBaseLB::useMem()
1374 {
1375   int i;
1376   int memused = 0;
1377   for (i=0; i<levelData.size(); i++)
1378     if (levelData[i]) memused+=levelData[i]->useMem();
1379   memused += newObjs.size() * sizeof(Location);
1380   return memused;
1381 }
1382
1383 #include "HybridBaseLB.def.h"
1384
1385 /*@{*/
1386
1387