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