Fixing a bug in the way data is stored in vec
[charm.git] / src / ck-ldb / LBDatabase.C
1 /**
2  * \addtogroup CkLdb
3 */
4 /*@{*/
5
6 #include "converse.h"
7
8 /*
9  * This C++ file contains the Charm stub functions
10  */
11
12 #include "LBDatabase.h"
13 #include "LBSimulation.h"
14 #include "topology.h"
15
16 #include "limits.h"
17
18 #include "NullLB.h"
19
20 #define VEC_SIZE 500
21 #define IMB_TOLERANCE 1.1
22 #define OUTOFWAY_TOLERANCE 2
23 #define UTILIZATION_THRESHOLD 0.7
24 #define NEGLECT_IDLE 2 // Should never be == 1
25
26 #   define DEBAD(x) /*CkPrintf x*/
27 #   define EXTRA_FEATURE 0
28
29 struct AdaptiveData {
30   double iteration;
31   double max_load;
32   double avg_load;
33   double utilization;
34   double idle_time;
35 };
36
37 struct AdaptiveLBDatabase {
38   std::vector<AdaptiveData> history_data;
39 } adaptive_lbdb;
40
41 struct AdaptiveLBInfo {
42   AdaptiveLBInfo() {
43     max_avg_ratio = 1;
44     remote_local_ratio = 1;
45   }
46   double max_avg_ratio;
47   double remote_local_ratio;
48 };
49
50 // TODO: Separate out the datastructure required by just the central and on all
51 // processors
52 struct AdaptiveLBStructure {
53   int tentative_period;
54   int final_lb_period;
55   // This is based on the linear extrapolation
56   int lb_calculated_period;
57   int lb_iteration_no;
58   // This is set when all the processor sends the maximum iteration no
59   int global_max_iter_no;
60   // This keeps track of what was the max iteration no we had previously
61   // received. TODO: Mostly global_max_iter_no should be sufficied.
62   int tentative_max_iter_no;
63   // TODO: Use reduction to collect max iteration. Then we don't need this
64   // counter.
65   int global_recv_iter_counter;
66   // true indicates it is in Inform->ReceiveMaxIter->FinalLBPeriod stage.
67   bool in_progress;
68   double lb_strategy_cost;
69   double lb_migration_cost;
70   bool doCommStrategy;
71   int lb_msg_send_no;
72   int lb_msg_recv_no;
73   // Total AtSync calls from all the chares residing on the processor
74   int total_syncs_called;
75   int last_lb_type;
76   AdaptiveLBInfo greedy_info;
77   AdaptiveLBInfo refine_info;
78   AdaptiveLBInfo comm_info;
79   AdaptiveLBInfo comm_refine_info;
80 } adaptive_struct;
81
82
83 CkReductionMsg* lbDataCollection(int nMsg, CkReductionMsg** msgs) {
84   double lb_data[8];
85   lb_data[1] = 0.0; // total number of processors contributing
86   lb_data[2] = 0.0; // total load
87   lb_data[3] = 0.0; // max load
88   lb_data[4] = 0.0; // idle time
89   lb_data[5] = 1.0; // utilization
90   lb_data[6] = 0.0; // total load with bg
91   lb_data[7] = 0.0; // max load with bg
92   for (int i = 0; i < nMsg; i++) {
93     CkAssert(msgs[i]->getSize() == 8*sizeof(double));
94     if (msgs[i]->getSize() != 8*sizeof(double)) {
95       CkPrintf("Error!!! Reduction not correct. Msg size is %d\n", msgs[i]->getSize());
96     }
97     double* m = (double *)msgs[i]->getData();
98     // Total count
99     lb_data[1] += m[1];
100     // Avg load
101     lb_data[2] += m[2];
102     // Max load
103     lb_data[3] = ((m[3] > lb_data[3])? m[3] : lb_data[3]);
104     // Avg idle
105     lb_data[4] += m[4];
106     // Get least utilization
107     lb_data[5] = ((m[5] < lb_data[5]) ? m[5] : lb_data[5]);
108     // Get Avg load with bg
109     lb_data[6] += m[6];
110     // Get Max load with bg
111     lb_data[7] = ((m[7] > lb_data[7])? m[7] : lb_data[7]);
112     if (i == 0) {
113       // Iteration no
114       lb_data[0] = m[0];
115     }
116     if (m[0] != lb_data[0]) {
117       CkPrintf("Error!!! Reduction is intermingled between iteration %lf and\
118       %lf\n", lb_data[0], m[0]);
119     }
120   }
121   return CkReductionMsg::buildNew(8*sizeof(double), lb_data);
122 }
123
124 /*global*/ CkReduction::reducerType lbDataCollectionType;
125 /*initcall*/ void registerLBDataCollection(void) {
126   lbDataCollectionType = CkReduction::addReducer(lbDataCollection);
127 }
128
129 CkGroupID _lbdb;
130
131 CkpvDeclare(int, numLoadBalancers);  /**< num of lb created */
132 CkpvDeclare(int, hasNullLB);         /**< true if NullLB is created */
133 CkpvDeclare(int, lbdatabaseInited);  /**< true if lbdatabase is inited */
134
135 // command line options
136 CkLBArgs _lb_args;
137 int _lb_predict=0;
138 int _lb_predict_delay=10;
139 int _lb_predict_window=20;
140
141 // registry class stores all load balancers linked and created at runtime
142 class LBDBRegistry {
143 friend class LBDBInit;
144 friend class LBDatabase;
145 private:
146   // table for all available LBs linked in
147   struct LBDBEntry {
148     const char *name;
149     LBCreateFn  cfn;
150     LBAllocFn   afn;
151     const char *help;
152     int         shown;          // if 0, donot show in help page
153     LBDBEntry(): name(0), cfn(0), afn(0), help(0), shown(1) {}
154     LBDBEntry(int) {}
155     LBDBEntry(const char *n, LBCreateFn cf, LBAllocFn af,
156               const char *h, int show=1):
157       name(n), cfn(cf), afn(af), help(h), shown(show) {};
158   };
159   CkVec<LBDBEntry> lbtables;            // a list of available LBs linked
160   CkVec<const char *>   compile_lbs;    // load balancers at compile time
161   CkVec<const char *>   runtime_lbs;    // load balancers at run time
162 public:
163   LBDBRegistry() {}
164   void displayLBs()
165   {
166     CmiPrintf("\nAvailable load balancers:\n");
167     for (int i=0; i<lbtables.length(); i++) {
168       LBDBEntry &entry = lbtables[i];
169       if (entry.shown) CmiPrintf("* %s: %s\n", entry.name, entry.help);
170     }
171     CmiPrintf("\n");
172   }
173   void addEntry(const char *name, LBCreateFn fn, LBAllocFn afn, const char *help, int shown) {
174     lbtables.push_back(LBDBEntry(name, fn, afn, help, shown));
175   }
176   void addCompiletimeBalancer(const char *name) {
177     compile_lbs.push_back(name);
178   }
179   void addRuntimeBalancer(const char *name) {
180     runtime_lbs.push_back(name);
181   }
182   LBCreateFn search(const char *name) {
183     char *ptr = strpbrk((char *)name, ":,");
184     int slen = ptr!=NULL?ptr-name:strlen(name);
185     for (int i=0; i<lbtables.length(); i++)
186       if (0==strncmp(name, lbtables[i].name, slen)) return lbtables[i].cfn;
187     return NULL;
188   }
189   LBAllocFn getLBAllocFn(const char *name) {
190     char *ptr = strpbrk((char *)name, ":,");
191     int slen = ptr-name;
192     for (int i=0; i<lbtables.length(); i++)
193       if (0==strncmp(name, lbtables[i].name, slen)) return lbtables[i].afn;
194     return NULL;
195   }
196 };
197
198 static LBDBRegistry lbRegistry;
199
200 void LBDefaultCreate(const char *lbname)
201 {
202   lbRegistry.addCompiletimeBalancer(lbname);
203 }
204
205 // default is to show the helper
206 void LBRegisterBalancer(const char *name, LBCreateFn fn, LBAllocFn afn, const char *help, int shown)
207 {
208   lbRegistry.addEntry(name, fn, afn, help, shown);
209 }
210
211 LBAllocFn getLBAllocFn(char *lbname) {
212     return lbRegistry.getLBAllocFn(lbname);
213 }
214
215 LBCreateFn getLBCreateFn(const char *lbname) {
216     return lbRegistry.search(lbname);
217 }
218 // create a load balancer group using the strategy name
219 static void createLoadBalancer(const char *lbname)
220 {
221     LBCreateFn fn = lbRegistry.search(lbname);
222     if (!fn) {    // invalid lb name
223       CmiPrintf("Abort: Unknown load balancer: '%s'!\n", lbname);
224       lbRegistry.displayLBs();    // display help page
225       CkAbort("Abort");
226     }
227     // invoke function to create load balancer
228     fn();
229 }
230
231 // mainchare
232 LBDBInit::LBDBInit(CkArgMsg *m)
233 {
234 #if CMK_LBDB_ON
235   _lbdb = CProxy_LBDatabase::ckNew();
236
237   // runtime specified load balancer
238   if (lbRegistry.runtime_lbs.size() > 0) {
239     for (int i=0; i<lbRegistry.runtime_lbs.size(); i++) {
240       const char *balancer = lbRegistry.runtime_lbs[i];
241       createLoadBalancer(balancer);
242     }
243   }
244   else if (lbRegistry.compile_lbs.size() > 0) {
245     for (int i=0; i<lbRegistry.compile_lbs.size(); i++) {
246       const char* balancer = lbRegistry.compile_lbs[i];
247       createLoadBalancer(balancer);
248     }
249   }
250   else {
251     // NullLB is the default when none of above lb created
252     // note user may create his own load balancer in his code manually like
253     // in NAMD, but never mind NullLB can disable itself if there is
254     // a non NULL LB.
255     createLoadBalancer("NullLB");
256   }
257
258   // simulation mode
259   if (LBSimulation::doSimulation) {
260     CmiPrintf("Charm++> Entering Load Balancer Simulation Mode ... \n");
261     CProxy_LBDatabase(_lbdb).ckLocalBranch()->StartLB();
262   }
263 #endif
264   delete m;
265 }
266
267 // called from init.C
268 void _loadbalancerInit()
269 {
270   CkpvInitialize(int, lbdatabaseInited);
271   CkpvAccess(lbdatabaseInited) = 0;
272   CkpvInitialize(int, numLoadBalancers);
273   CkpvAccess(numLoadBalancers) = 0;
274   CkpvInitialize(int, hasNullLB);
275   CkpvAccess(hasNullLB) = 0;
276
277   char **argv = CkGetArgv();
278   char *balancer = NULL;
279   CmiArgGroup("Charm++","Load Balancer");
280   while (CmiGetArgStringDesc(argv, "+balancer", &balancer, "Use this load balancer")) {
281     if (CkMyRank() == 0)
282       lbRegistry.addRuntimeBalancer(balancer);   /* lbRegistry is a static */
283   }
284
285   // set up init value for LBPeriod time in seconds
286   // it can also be set by calling LDSetLBPeriod()
287   CmiGetArgDoubleDesc(argv,"+LBPeriod", &_lb_args.lbperiod(),"the minimum time period in seconds allowed for two consecutive automatic load balancing");
288   _lb_args.loop() = CmiGetArgFlagDesc(argv, "+LBLoop", "Use multiple load balancing strategies in loop");
289
290   // now called in cldb.c: CldModuleGeneralInit()
291   // registerLBTopos();
292   CmiGetArgStringDesc(argv, "+LBTopo", &_lbtopo, "define load balancing topology");
293   //Read the K parameter for RefineKLB
294   CmiGetArgIntDesc(argv, "+LBNumMoves", &_lb_args.percentMovesAllowed() , "Percentage of chares to be moved (used by RefineKLB) [0-100]");
295
296   /**************** FUTURE PREDICTOR ****************/
297   _lb_predict = CmiGetArgFlagDesc(argv, "+LBPredictor", "Turn on LB future predictor");
298   CmiGetArgIntDesc(argv, "+LBPredictorDelay", &_lb_predict_delay, "Number of balance steps before learning a model");
299   CmiGetArgIntDesc(argv, "+LBPredictorWindow", &_lb_predict_window, "Number of steps to use to learn a model");
300   if (_lb_predict_window < _lb_predict_delay) {
301     CmiPrintf("LB> [%d] Argument LBPredictorWindow (%d) less than LBPredictorDelay (%d) , fixing\n", CkMyPe(), _lb_predict_window, _lb_predict_delay);
302     _lb_predict_delay = _lb_predict_window;
303   }
304
305   /******************* SIMULATION *******************/
306   // get the step number at which to dump the LB database
307   CmiGetArgIntDesc(argv, "+LBVersion", &_lb_args.lbversion(), "LB database file version number");
308   CmiGetArgIntDesc(argv, "+LBCentPE", &_lb_args.central_pe(), "CentralLB processor");
309   int _lb_dump_activated = 0;
310   if (CmiGetArgIntDesc(argv, "+LBDump", &LBSimulation::dumpStep, "Dump the LB state from this step"))
311     _lb_dump_activated = 1;
312   if (_lb_dump_activated && LBSimulation::dumpStep < 0) {
313     CmiPrintf("LB> Argument LBDump (%d) negative, setting to 0\n",LBSimulation::dumpStep);
314     LBSimulation::dumpStep = 0;
315   }
316   CmiGetArgIntDesc(argv, "+LBDumpSteps", &LBSimulation::dumpStepSize, "Dump the LB state for this amount of steps");
317   if (LBSimulation::dumpStepSize <= 0) {
318     CmiPrintf("LB> Argument LBDumpSteps (%d) too small, setting to 1\n",LBSimulation::dumpStepSize);
319     LBSimulation::dumpStepSize = 1;
320   }
321   CmiGetArgStringDesc(argv, "+LBDumpFile", &LBSimulation::dumpFile, "Set the LB state file name");
322   // get the simulation flag and number. Now the flag can also be avoided by the presence of the number
323   LBSimulation::doSimulation = CmiGetArgIntDesc(argv, "+LBSim", &LBSimulation::simStep, "Read LB state from LBDumpFile since this step");
324   // check for stupid LBSim parameter
325   if (LBSimulation::doSimulation && LBSimulation::simStep < 0) {
326     CmiPrintf("LB> Argument LBSim (%d) invalid, should be >= 0\n");
327     CkExit();
328     return;
329   }
330   CmiGetArgIntDesc(argv, "+LBSimSteps", &LBSimulation::simStepSize, "Read LB state for this number of steps");
331   if (LBSimulation::simStepSize <= 0) {
332     CmiPrintf("LB> Argument LBSimSteps (%d) too small, setting to 1\n",LBSimulation::simStepSize);
333     LBSimulation::simStepSize = 1;
334   }
335
336
337   LBSimulation::simProcs = 0;
338   CmiGetArgIntDesc(argv, "+LBSimProcs", &LBSimulation::simProcs, "Number of target processors.");
339
340   LBSimulation::showDecisionsOnly =
341     CmiGetArgFlagDesc(argv, "+LBShowDecisions",
342                       "Write to File: Load Balancing Object to Processor Map decisions during LB Simulation");
343
344   // force a global barrier after migration done
345   _lb_args.syncResume() = CmiGetArgFlagDesc(argv, "+LBSyncResume",
346                   "LB performs a barrier after migration is finished");
347
348   // both +LBDebug and +LBDebug level should work
349   if (!CmiGetArgIntDesc(argv, "+LBDebug", &_lb_args.debug(),
350                                           "Turn on LB debugging printouts"))
351     _lb_args.debug() = CmiGetArgFlagDesc(argv, "+LBDebug",
352                                              "Turn on LB debugging printouts");
353
354   // getting the size of the team with +teamSize
355   if (!CmiGetArgIntDesc(argv, "+teamSize", &_lb_args.teamSize(),
356                                           "Team size"))
357     _lb_args.teamSize() = 1;
358
359   // ask to print summary/quality of load balancer
360   _lb_args.printSummary() = CmiGetArgFlagDesc(argv, "+LBPrintSummary",
361                 "Print load balancing result summary");
362
363   // to ignore baclground load
364   _lb_args.ignoreBgLoad() = CmiGetArgFlagDesc(argv, "+LBNoBackground",
365                       "Load balancer ignores the background load.");
366 #ifdef __BIGSIM__
367   _lb_args.ignoreBgLoad() = 1;
368 #endif
369   _lb_args.migObjOnly() = CmiGetArgFlagDesc(argv, "+LBObjOnly",
370                       "Only load balancing migratable objects, ignoring all others.");
371   if (_lb_args.migObjOnly()) _lb_args.ignoreBgLoad() = 1;
372
373   // assume all CPUs are identical
374   _lb_args.testPeSpeed() = CmiGetArgFlagDesc(argv, "+LBTestPESpeed",
375                       "Load balancer test all CPUs speed.");
376   _lb_args.samePeSpeed() = CmiGetArgFlagDesc(argv, "+LBSameCpus",
377                       "Load balancer assumes all CPUs are of same speed.");
378   if (!_lb_args.testPeSpeed()) _lb_args.samePeSpeed() = 1;
379
380   _lb_args.useCpuTime() = CmiGetArgFlagDesc(argv, "+LBUseCpuTime",
381                       "Load balancer uses CPU time instead of wallclock time.");
382
383   // turn instrumentation off at startup
384   _lb_args.statsOn() = !CmiGetArgFlagDesc(argv, "+LBOff",
385                         "Turn load balancer instrumentation off");
386
387   // turn instrumentation of communicatin off at startup
388   _lb_args.traceComm() = !CmiGetArgFlagDesc(argv, "+LBCommOff",
389                 "Turn load balancer instrumentation of communication off");
390
391   // set alpha and beeta
392   _lb_args.alpha() = PER_MESSAGE_SEND_OVERHEAD_DEFAULT;
393   _lb_args.beeta() = PER_BYTE_SEND_OVERHEAD_DEFAULT;
394   CmiGetArgDoubleDesc(argv,"+LBAlpha", &_lb_args.alpha(),
395                            "per message send overhead");
396   CmiGetArgDoubleDesc(argv,"+LBBeta", &_lb_args.beeta(),
397                            "per byte send overhead");
398
399   if (CkMyPe() == 0) {
400     if (_lb_args.debug()) {
401       CmiPrintf("CharmLB> Verbose level %d, load balancing period: %g seconds\n", _lb_args.debug(), _lb_args.lbperiod());
402     }
403     if (_lb_args.debug() > 1) {
404       CmiPrintf("CharmLB> Topology %s alpha: %es beta: %es.\n", _lbtopo, _lb_args.alpha(), _lb_args.beeta());
405     }
406     if (_lb_args.printSummary())
407       CmiPrintf("CharmLB> Load balancer print summary of load balancing result.\n");
408     if (_lb_args.ignoreBgLoad())
409       CmiPrintf("CharmLB> Load balancer ignores processor background load.\n");
410     if (_lb_args.samePeSpeed())
411       CmiPrintf("CharmLB> Load balancer assumes all CPUs are same.\n");
412     if (_lb_args.useCpuTime())
413       CmiPrintf("CharmLB> Load balancer uses CPU time instead of wallclock time.\n");
414     if (LBSimulation::doSimulation)
415       CmiPrintf("CharmLB> Load balancer running in simulation mode on file '%s' version %d.\n", LBSimulation::dumpFile, _lb_args.lbversion());
416     if (_lb_args.statsOn()==0)
417       CkPrintf("CharmLB> Load balancing instrumentation is off.\n");
418     if (_lb_args.traceComm()==0)
419       CkPrintf("CharmLB> Load balancing instrumentation for communication is off.\n");
420     if (_lb_args.migObjOnly())
421       CkPrintf("LB> Load balancing strategy ignores non-migratable objects.\n");
422   }
423 }
424
425 int LBDatabase::manualOn = 0;
426 char *LBDatabase::avail_vector = NULL;
427 CmiNodeLock avail_vector_lock;
428
429 static LBRealType * _expectedLoad = NULL;
430
431 void LBDatabase::initnodeFn()
432 {
433   int proc;
434   int num_proc = CkNumPes();
435   avail_vector= new char[num_proc];
436   for(proc = 0; proc < num_proc; proc++)
437       avail_vector[proc] = 1;
438   avail_vector_lock = CmiCreateLock();
439
440   _expectedLoad = new LBRealType[num_proc];
441   for (proc=0; proc<num_proc; proc++) _expectedLoad[proc]=0.0;
442
443   //CkPrintf("Total objs in %d is %d\n", CkMyPe(), getLBDB()->ObjDataCount());
444 }
445
446 // called my constructor
447 void LBDatabase::init(void)
448 {
449   //thisProxy = CProxy_LBDatabase(thisgroup);
450   myLDHandle = LDCreate();
451   mystep = 0;
452   nloadbalancers = 0;
453   new_ld_balancer = 0;
454
455   CkpvAccess(lbdatabaseInited) = 1;
456 #if CMK_LBDB_ON
457   if (manualOn) TurnManualLBOn();
458 #endif
459
460   total_load_vec.resize(VEC_SIZE, 0.0);
461   total_count_vec.resize(VEC_SIZE, 0);
462   purge_index = 0;
463   max_iteration = -1;
464   prev_idle = 0.0;
465   alpha_beta_cost_to_load = 1.0; // Some random value. TODO: Find the actual
466
467   // If metabalancer enabled, initialize the variables
468   adaptive_struct.tentative_period =  INT_MAX;
469   adaptive_struct.final_lb_period =  INT_MAX;
470   adaptive_struct.lb_calculated_period = INT_MAX;
471   adaptive_struct.lb_iteration_no = -1;
472   adaptive_struct.global_max_iter_no = 0;
473   adaptive_struct.tentative_max_iter_no = -1;
474   adaptive_struct.global_recv_iter_counter = 0;
475   adaptive_struct.in_progress = false;
476   adaptive_struct.lb_strategy_cost = 0.0;
477   adaptive_struct.lb_migration_cost = 0.0;
478   adaptive_struct.lb_msg_send_no = 0;
479   adaptive_struct.lb_msg_recv_no = 0;
480   adaptive_struct.total_syncs_called = 0;
481   adaptive_struct.last_lb_type = -1;
482
483   // This is indicating if the load balancing strategy and migration started.
484   // This is mainly used to register callbacks for noobj pes. They would
485   // register as soon as resumefromsync is called. On receiving the handles at
486   // the central pe, it clears the previous handlers and sets lb_in_progress
487   // to false so that it doesn't clear the handles.
488   lb_in_progress = false;
489
490   is_prev_lb_refine = -1;
491 }
492
493 LBDatabase::LastLBInfo::LastLBInfo()
494 {
495   expectedLoad = _expectedLoad;
496 }
497
498 void LBDatabase::get_avail_vector(char * bitmap) {
499     CmiAssert(bitmap && avail_vector);
500     const int num_proc = CkNumPes();
501     for(int proc = 0; proc < num_proc; proc++){
502       bitmap[proc] = avail_vector[proc];
503     }
504 }
505
506 // new_ld == -1(default) : calcualte a new ld
507 //           -2 : ignore new ld
508 //           >=0: given a new ld
509 void LBDatabase::set_avail_vector(char * bitmap, int new_ld){
510     int assigned = 0;
511     const int num_proc = CkNumPes();
512     if (new_ld == -2) assigned = 1;
513     else if (new_ld >= 0) {
514       CmiAssert(new_ld < num_proc);
515       new_ld_balancer = new_ld;
516       assigned = 1;
517     }
518     CmiAssert(bitmap && avail_vector);
519     for(int count = 0; count < num_proc; count++){
520         avail_vector[count] = bitmap[count];
521         if((bitmap[count] == 1) && !assigned){
522             new_ld_balancer = count;
523             assigned = 1;
524         }
525     }
526 }
527
528 // called in CreateFooLB() when multiple load balancers are created
529 // on PE0, BaseLB of each load balancer applies a ticket number
530 // and broadcast the ticket number to all processors
531 int LBDatabase::getLoadbalancerTicket()  {
532   int seq = nloadbalancers;
533   nloadbalancers ++;
534   loadbalancers.resize(nloadbalancers);
535   loadbalancers[seq] = NULL;
536   return seq;
537 }
538
539 void LBDatabase::addLoadbalancer(BaseLB *lb, int seq) {
540 //  CmiPrintf("[%d] addLoadbalancer for seq %d\n", CkMyPe(), seq);
541   if (seq == -1) return;
542   if (CkMyPe() == 0) {
543     CmiAssert(seq < nloadbalancers);
544     if (loadbalancers[seq]) {
545       CmiPrintf("Duplicate load balancer created at %d\n", seq);
546       CmiAbort("LBDatabase");
547     }
548   }
549   else
550     nloadbalancers ++;
551   loadbalancers.resize(seq+1);
552   loadbalancers[seq] = lb;
553 }
554
555 // switch strategy in order
556 void LBDatabase::nextLoadbalancer(int seq) {
557   if (seq == -1) return;                // -1 means this is the only LB
558   int next = seq+1;
559   if (_lb_args.loop()) {
560     if (next == nloadbalancers) next = 0;
561   }
562   else {
563     if (next == nloadbalancers) next --;  // keep using the last one
564   }
565   if (seq != next) {
566     loadbalancers[seq]->turnOff();
567     CmiAssert(loadbalancers[next]);
568     loadbalancers[next]->turnOn();
569   }
570 }
571
572 // return the seq-th load balancer string name of
573 // it can be specified in either compile time or runtime
574 // runtime has higher priority
575 const char *LBDatabase::loadbalancer(int seq) {
576   if (lbRegistry.runtime_lbs.length()) {
577     CmiAssert(seq < lbRegistry.runtime_lbs.length());
578     return lbRegistry.runtime_lbs[seq];
579   }
580   else {
581     CmiAssert(seq < lbRegistry.compile_lbs.length());
582     return lbRegistry.compile_lbs[seq];
583   }
584 }
585
586 void LBDatabase::pup(PUP::er& p)
587 {
588         IrrGroup::pup(p);
589         // the memory should be already allocated
590         int np;
591         if (!p.isUnpacking()) np = CkNumPes();
592         p|np;
593         CmiAssert(avail_vector);
594         // in case number of processors changes
595         if (p.isUnpacking() && np > CkNumPes()) {
596                 CmiLock(avail_vector_lock);
597                 delete [] avail_vector;
598                 avail_vector = new char[np];
599                 for (int i=0; i<np; i++) avail_vector[i] = 1;
600                 CmiUnlock(avail_vector_lock);
601         }
602         p(avail_vector, np);
603         p|mystep;
604         if(p.isUnpacking()) nloadbalancers = 0;
605 }
606
607
608 void LBDatabase::EstObjLoad(const LDObjHandle &_h, double cputime)
609 {
610 #if CMK_LBDB_ON
611   LBDB *const db = (LBDB*)(_h.omhandle.ldb.handle);
612   LBObj *const obj = db->LbObj(_h);
613
614   CmiAssert(obj != NULL);
615   obj->setTiming(cputime);
616 #endif
617 }
618
619 void LBDatabase::ResumeClients() {
620   // If metabalancer enabled, initialize the variables
621   adaptive_lbdb.history_data.clear();
622
623   adaptive_struct.tentative_period =  INT_MAX;
624   adaptive_struct.final_lb_period =  INT_MAX;
625   adaptive_struct.lb_calculated_period = INT_MAX;
626   adaptive_struct.lb_iteration_no = -1;
627   adaptive_struct.global_max_iter_no = 0;
628   adaptive_struct.tentative_max_iter_no = -1;
629   adaptive_struct.global_recv_iter_counter = 0;
630   adaptive_struct.in_progress = false;
631   adaptive_struct.lb_strategy_cost = 0.0;
632   adaptive_struct.lb_migration_cost = 0.0;
633   adaptive_struct.lb_msg_send_no = 0;
634   adaptive_struct.lb_msg_recv_no = 0;
635   adaptive_struct.total_syncs_called = 0;
636
637   total_load_vec.clear();
638   total_count_vec.clear();
639   purge_index = 0;
640   prev_idle = 0.0;
641   if (lb_in_progress) {
642     lbdb_no_obj_callback.clear();
643     lb_in_progress = false;
644   }
645
646   total_load_vec.resize(VEC_SIZE, 0.0);
647   total_count_vec.resize(VEC_SIZE, 0);
648
649   // While resuming client, if we find that there are no objects, then handle
650   // the case accordingly.
651   if (getLBDB()->ObjDataCount() == 0) {
652     HandleAdaptiveNoObj();
653   }
654   LDResumeClients(myLDHandle);
655 }
656
657 bool LBDatabase::AddLoad(int it_n, double load) {
658   if (it_n > VEC_SIZE && purge_index < VEC_SIZE) {
659     total_count_vec.assign(VEC_SIZE, 0);
660     total_load_vec.assign(VEC_SIZE, 0.0);
661     purge_index += VEC_SIZE;
662   }
663   int index = it_n - purge_index;
664   total_count_vec[index]++;
665   adaptive_struct.total_syncs_called++;
666   DEBAD(("At PE %d Total contribution for iteration %d is %d total objs %d\n",
667   CkMyPe(), it_n,
668     total_count_vec[index], getLBDB()->ObjDataCount()));
669
670   if (it_n > adaptive_struct.lb_iteration_no) {
671     adaptive_struct.lb_iteration_no = it_n;
672   }
673   total_load_vec[index] += load;
674   if (total_count_vec[index] == getLBDB()->ObjDataCount()) {
675     double idle_time, bg_walltime, cpu_bgtime;
676     IdleTime(&idle_time);
677     BackgroundLoad(&bg_walltime, &cpu_bgtime);
678
679     int sync_for_bg = adaptive_struct.total_syncs_called +
680         getLBDB()->ObjDataCount();
681     bg_walltime = bg_walltime * getLBDB()->ObjDataCount() / sync_for_bg;
682
683     if (it_n < NEGLECT_IDLE) {
684       prev_idle = idle_time;
685     }
686     idle_time -= prev_idle;
687
688     // The chares do not contribute their 0th iteration load. So the total syncs
689     // in reality is total_syncs_called + obj_counts
690     int total_countable_syncs = adaptive_struct.total_syncs_called +
691         (1 - NEGLECT_IDLE) * getLBDB()->ObjDataCount(); // TODO: Fix me! weird!
692     if (total_countable_syncs != 0) {
693       idle_time = idle_time * getLBDB()->ObjDataCount() / total_countable_syncs;
694     }
695     //CkPrintf("[%d] Idle time %lf and countable %d for iteration %d\n", CkMyPe(), idle_time, total_countable_syncs, iteration);
696
697     double lb_data[8];
698     lb_data[0] = it_n;
699     lb_data[1] = 1;
700     lb_data[2] = total_load_vec[index]; // For average load
701     lb_data[3] = total_load_vec[index]; // For max load
702     lb_data[4] = idle_time;
703     // Set utilization
704     if (total_load_vec[index] == 0.0) {
705       lb_data[5] = 0.0;
706     } else {
707       lb_data[5] = total_load_vec[index]/(idle_time + total_load_vec[index]);
708     }
709     lb_data[6] = lb_data[2] + bg_walltime; // For Avg load with bg
710     lb_data[7] = lb_data[6]; // For Max load with bg
711
712     //CkPrintf("   [%d] sends total load %lf idle time %lf ratio of idle/load %lf at iter %d\n", CkMyPe(),
713     //    total_load_vec[iteration], idle_time,
714     //    idle_time/total_load_vec[iteration], adaptive_struct.lb_iteration_no);
715
716     CkCallback cb(CkIndex_LBDatabase::ReceiveMinStats((CkReductionMsg*)NULL), thisProxy[0]);
717     contribute(8*sizeof(double), lb_data, lbDataCollectionType, cb);
718   }
719   return true;
720 }
721
722 void LBDatabase::ReceiveMinStats(CkReductionMsg *msg) {
723   double* load = (double *) msg->getData();
724   double avg = load[2]/load[1];
725   double max = load[3];
726   double avg_idle = load[4]/load[1];
727   double utilization = load[5];
728   int iteration_n = load[0];
729   double avg_load_bg = load[6]/load[1];
730   double max_load_bg = load[7];
731   DEBAD(("** [%d] Iteration Avg load: %lf Max load: %lf Avg Idle : %lf Max Idle : %lf for %lf procs\n",iteration_n, avg, max, avg_idle, utilization, load[1]));
732   CkPrintf("** [%d] Iteration Avg load: %lf Max load: %lf With bg Avg load: %lf Max load: %lf Avg Idle : %lf Max Idle : %lf for %lf procs\n",iteration_n, avg, max, avg_load_bg, max_load_bg, avg_idle, utilization, load[1]);
733   delete msg;
734
735 #if EXTRA_FEATURE
736   if (adaptive_struct.final_lb_period != iteration_n) {
737     for (int i = 0; i < lbdb_no_obj_callback.size(); i++) {
738       thisProxy[lbdb_no_obj_callback[i]].TriggerAdaptiveReduction();
739     }
740   }
741 #endif
742
743   // Store the data for this iteration
744   adaptive_struct.lb_iteration_no = iteration_n;
745   AdaptiveData data;
746   data.iteration = adaptive_struct.lb_iteration_no;
747   data.max_load = max;
748   data.avg_load = avg;
749   data.utilization = utilization;
750   data.idle_time = avg_idle;
751   adaptive_lbdb.history_data.push_back(data);
752
753   // If lb period inform is in progress, dont inform again.
754   // If this is the lb data corresponding to the final lb period informed, then
755   // don't recalculate as some of the processors might have already gone into
756   // LB_STAGE.
757   if (adaptive_struct.in_progress || (adaptive_struct.final_lb_period == iteration_n)) {
758     return;
759   }
760
761   double utilization_threshold = UTILIZATION_THRESHOLD;
762
763 #if EXTRA_FEATURE
764   CkPrintf("alpha_beta_to_load %lf\n", alpha_beta_cost_to_load);
765   if (alpha_beta_cost_to_load < 0.1) {
766     // Ignore the effect of idle time and there by lesser utilization. So we
767     // assign utilization threshold to be 0.0
768     CkPrintf("Changing the idle load tolerance coz this isn't communication intensive benchmark\n");
769     utilization_threshold = 0.0;
770   }
771 #endif
772
773   // First generate the lb period based on the cost of lb. Find out what is the
774   // expected imbalance at the calculated lb period.
775   int period;
776   // This is based on the new max load after load balancing. So technically, it
777   // is calculated based on the shifter up avg curve.
778   double ratio_at_t = 1.0;
779   int tmp_lb_type;
780   double tmp_max_avg_ratio, tmp_comm_ratio;
781   GetPrevLBData(tmp_lb_type, tmp_max_avg_ratio, tmp_comm_ratio);
782   double tolerate_imb = IMB_TOLERANCE * tmp_max_avg_ratio;
783
784   if (generatePlan(period, ratio_at_t)) {
785     DEBAD(("Generated period and calculated %d and period %d max iter %d\n",
786       adaptive_struct.lb_calculated_period, period,
787       adaptive_struct.tentative_max_iter_no));
788     // set the imbalance tolerance to be ratio_at_calculated_lb_period
789     if (ratio_at_t != 1.0) {
790       CkPrintf("Changed tolerance to %lf after line eq whereas max/avg is %lf\n", ratio_at_t, max/avg);
791       // Since ratio_at_t is shifter up, max/(tmp_max_avg_ratio * avg) should be
792       // compared with the tolerance
793       tolerate_imb = ratio_at_t * tmp_max_avg_ratio * OUTOFWAY_TOLERANCE;
794     }
795
796     CkPrintf("Prev LB Data Type %d, max/avg %lf, local/remote %lf\n", tmp_lb_type, tmp_max_avg_ratio, tmp_comm_ratio);
797
798     if ((utilization < utilization_threshold || max/avg >= tolerate_imb) && adaptive_lbdb.history_data.size() > 6) {
799       CkPrintf("Trigger soon even though we calculated lbperiod max/avg(%lf) and utilization ratio (%lf)\n", max/avg, utilization);
800       TriggerSoon(iteration_n, max/avg, tolerate_imb);
801       return;
802     }
803
804     // If the new lb period from linear extrapolation is greater than maximum
805     // iteration known from previously collected data, then inform all the
806     // processors about the new calculated period.
807     if (period > adaptive_struct.tentative_max_iter_no) {
808       adaptive_struct.doCommStrategy = false;
809       adaptive_struct.lb_calculated_period = period;
810       adaptive_struct.in_progress = true;
811       CkPrintf("Sticking to the calculated period %d\n",
812         adaptive_struct.lb_calculated_period);
813       thisProxy.LoadBalanceDecision(adaptive_struct.lb_msg_send_no++,
814         adaptive_struct.lb_calculated_period);
815       return;
816     }
817     // TODO: Shouldn't we return from here??
818   }
819
820   CkPrintf("Prev LB Data Type %d, max/avg %lf, local/remote %lf\n", tmp_lb_type, tmp_max_avg_ratio, tmp_comm_ratio);
821
822   // This would be called when the datasize is not enough to calculate lb period
823   if ((utilization < utilization_threshold || max/avg >= tolerate_imb) && adaptive_lbdb.history_data.size() > 4) {
824     CkPrintf("Carry out load balancing step at iter max/avg(%lf) and utilization ratio (%lf)\n", max/avg, utilization);
825     TriggerSoon(iteration_n, max/avg, tolerate_imb);
826     return;
827   }
828
829 }
830
831 void LBDatabase::TriggerSoon(int iteration_n, double imbalance_ratio,
832     double tolerate_imb) {
833
834   // If the previously calculated_period (not the final decision) is greater
835   // than the iter +1 and if it is greater than the maximum iteration we have
836   // seen so far, then we can inform this
837   if ((iteration_n + 1 > adaptive_struct.tentative_max_iter_no) &&
838       (iteration_n+1 < adaptive_struct.lb_calculated_period)) {
839     if (imbalance_ratio < tolerate_imb) {
840       adaptive_struct.doCommStrategy = true;
841       CkPrintf("No load imbalance but idle time\n");
842     } else {
843       adaptive_struct.doCommStrategy = false;
844       CkPrintf("load imbalance \n");
845     }
846     adaptive_struct.lb_calculated_period = iteration_n + 1;
847     adaptive_struct.in_progress = true;
848     CkPrintf("Informing everyone the lb period is %d\n",
849         adaptive_struct.lb_calculated_period);
850     thisProxy.LoadBalanceDecision(adaptive_struct.lb_msg_send_no++,
851         adaptive_struct.lb_calculated_period);
852   }
853 }
854
855 bool LBDatabase::generatePlan(int& period, double& ratio_at_t) {
856   if (adaptive_lbdb.history_data.size() <= 4) {
857     return false;
858   }
859
860   // Some heuristics for lbperiod
861   // If constant load or almost constant,
862   // then max * new_lb_period > avg * new_lb_period + lb_cost
863   double max = 0.0;
864   double avg = 0.0;
865   AdaptiveData data;
866   for (int i = 0; i < adaptive_lbdb.history_data.size(); i++) {
867     data = adaptive_lbdb.history_data[i];
868     max += data.max_load;
869     avg += data.avg_load;
870     //DEBAD(("max (%d, %lf) avg (%d, %lf)\n", i, data.max_load, i, data.avg_load));
871     //CkPrintf("max (%d, %lf) avg (%d, %lf)\n", i, data.max_load, i, data.avg_load);
872   }
873 //  max /= (adaptive_struct.lb_iteration_no - adaptive_lbdb.history_data[0].iteration);
874 //  avg /= (adaptive_struct.lb_iteration_no - adaptive_lbdb.history_data[0].iteration);
875
876   // If linearly varying load, then find lb_period
877   // area between the max and avg curve
878   // If we can attain perfect balance, then the new load is close to the
879   // average. Hence we pass 1, else pass in some other value which would be the
880   // new max_load after load balancing.
881   int tmp_lb_type;
882   double tmp_max_avg_ratio, tmp_comm_ratio;
883   double tolerate_imb;
884
885 #if EXTRA_FEATURE
886   // First get the data for refine.
887   GetLBDataForLB(1, tmp_max_avg_ratio, tmp_comm_ratio);
888   tolerate_imb = tmp_max_avg_ratio;
889
890   // If RefineLB does a good job, then find the period considering RefineLB
891   if (tmp_max_avg_ratio <= 1.01) {
892     if (max/avg < tolerate_imb) {
893       CkPrintf("Resorting to imb = 1.0 coz max/avg (%lf) < imb(%lf)\n", max/avg, tolerate_imb);
894       tolerate_imb = 1.0;
895     }
896     CkPrintf("Will generate plan for refine %lf imb and %lf overhead\n", tolerate_imb, 0.2);
897     return getPeriodForStrategy(tolerate_imb, 0.2, period, ratio_at_t);
898   }
899
900   GetLBDataForLB(0, tmp_max_avg_ratio, tmp_comm_ratio);
901 #endif
902
903   GetPrevLBData(tmp_lb_type, tmp_max_avg_ratio, tmp_comm_ratio);
904   tolerate_imb = tmp_max_avg_ratio;
905   if (max/avg < tolerate_imb) {
906     CkPrintf("Resorting to imb = 1.0 coz max/avg (%lf) < imb(%lf)\n", max/avg, tolerate_imb);
907     tolerate_imb = 1.0;
908   }
909
910   if (getPeriodForStrategy(tolerate_imb, 1, period, ratio_at_t)) {
911     return true;
912   }
913
914   max = 0.0;
915   avg = 0.0;
916   for (int i = 0; i < adaptive_lbdb.history_data.size(); i++) {
917     data = adaptive_lbdb.history_data[i];
918     max += data.max_load;
919     avg += data.avg_load*tolerate_imb;
920     //DEBAD(("max (%d, %lf) avg (%d, %lf)\n", i, data.max_load, i, data.avg_load));
921     //CkPrintf("max (%d, %lf) avg (%d, %lf)\n", i, data.max_load, i, data.avg_load);
922   }
923   max /= adaptive_lbdb.history_data.size();
924   avg /= adaptive_lbdb.history_data.size();
925   double cost = adaptive_struct.lb_strategy_cost + adaptive_struct.lb_migration_cost;
926   period = cost/(max - avg); 
927   ratio_at_t = max / avg;
928   return true;
929 }
930
931 bool LBDatabase::getPeriodForStrategy(double new_load_percent,
932     double overhead_percent, int& period, double& ratio_at_t) {
933   double mslope, aslope, mc, ac;
934   getLineEq(new_load_percent, aslope, ac, mslope, mc);
935   CkPrintf("new load percent %lf\n", new_load_percent);
936   CkPrintf("\n max: %fx + %f; avg: %fx + %f\n", mslope, mc, aslope, ac);
937   double a = (mslope - aslope)/2;
938   double b = (mc - ac);
939   double c = -(adaptive_struct.lb_strategy_cost +
940       adaptive_struct.lb_migration_cost) * overhead_percent;
941   bool got_period = getPeriodForLinear(a, b, c, period);
942   if (!got_period) {
943     return false;
944   }
945
946   if (mslope < 0) {
947     if (period > (-mc/mslope)) {
948       CkPrintf("Max < 0 Period set when max load is -ve\n");
949       return false;
950     }
951   }
952
953   if (aslope < 0) {
954     if (period > (-ac/aslope)) {
955       CkPrintf("Avg < 0 Period set when avg load is -ve\n");
956       return false;
957     }
958   }
959
960   int intersection_t = (mc-ac) / (aslope - mslope);
961   if (intersection_t > 0 && period > intersection_t) {
962     CkPrintf("Avg | Max Period set when curves intersect\n");
963     return false;
964   }
965   ratio_at_t = ((mslope*period + mc)/(aslope*period + ac));
966   CkPrintf("Ratio at t (%lf*%d + %lf) / (%lf*%d+%lf) = %lf\n", mslope, period, mc, aslope, period, ac, ratio_at_t);
967   return true;
968 }
969
970 bool LBDatabase::getPeriodForLinear(double a, double b, double c, int& period) {
971   CkPrintf("Quadratic Equation %lf X^2 + %lf X + %lf\n", a, b, c);
972   if (a == 0.0) {
973     period = (-c / b);
974     if (period < 0) {
975       CkPrintf("-ve period for -c/b (%d)\n", period);
976       return false;
977     }
978     CkPrintf("Ideal period for linear load %d\n", period);
979     return true;
980   }
981   int x;
982   double t = (b * b) - (4*a*c);
983   if (t < 0) {
984     CkPrintf("(b * b) - (4*a*c) is -ve sqrt : %lf\n", sqrt(t));
985     return false;
986   }
987   t = (-b + sqrt(t)) / (2*a);
988   x = t;
989   if (x < 0) {
990     CkPrintf("boo!!! x (%d) < 0\n", x);
991     x = 0;
992     return false;
993   }
994   period = x;
995   CkPrintf("Ideal period for linear load %d\n", period);
996   return true;
997 }
998
999 bool LBDatabase::getLineEq(double new_load_percent, double& aslope, double& ac, double& mslope, double& mc) {
1000   int total = adaptive_lbdb.history_data.size();
1001   int iterations = 1 + adaptive_lbdb.history_data[total - 1].iteration -
1002       adaptive_lbdb.history_data[0].iteration;
1003   double a1 = 0;
1004   double m1 = 0;
1005   double a2 = 0;
1006   double m2 = 0;
1007   AdaptiveData data;
1008   int i = 0;
1009   for (i = 0; i < total/2; i++) {
1010     data = adaptive_lbdb.history_data[i];
1011     m1 += data.max_load;
1012     a1 += data.avg_load;
1013     CkPrintf("max (%d, %lf) avg (%d, %lf) adjusted_avg (%d, %lf)\n", i, data.max_load, i, data.avg_load, i, new_load_percent*data.avg_load);
1014   }
1015   m1 /= i;
1016   a1 = (a1 * new_load_percent) / i;
1017
1018   for (i = total/2; i < total; i++) {
1019     data = adaptive_lbdb.history_data[i];
1020     m2 += data.max_load;
1021     a2 += data.avg_load;
1022     CkPrintf("max (%d, %lf) avg (%d, %lf) adjusted_avg (%d, %lf)\n", i, data.max_load, i, data.avg_load, i, new_load_percent*data.avg_load);
1023   }
1024   m2 /= (i - total/2);
1025   a2 = (a2 * new_load_percent) / (i - total/2);
1026
1027   aslope = 2 * (a2 - a1) / iterations;
1028   mslope = 2 * (m2 - m1) / iterations;
1029   ac = adaptive_lbdb.history_data[0].avg_load * new_load_percent;
1030   mc = adaptive_lbdb.history_data[0].max_load;
1031
1032   ac = a1 - ((aslope * total)/4);
1033   mc = m1 - ((mslope * total)/4);
1034
1035   //ac = (adaptive_lbdb.history_data[1].avg_load * new_load_percent - aslope);
1036   //mc = (adaptive_lbdb.history_data[1].max_load - mslope);
1037
1038   return true;
1039 }
1040
1041 void LBDatabase::LoadBalanceDecision(int req_no, int period) {
1042   if (req_no < adaptive_struct.lb_msg_recv_no) {
1043     CkPrintf("Error!!! Received a request which was already sent or old\n");
1044     return;
1045   }
1046   //CkPrintf("[%d] Load balance decision made cur iteration: %d period:%d state: %d\n",CkMyPe(), adaptive_struct.lb_iteration_no, period, local_state);
1047   adaptive_struct.tentative_period = period;
1048   adaptive_struct.lb_msg_recv_no = req_no;
1049   thisProxy[0].ReceiveIterationNo(req_no, adaptive_struct.lb_iteration_no);
1050 }
1051
1052 void LBDatabase::LoadBalanceDecisionFinal(int req_no, int period) {
1053   if (req_no < adaptive_struct.lb_msg_recv_no) {
1054     return;
1055   }
1056   DEBAD(("[%d] Final Load balance decision made cur iteration: %d period:%d \n",CkMyPe(), adaptive_struct.lb_iteration_no, period));
1057   adaptive_struct.tentative_period = period;
1058   adaptive_struct.final_lb_period = period;
1059   LDOMAdaptResumeSync(myLDHandle, period);
1060 }
1061
1062
1063 void LBDatabase::ReceiveIterationNo(int req_no, int local_iter_no) {
1064   CmiAssert(CkMyPe() == 0);
1065
1066   adaptive_struct.global_recv_iter_counter++;
1067   if (local_iter_no > adaptive_struct.global_max_iter_no) {
1068     adaptive_struct.global_max_iter_no = local_iter_no;
1069   }
1070
1071   int period;
1072   if (CkNumPes() == adaptive_struct.global_recv_iter_counter) {
1073
1074     if (adaptive_struct.global_max_iter_no > adaptive_struct.tentative_max_iter_no) {
1075       adaptive_struct.tentative_max_iter_no = adaptive_struct.global_max_iter_no;
1076     }
1077     period = (adaptive_struct.tentative_period > adaptive_struct.global_max_iter_no) ? adaptive_struct.tentative_period : adaptive_struct.global_max_iter_no + 1;
1078     // If no one has gone into load balancing stage, then we can safely change
1079     // the period otherwise keep the old period.
1080     if (adaptive_struct.global_max_iter_no < adaptive_struct.final_lb_period) {
1081       adaptive_struct.tentative_period = period;
1082       CkPrintf("Final lb_period CHANGED!%d\n", adaptive_struct.tentative_period);
1083     } else {
1084       adaptive_struct.tentative_period = adaptive_struct.final_lb_period;
1085       CkPrintf("Final lb_period NOT CHANGED!%d\n", adaptive_struct.tentative_period);
1086     }
1087     thisProxy.LoadBalanceDecisionFinal(req_no, adaptive_struct.tentative_period);
1088     adaptive_struct.in_progress = false;
1089     adaptive_struct.global_recv_iter_counter = 0;
1090   }
1091 }
1092
1093 int LBDatabase::getPredictedLBPeriod(bool& is_tentative) {
1094   // If tentative and final_lb_period are the same, then the decision has been
1095   // made but if not, they are in the middle of consensus, hence return the
1096   // lease of the two
1097   if (adaptive_struct.tentative_period != adaptive_struct.final_lb_period) {
1098     is_tentative = true;
1099   } else {
1100     is_tentative = false;
1101   }
1102   if (adaptive_struct.tentative_period < adaptive_struct.final_lb_period) {
1103     return adaptive_struct.tentative_period;
1104    } else {
1105      return adaptive_struct.final_lb_period;
1106    }
1107 }
1108
1109 // Called by CentralLB to indicate that the LB strategy and migration is in
1110 // progress.
1111 void LBDatabase::ResetAdaptive() {
1112   adaptive_struct.lb_iteration_no = -1;
1113   lb_in_progress = true;
1114 }
1115
1116 void LBDatabase::HandleAdaptiveNoObj() {
1117 #if EXTRA_FEATURE
1118   adaptive_struct.lb_iteration_no++;
1119   //CkPrintf("HandleAdaptiveNoObj %d\n", adaptive_struct.lb_iteration_no);
1120   thisProxy[0].RegisterNoObjCallback(CkMyPe());
1121   TriggerAdaptiveReduction();
1122 #endif
1123 }
1124
1125 void LBDatabase::RegisterNoObjCallback(int index) {
1126 #if EXTRA_FEATURE
1127   if (lb_in_progress) {
1128     lbdb_no_obj_callback.clear();
1129     //CkPrintf("Clearing and registering\n");
1130     lb_in_progress = false;
1131   }
1132   lbdb_no_obj_callback.push_back(index);
1133   CkPrintf("Registered %d to have no objs.\n", index);
1134
1135   // If collection has already happened and this is second iteration, then
1136   // trigger reduction.
1137   if (adaptive_struct.lb_iteration_no != -1) {
1138     //CkPrintf("Collection already started now %d so kick in\n", adaptive_struct.lb_iteration_no);
1139     thisProxy[index].TriggerAdaptiveReduction();
1140   }
1141 #endif
1142 }
1143
1144 void LBDatabase::TriggerAdaptiveReduction() {
1145 #if EXTRA_FEATURE
1146   adaptive_struct.lb_iteration_no++;
1147   //CkPrintf("Trigger adaptive for %d\n", adaptive_struct.lb_iteration_no);
1148   double lb_data[6];
1149   lb_data[0] = adaptive_struct.lb_iteration_no;
1150   lb_data[1] = 1;
1151   lb_data[2] = 0.0;
1152   lb_data[3] = 0.0;
1153   lb_data[4] = 0.0;
1154   lb_data[5] = 0.0;
1155
1156   // CkPrintf("   [%d] sends total load %lf idle time %lf ratio of idle/load %lf at iter %d\n", CkMyPe(),
1157   //     total_load_vec[iteration], idle_time,
1158   //     idle_time/total_load_vec[iteration], adaptive_struct.lb_iteration_no);
1159
1160   CkCallback cb(CkIndex_LBDatabase::ReceiveMinStats((CkReductionMsg*)NULL), thisProxy[0]);
1161   contribute(6*sizeof(double), lb_data, lbDataCollectionType, cb);
1162 #endif
1163 }
1164
1165
1166 bool LBDatabase::isStrategyComm() {
1167   return adaptive_struct.doCommStrategy;
1168 }
1169
1170 void LBDatabase::SetMigrationCost(double lb_migration_cost) {
1171   adaptive_struct.lb_migration_cost = lb_migration_cost;
1172 }
1173
1174 void LBDatabase::SetStrategyCost(double lb_strategy_cost) {
1175   adaptive_struct.lb_strategy_cost = lb_strategy_cost;
1176 }
1177
1178 void LBDatabase::UpdateAfterLBData(int lb, double lb_max, double lb_avg, double
1179     local_comm, double remote_comm) {
1180   adaptive_struct.last_lb_type = lb;
1181   if (lb == 0) {
1182     adaptive_struct.greedy_info.max_avg_ratio = lb_max/lb_avg;
1183   } else if (lb == 1) {
1184     adaptive_struct.refine_info.max_avg_ratio = lb_max/lb_avg;
1185   } else if (lb == 2) {
1186     adaptive_struct.comm_info.remote_local_ratio = remote_comm/local_comm;
1187   } else if (lb == 3) {
1188     adaptive_struct.comm_refine_info.remote_local_ratio =
1189     remote_comm/local_comm;
1190   }
1191 }
1192
1193 void LBDatabase::UpdateAfterLBData(double max_load, double max_cpu, double
1194 avg_load) {
1195   if (adaptive_struct.last_lb_type == -1) {
1196     adaptive_struct.last_lb_type = 0;
1197   }
1198   int lb = adaptive_struct.last_lb_type;
1199   //CkPrintf("Storing data after lb ratio %lf for lb %d\n", max_load/avg_load, lb);
1200   if (lb == 0) {
1201     adaptive_struct.greedy_info.max_avg_ratio = max_load/avg_load;
1202   } else if (lb == 1) {
1203     adaptive_struct.refine_info.max_avg_ratio = max_load/avg_load;
1204   } else if (lb == 2) {
1205     adaptive_struct.comm_info.max_avg_ratio = max_load/avg_load;
1206   } else if (lb == 3) {
1207     adaptive_struct.comm_refine_info.max_avg_ratio = max_load/avg_load;
1208   }
1209 }
1210
1211 void LBDatabase::UpdateAfterLBComm(double alpha_beta_to_load) {
1212   CkPrintf("Setting alpha beta %lf\n", alpha_beta_to_load);
1213   alpha_beta_cost_to_load = alpha_beta_to_load;
1214 }
1215
1216
1217 void LBDatabase::GetPrevLBData(int& lb_type, double& lb_max_avg_ratio, double&
1218     remote_local_comm_ratio) {
1219   lb_type = adaptive_struct.last_lb_type;
1220   lb_max_avg_ratio = 1;
1221   remote_local_comm_ratio = 1;
1222   GetLBDataForLB(lb_type, lb_max_avg_ratio, remote_local_comm_ratio);
1223 }
1224
1225 void LBDatabase::GetLBDataForLB(int lb_type, double& lb_max_avg_ratio, double&
1226     remote_local_comm_ratio) {
1227   if (lb_type == 0) {
1228     lb_max_avg_ratio = adaptive_struct.greedy_info.max_avg_ratio;
1229   } else if (lb_type == 1) {
1230     lb_max_avg_ratio = adaptive_struct.refine_info.max_avg_ratio;
1231   } else if (lb_type == 2) {
1232     remote_local_comm_ratio = adaptive_struct.comm_info.remote_local_ratio;
1233   } else if (lb_type == 3) {
1234     remote_local_comm_ratio =
1235        adaptive_struct.comm_refine_info.remote_local_ratio;
1236   }
1237 }
1238
1239 /*
1240   callable from user's code
1241 */
1242 void TurnManualLBOn()
1243 {
1244 #if CMK_LBDB_ON
1245    LBDatabase * myLbdb = LBDatabase::Object();
1246    if (myLbdb) {
1247      myLbdb->TurnManualLBOn();
1248    }
1249    else {
1250      LBDatabase::manualOn = 1;
1251    }
1252 #endif
1253 }
1254
1255 void TurnManualLBOff()
1256 {
1257 #if CMK_LBDB_ON
1258    LBDatabase * myLbdb = LBDatabase::Object();
1259    if (myLbdb) {
1260      myLbdb->TurnManualLBOff();
1261    }
1262    else {
1263      LBDatabase::manualOn = 0;
1264    }
1265 #endif
1266 }
1267
1268 extern "C" void LBTurnInstrumentOn() {
1269 #if CMK_LBDB_ON
1270   if (CkpvAccess(lbdatabaseInited))
1271     LBDatabase::Object()->CollectStatsOn();
1272   else
1273     _lb_args.statsOn() = 1;
1274 #endif
1275 }
1276
1277 extern "C" void LBTurnInstrumentOff() {
1278 #if CMK_LBDB_ON
1279   if (CkpvAccess(lbdatabaseInited))
1280     LBDatabase::Object()->CollectStatsOff();
1281   else
1282     _lb_args.statsOn() = 0;
1283 #endif
1284 }
1285 void LBClearLoads() {
1286 #if CMK_LBDB_ON
1287   LBDatabase::Object()->ClearLoads();
1288 #endif
1289 }
1290
1291 void LBTurnPredictorOn(LBPredictorFunction *model) {
1292 #if CMK_LBDB_ON
1293   LBDatabase::Object()->PredictorOn(model);
1294 #endif
1295 }
1296
1297 void LBTurnPredictorOn(LBPredictorFunction *model, int wind) {
1298 #if CMK_LBDB_ON
1299   LBDatabase::Object()->PredictorOn(model, wind);
1300 #endif
1301 }
1302
1303 void LBTurnPredictorOff() {
1304 #if CMK_LBDB_ON
1305   LBDatabase::Object()->PredictorOff();
1306 #endif
1307 }
1308
1309 void LBChangePredictor(LBPredictorFunction *model) {
1310 #if CMK_LBDB_ON
1311   LBDatabase::Object()->ChangePredictor(model);
1312 #endif
1313 }
1314
1315 void LBSetPeriod(double second) {
1316 #if CMK_LBDB_ON
1317   if (CkpvAccess(lbdatabaseInited))
1318     LBDatabase::Object()->SetLBPeriod(second);
1319   else
1320     _lb_args.lbperiod() = second;
1321 #endif
1322 }
1323
1324 #include "LBDatabase.def.h"
1325
1326 /*@}*/