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