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