A few bug fixes related to the mlogft machine.
[charm.git] / src / ck-ldb / LBDatabase.C
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7
8 /**
9  * \addtogroup CkLdb
10 */
11 /*@{*/
12
13 #include "converse.h"
14
15 /*
16  * This C++ file contains the Charm stub functions
17  */
18
19 #include "LBDatabase.h"
20 #include "LBSimulation.h"
21 #include "topology.h"
22
23 #include "NullLB.h"
24
25 CkGroupID _lbdb;
26
27 CkpvDeclare(int, numLoadBalancers);  /**< num of lb created */
28 CkpvDeclare(int, hasNullLB);         /**< true if NullLB is created */
29 CkpvDeclare(int, lbdatabaseInited);  /**< true if lbdatabase is inited */
30
31 // command line options
32 CkLBArgs _lb_args;
33 int _lb_predict=0;
34 int _lb_predict_delay=10;
35 int _lb_predict_window=20;
36
37 // registry class stores all load balancers linked and created at runtime
38 class LBDBRegistry {
39 friend class LBDBInit;
40 friend class LBDatabase;
41 private:
42   // table for all available LBs linked in
43   struct LBDBEntry {
44     const char *name;
45     LBCreateFn  cfn;
46     LBAllocFn   afn;
47     const char *help;
48     int         shown;          // if 0, donot show in help page
49     LBDBEntry(): name(0), cfn(0), afn(0), help(0), shown(1) {}
50     LBDBEntry(int) {}
51     LBDBEntry(const char *n, LBCreateFn cf, LBAllocFn af, 
52               const char *h, int show=1):
53       name(n), cfn(cf), afn(af), help(h), shown(show) {};
54   };
55   CkVec<LBDBEntry> lbtables;            // a list of available LBs linked
56   CkVec<const char *>   compile_lbs;    // load balancers at compile time
57   CkVec<const char *>   runtime_lbs;    // load balancers at run time
58 public:
59   LBDBRegistry() {}
60   void displayLBs()
61   {
62     CmiPrintf("\nAvailable load balancers:\n");
63     for (int i=0; i<lbtables.length(); i++) {
64       LBDBEntry &entry = lbtables[i];
65       if (entry.shown) CmiPrintf("* %s: %s\n", entry.name, entry.help);
66     }
67     CmiPrintf("\n");
68   }
69   void addEntry(const char *name, LBCreateFn fn, LBAllocFn afn, const char *help, int shown) {
70     lbtables.push_back(LBDBEntry(name, fn, afn, help, shown));
71   }
72   void addCompiletimeBalancer(const char *name) {
73     compile_lbs.push_back(name); 
74   }
75   void addRuntimeBalancer(const char *name) {
76     runtime_lbs.push_back(name); 
77   }
78   LBCreateFn search(const char *name) {
79     char *ptr = strpbrk((char *)name, ":,");
80     int slen = ptr!=NULL?ptr-name:strlen(name);
81     for (int i=0; i<lbtables.length(); i++)
82       if (0==strncmp(name, lbtables[i].name, slen)) return lbtables[i].cfn;
83     return NULL;
84   }
85   LBAllocFn getLBAllocFn(const char *name) {
86     char *ptr = strpbrk((char *)name, ":,");
87     int slen = ptr-name;
88     for (int i=0; i<lbtables.length(); i++)
89       if (0==strncmp(name, lbtables[i].name, slen)) return lbtables[i].afn;
90     return NULL;
91   }
92 };
93
94 static LBDBRegistry lbRegistry;
95
96 void LBDefaultCreate(const char *lbname)
97 {
98   lbRegistry.addCompiletimeBalancer(lbname);
99 }
100
101 // default is to show the helper
102 void LBRegisterBalancer(const char *name, LBCreateFn fn, LBAllocFn afn, const char *help, int shown)
103 {
104   lbRegistry.addEntry(name, fn, afn, help, shown);
105 }
106
107 LBAllocFn getLBAllocFn(char *lbname) {
108     return lbRegistry.getLBAllocFn(lbname);
109 }
110
111 // create a load balancer group using the strategy name
112 static void createLoadBalancer(const char *lbname)
113 {
114     LBCreateFn fn = lbRegistry.search(lbname);
115     if (!fn) {    // invalid lb name
116       CmiPrintf("Abort: Unknown load balancer: '%s'!\n", lbname);
117       lbRegistry.displayLBs();    // display help page
118       CkAbort("Abort");
119     }
120     // invoke function to create load balancer 
121     fn();
122 }
123
124 LBDBInit::LBDBInit(CkArgMsg *m)
125 {
126 #if CMK_LBDB_ON
127   _lbdb = CProxy_LBDatabase::ckNew();
128
129   // runtime specified load balancer
130   if (lbRegistry.runtime_lbs.size() > 0) {
131     for (int i=0; i<lbRegistry.runtime_lbs.size(); i++) {
132       const char *balancer = lbRegistry.runtime_lbs[i];
133       createLoadBalancer(balancer);
134     }
135   }
136   else if (lbRegistry.compile_lbs.size() > 0) {
137     for (int i=0; i<lbRegistry.compile_lbs.size(); i++) {
138       const char* balancer = lbRegistry.compile_lbs[i];
139       createLoadBalancer(balancer);
140     }
141   }
142   else {
143     // NullLB is the default when none of above lb created
144     // note user may create his own load balancer in his code manually like
145     // in NAMD, but never mind NullLB can disable itself if there is 
146     // a non NULL LB.
147     createLoadBalancer("NullLB");
148   }
149
150   // simulation mode
151   if (LBSimulation::doSimulation) {
152     CmiPrintf("Charm++> Entering Load Balancer Simulation Mode ... \n");
153     CProxy_LBDatabase(_lbdb).ckLocalBranch()->StartLB();
154   }
155 #endif
156   delete m;
157 }
158
159 // called from init.C
160 void _loadbalancerInit()
161 {
162   CkpvInitialize(int, lbdatabaseInited);
163   CkpvAccess(lbdatabaseInited) = 0;
164   CkpvInitialize(int, numLoadBalancers);
165   CkpvAccess(numLoadBalancers) = 0;
166   CkpvInitialize(int, hasNullLB);
167   CkpvAccess(hasNullLB) = 0;
168
169   char **argv = CkGetArgv();
170   char *balancer = NULL;
171   CmiArgGroup("Charm++","Load Balancer");
172   while (CmiGetArgStringDesc(argv, "+balancer", &balancer, "Use this load balancer")) {
173     if (CkMyRank() == 0)                
174       lbRegistry.addRuntimeBalancer(balancer);   /* lbRegistry is a static */
175   }
176
177   // set up init value for LBPeriod time in seconds
178   // it can also be set by calling LDSetLBPeriod()
179   CmiGetArgDoubleDesc(argv,"+LBPeriod", &_lb_args.lbperiod(),"the minimum time period in seconds allowed for two consecutive automatic load balancing");
180   _lb_args.loop() = CmiGetArgFlagDesc(argv, "+LBLoop", "Use multiple load balancing strategies in loop");
181
182   // now called in cldb.c: CldModuleGeneralInit()
183   // registerLBTopos();
184   CmiGetArgStringDesc(argv, "+LBTopo", &_lbtopo, "define load balancing topology");
185   //Read the K parameter for RefineKLB
186   CmiGetArgIntDesc(argv, "+LBNumMoves", &_lb_args.percentMovesAllowed() , "Percentage of chares to be moved (used by RefineKLB) [0-100]");
187
188   /**************** FUTURE PREDICTOR ****************/
189   _lb_predict = CmiGetArgFlagDesc(argv, "+LBPredictor", "Turn on LB future predictor");
190   CmiGetArgIntDesc(argv, "+LBPredictorDelay", &_lb_predict_delay, "Number of balance steps before learning a model");
191   CmiGetArgIntDesc(argv, "+LBPredictorWindow", &_lb_predict_window, "Number of steps to use to learn a model");
192   if (_lb_predict_window < _lb_predict_delay) {
193     CmiPrintf("LB> Argument LBPredictorWindow less than LBPredictorDelay, fixing\n");
194     _lb_predict_delay = _lb_predict_window;
195   }
196
197   /******************* SIMULATION *******************/
198   // get the step number at which to dump the LB database
199   CmiGetArgIntDesc(argv, "+LBVersion", &_lb_args.lbversion(), "LB database file version number");
200   CmiGetArgIntDesc(argv, "+LBCentPE", &_lb_args.central_pe(), "CentralLB processor");
201   int _lb_dump_activated = 0;
202   if (CmiGetArgIntDesc(argv, "+LBDump", &LBSimulation::dumpStep, "Dump the LB state from this step"))
203     _lb_dump_activated = 1;
204   if (_lb_dump_activated && LBSimulation::dumpStep < 0) {
205     CmiPrintf("LB> Argument LBDump (%d) negative, setting to 0\n",LBSimulation::dumpStep);
206     LBSimulation::dumpStep = 0;
207   }
208   CmiGetArgIntDesc(argv, "+LBDumpSteps", &LBSimulation::dumpStepSize, "Dump the LB state for this amount of steps");
209   if (LBSimulation::dumpStepSize <= 0) {
210     CmiPrintf("LB> Argument LBDumpSteps (%d) too small, setting to 1\n",LBSimulation::dumpStepSize);
211     LBSimulation::dumpStepSize = 1;
212   }
213   CmiGetArgStringDesc(argv, "+LBDumpFile", &LBSimulation::dumpFile, "Set the LB state file name");
214   // get the simulation flag and number. Now the flag can also be avoided by the presence of the number
215   LBSimulation::doSimulation = CmiGetArgIntDesc(argv, "+LBSim", &LBSimulation::simStep, "Read LB state from LBDumpFile since this step");
216   // check for stupid LBSim parameter
217   if (LBSimulation::doSimulation && LBSimulation::simStep < 0) {
218     CmiPrintf("LB> Argument LBSim (%d) invalid, should be >= 0\n");
219     CkExit();
220     return;
221   }
222   CmiGetArgIntDesc(argv, "+LBSimSteps", &LBSimulation::simStepSize, "Read LB state for this number of steps");
223   if (LBSimulation::simStepSize <= 0) {
224     CmiPrintf("LB> Argument LBSimSteps (%d) too small, setting to 1\n",LBSimulation::simStepSize);
225     LBSimulation::simStepSize = 1;
226   }
227
228
229   LBSimulation::simProcs = 0;
230   CmiGetArgIntDesc(argv, "+LBSimProcs", &LBSimulation::simProcs, "Number of target processors.");
231
232   LBSimulation::showDecisionsOnly = 
233     CmiGetArgFlagDesc(argv, "+LBShowDecisions",
234                       "Write to File: Load Balancing Object to Processor Map decisions during LB Simulation");
235
236   // force a global barrier after migration done
237   _lb_args.syncResume() = CmiGetArgFlagDesc(argv, "+LBSyncResume", 
238                   "LB performs a barrier after migration is finished");
239
240   // both +LBDebug and +LBDebug level should work
241   if (!CmiGetArgIntDesc(argv, "+LBDebug", &_lb_args.debug(), 
242                                           "Turn on LB debugging printouts"))
243     _lb_args.debug() = CmiGetArgFlagDesc(argv, "+LBDebug", 
244                                              "Turn on LB debugging printouts");
245
246   // ask to print summary/quality of load balancer
247   _lb_args.printSummary() = CmiGetArgFlagDesc(argv, "+LBPrintSummary",
248                 "Print load balancing result summary");
249
250   // to ignore baclground load
251   _lb_args.ignoreBgLoad() = CmiGetArgFlagDesc(argv, "+LBNoBackground", 
252                       "Load balancer ignores the background load.");
253 #ifdef __BLUEGENE__
254   _lb_args.ignoreBgLoad() = 1;
255 #endif
256   _lb_args.migObjOnly() = CmiGetArgFlagDesc(argv, "+LBObjOnly", 
257                       "Only load balancing migratable objects, ignoring all others.");
258   if (_lb_args.migObjOnly()) _lb_args.ignoreBgLoad() = 1;
259
260   // assume all CPUs are identical
261   _lb_args.samePeSpeed() = CmiGetArgFlagDesc(argv, "+LBSameCpus", 
262                       "Load balancer assumes all CPUs are of same speed.");
263
264   _lb_args.useCpuTime() = CmiGetArgFlagDesc(argv, "+LBUseCpuTime", 
265                       "Load balancer uses CPU time instead of wallclock time.");
266
267   // turn instrumentation off at startup
268   _lb_args.statsOn() = !CmiGetArgFlagDesc(argv, "+LBOff",
269                         "Turn load balancer instrumentation off");
270
271   // turn instrumentation of communicatin off at startup
272   _lb_args.traceComm() = !CmiGetArgFlagDesc(argv, "+LBCommOff",
273                 "Turn load balancer instrumentation of communication off");
274
275   // set alpha and beeta
276   _lb_args.alpha() = PER_MESSAGE_SEND_OVERHEAD_DEFAULT;
277   _lb_args.beeta() = PER_BYTE_SEND_OVERHEAD_DEFAULT;
278   CmiGetArgDoubleDesc(argv,"+LBAlpha", &_lb_args.alpha(),
279                            "per message send overhead");
280   CmiGetArgDoubleDesc(argv,"+LBBeta", &_lb_args.beeta(),
281                            "per byte send overhead");
282
283   if (CkMyPe() == 0) {
284     if (_lb_args.debug()) {
285       CmiPrintf("LB> Load balancer running with verbose mode level %d, period time: %gs, alpha: %es beta: %es.\n", _lb_args.debug(), _lb_args.lbperiod(), _lb_args.alpha(), _lb_args.beeta());
286       CkPrintf("LB> Topology %s\n", _lbtopo);
287     }
288     if (_lb_args.printSummary())
289       CmiPrintf("LB> Load balancer print summary of load balancing result.\n");
290     if (_lb_args.ignoreBgLoad())
291       CmiPrintf("LB> Load balancer ignores processor background load.\n");
292     if (_lb_args.samePeSpeed())
293       CmiPrintf("LB> Load balancer assumes all CPUs are same.\n");
294     if (_lb_args.useCpuTime())
295       CmiPrintf("LB> Load balancer uses CPU time instead of wallclock time.\n");
296     if (LBSimulation::doSimulation)
297       CmiPrintf("LB> Load balancer running in simulation mode on file '%s' version %d.\n", LBSimulation::dumpFile, _lb_args.lbversion());
298     if (_lb_args.statsOn()==0)
299       CkPrintf("LB> Load balancing instrumentation is off.\n");
300     if (_lb_args.traceComm()==0)
301       CkPrintf("LB> Load balancing instrumentation for communication is off.\n");
302     if (_lb_args.migObjOnly())
303       CkPrintf("LB> Load balancing strategy ignores non-migtabale objects.\n");
304   }
305 }
306
307 int LBDatabase::manualOn = 0;
308 char *LBDatabase::avail_vector = NULL;
309 CmiNodeLock avail_vector_lock;
310
311 static double * _expectedLoad = NULL;
312
313 void LBDatabase::initnodeFn()
314 {
315   int proc;
316   int num_proc = CkNumPes();
317   avail_vector= new char[num_proc];
318   for(proc = 0; proc < num_proc; proc++)
319       avail_vector[proc] = 1;
320   avail_vector_lock = CmiCreateLock();
321
322   _expectedLoad = new double[num_proc];
323   for (proc=0; proc<num_proc; proc++) _expectedLoad[proc]=0.0;
324 }
325
326 // called my constructor
327 void LBDatabase::init(void) 
328 {
329   myLDHandle = LDCreate();
330   mystep = 0;
331   nloadbalancers = 0;
332   new_ld_balancer = 0;
333
334   CkpvAccess(lbdatabaseInited) = 1;
335 #if CMK_LBDB_ON
336   if (manualOn) TurnManualLBOn();
337 #endif
338 }
339
340 LBDatabase::LastLBInfo::LastLBInfo()
341 {
342   expectedLoad = _expectedLoad;
343 }
344
345 void LBDatabase::get_avail_vector(char * bitmap) {
346     CmiAssert(bitmap && avail_vector);
347     const int num_proc = CkNumPes();
348     for(int proc = 0; proc < num_proc; proc++){
349       bitmap[proc] = avail_vector[proc];
350     }
351 }
352
353 // new_ld == -1(default) : calcualte a new ld
354 //           -2 : ignore new ld
355 //           >=0: given a new ld
356 void LBDatabase::set_avail_vector(char * bitmap, int new_ld){
357     int assigned = 0;
358     const int num_proc = CkNumPes();
359     if (new_ld == -2) assigned = 1;
360     else if (new_ld >= 0) {
361       CmiAssert(new_ld < num_proc);
362       new_ld_balancer = new_ld;
363       assigned = 1;
364     }
365     CmiAssert(bitmap && avail_vector);
366     for(int count = 0; count < num_proc; count++){
367         avail_vector[count] = bitmap[count];
368         if((bitmap[count] == 1) && !assigned){
369             new_ld_balancer = count;
370             assigned = 1;
371         }
372     }
373 }
374
375 // called in CreateFooLB() when multiple load balancers are created
376 // on PE0, BaseLB of each load balancer applies a ticket number
377 // and broadcast the ticket number to all processors
378 int LBDatabase::getLoadbalancerTicket()  { 
379   int seq = nloadbalancers;
380   nloadbalancers ++;
381   loadbalancers.resize(nloadbalancers); 
382   loadbalancers[seq] = NULL;
383   return seq; 
384 }
385
386 void LBDatabase::addLoadbalancer(BaseLB *lb, int seq) {
387 //  CmiPrintf("[%d] addLoadbalancer for seq %d\n", CkMyPe(), seq);
388   if (seq == -1) return;
389   if (CkMyPe() == 0) {
390     CmiAssert(seq < nloadbalancers);
391     if (loadbalancers[seq]) {
392       CmiPrintf("Duplicate load balancer created at %d\n", seq);
393       CmiAbort("LBDatabase");
394     }
395   }
396   else
397     nloadbalancers ++;
398   loadbalancers.resize(seq+1);
399   loadbalancers[seq] = lb;
400 }
401
402 // switch strategy in order
403 void LBDatabase::nextLoadbalancer(int seq) {
404   if (seq == -1) return;                // -1 means this is the only LB
405   int next = seq+1;
406   if (_lb_args.loop()) {
407     if (next == nloadbalancers) next = 0;
408   }
409   else {
410     if (next == nloadbalancers) next --;  // keep using the last one
411   }
412   if (seq != next) {
413     loadbalancers[seq]->turnOff();
414     CmiAssert(loadbalancers[next]);
415     loadbalancers[next]->turnOn();
416   }
417 }
418
419 // return the seq-th load balancer string name of
420 // it can be specified in either compile time or runtime
421 // runtime has higher priority
422 const char *LBDatabase::loadbalancer(int seq) {
423   if (lbRegistry.runtime_lbs.length()) {
424     CmiAssert(seq < lbRegistry.runtime_lbs.length());
425     return lbRegistry.runtime_lbs[seq];
426   }
427   else {
428     CmiAssert(seq < lbRegistry.compile_lbs.length());
429     return lbRegistry.compile_lbs[seq];
430   }
431 }
432
433 void LBDatabase::pup(PUP::er& p)
434
435   IrrGroup::pup(p); 
436   // the memory should be already allocated
437   int np;
438   if (!p.isUnpacking()) np = CkNumPes();
439   p|np;
440         CmiAssert(avail_vector);
441   // in case number of processors changes
442   if (p.isUnpacking() && np > CkNumPes()) {
443     CmiLock(avail_vector_lock);
444     delete [] avail_vector;
445     avail_vector = new char[np];
446     for (int i=0; i<np; i++) avail_vector[i] = 1;
447     CmiUnlock(avail_vector_lock);
448   }
449   p(avail_vector, np);
450         p|mystep;
451 }
452
453
454 void LBDatabase::EstObjLoad(const LDObjHandle &_h, double cputime)
455 {
456 #if CMK_LBDB_ON
457   LBDB *const db = (LBDB*)(_h.omhandle.ldb.handle);
458   LBObj *const obj = db->LbObj(_h);
459
460   CmiAssert(obj != NULL);
461   obj->setTiming(cputime);
462 #endif
463 }
464
465 /*
466   callable from user's code
467 */
468 void TurnManualLBOn()
469 {
470 #if CMK_LBDB_ON
471    LBDatabase * myLbdb = LBDatabase::Object();
472    if (myLbdb) {
473      myLbdb->TurnManualLBOn();
474    }
475    else {
476      LBDatabase::manualOn = 1;
477    }
478 #endif
479 }
480
481 void TurnManualLBOff()
482 {
483 #if CMK_LBDB_ON
484    LBDatabase * myLbdb = LBDatabase::Object();
485    if (myLbdb) {
486      myLbdb->TurnManualLBOff();
487    }
488    else {
489      LBDatabase::manualOn = 0;
490    }
491 #endif
492 }
493
494 void LBTurnInstrumentOn() { 
495 #if CMK_LBDB_ON
496   if (CkpvAccess(lbdatabaseInited))
497     LBDatabase::Object()->CollectStatsOn(); 
498   else
499     _lb_args.statsOn() = 1;
500 #endif
501 }
502
503 void LBTurnInstrumentOff() { 
504 #if CMK_LBDB_ON
505   if (CkpvAccess(lbdatabaseInited))
506     LBDatabase::Object()->CollectStatsOff(); 
507   else
508     _lb_args.statsOn() = 0;
509 #endif
510 }
511 void LBClearLoads() {
512 #if CMK_LBDB_ON
513   LBDatabase::Object()->ClearLoads(); 
514 #endif
515 }
516
517 void LBTurnPredictorOn(LBPredictorFunction *model) {
518 #if CMK_LBDB_ON
519   LBDatabase::Object()->PredictorOn(model);
520 #endif
521 }
522
523 void LBTurnPredictorOn(LBPredictorFunction *model, int wind) {
524 #if CMK_LBDB_ON
525   LBDatabase::Object()->PredictorOn(model, wind);
526 #endif
527 }
528
529 void LBTurnPredictorOff() {
530 #if CMK_LBDB_ON
531   LBDatabase::Object()->PredictorOff();
532 #endif
533 }
534
535 void LBChangePredictor(LBPredictorFunction *model) {
536 #if CMK_LBDB_ON
537   LBDatabase::Object()->ChangePredictor(model);
538 #endif
539 }
540
541 void LBSetPeriod(double second) {
542 #if CMK_LBDB_ON
543   if (CkpvAccess(lbdatabaseInited))
544     LBDatabase::Object()->SetLBPeriod(second); 
545   else
546     _lb_args.lbperiod() = second;
547 #endif
548 }
549
550 #include "LBDatabase.def.h"
551
552 /*@}*/