Merge branch 'charm' of charmgit:charm into charm
[charm.git] / src / ck-ldb / BaseLB.h
1 /**
2  \defgroup CkLdb  Charm++ Load Balancing Framework 
3 */
4 /*@{*/
5
6 #ifndef BASELB_H
7 #define BASELB_H
8
9 #include "LBDatabase.h"
10
11 #define PER_MESSAGE_SEND_OVERHEAD_DEFAULT   3.5e-5
12 #define PER_BYTE_SEND_OVERHEAD_DEFAULT      8.5e-9
13 #define PER_MESSAGE_RECV_OVERHEAD           0.0
14 #define PER_BYTE_RECV_OVERHEAD              0.0
15
16 /// Base class for all LB strategies.
17 /**
18   BaseLB is the base class for all LB strategy class.
19   it does some tracking about how many lb strategies are created.
20   it also defines some common functions.
21 */
22 class BaseLB: public CBase_BaseLB
23 {
24 protected:
25   int  seqno;
26   const char *lbname;
27   LBDatabase *theLbdb;
28   LDBarrierReceiver receiver;
29   int  notifier;
30   int  startLbFnHdl;
31 private:
32   void initLB(const CkLBOptions &);
33 public:
34   struct ProcStats {            // per processor data
35     int n_objs;                 // number of objects on the processor
36     double pe_speed;            // processor frequency
37     /// total time (total_walltime) = idletime + overhead (bg_walltime)
38     ///                             + object load (obj_walltime)
39     /// walltime and cputime may be different on shared compute nodes
40     /// it is advisable to use walltime in most cases
41     double total_walltime;
42     /// time for which the processor is sitting idle
43     double idletime;
44     /// bg_walltime called background load (overhead in ckgraph.h) is a
45     /// derived quantity: total_walltime - idletime - object load (obj_walltime)
46     double bg_walltime;
47 #if CMK_LB_CPUTIMER
48     double total_cputime;
49     double bg_cputime;
50 #endif
51     // double utilization;
52     int pe;                     // processor id
53     CmiBool available;
54     ProcStats(): n_objs(0), pe_speed(1), total_walltime(0.0), idletime(0.0),
55 #if CMK_LB_CPUTIMER
56                  total_cputime(0.0), bg_cputime(0.0),
57 #endif
58                  bg_walltime(0.0), pe(-1), available(CmiTrue) {}
59     inline void clearBgLoad() {
60       idletime = bg_walltime = 
61 #if CMK_LB_CPUTIMER
62       bg_cputime = 
63 #endif
64       0.0;
65     }
66     inline void pup(PUP::er &p) {
67       p|total_walltime;
68       p|idletime;
69       p|bg_walltime;
70 #if CMK_LB_CPUTIMER
71       p|total_cputime;
72       p|bg_cputime;
73 #endif
74       p|pe_speed;
75       if (_lb_args.lbversion() < 1 && p.isUnpacking()) {
76          double dummy;  p|dummy;    // for old format with utilization
77       }
78       p|available; p|n_objs;
79       if (_lb_args.lbversion()>=2) p|pe; 
80     }
81   };
82
83   /** Passed to the virtual functions Strategy(...) and work(...) */
84   struct LDStats {
85     int count;                  // number of processors in the array "procs"
86     ProcStats *procs;           // processor statistics
87
88     int n_objs;                 // total number of objects in the vector "objData"
89     int n_migrateobjs;          // total number of migratable objects
90     CkVec<LDObjData> objData;   // LDObjData and LDCommData defined in lbdb.h
91     CkVec<int> from_proc;       // current pe an object is on
92     CkVec<int> to_proc;         // new pe you want the object to be on
93
94     int n_comm;                 // number of edges in the vector "commData"
95     CkVec<LDCommData> commData; // communication data - edge list representation
96                                 // of the communication between objects
97
98     int *objHash;               // this a map from the hash for the 4 integer
99                                 // LDObjId to the index in the vector "objData"
100     int  hashSize;
101
102     int complete_flag;          // if this ocg is complete, eg in HybridLB,
103                                 // this LDStats may not be complete
104
105     LDStats(int c=0, int complete_flag=1);
106     /// the functions below should be used to obtain the number of processors
107     /// instead of accessing count directly
108     inline int nprocs() const { return count; }
109     inline int &nprocs() { return count; }
110
111     void assign(int oid, int pe) { CmiAssert(procs[pe].available); to_proc[oid] = pe; }
112     /// build hash table
113     void makeCommHash();
114     void deleteCommHash();
115     /// given an LDObjKey, returns the index in the objData vector
116     /// this index changes every time one does load balancing even within a run
117     int getHash(const LDObjKey &);
118     int getHash(const LDObjid &oid, const LDOMid &mid);
119     int getSendHash(LDCommData &cData);
120     int getRecvHash(LDCommData &cData);
121     void clearCommHash();
122     void clear() {
123       n_objs = n_migrateobjs = n_comm = 0;
124       objData.free();
125       commData.free();
126       from_proc.free();
127       to_proc.free();
128       deleteCommHash();
129     }
130     void clearBgLoad() {
131       for (int i=0; i<nprocs(); i++) procs[i].clearBgLoad();
132     }
133     void computeNonlocalComm(int &nmsgs, int &nbytes);
134     double computeAverageLoad();
135     void normalize_speed();
136     void print();
137     // edit functions
138     void removeObject(int obj);
139     void pup(PUP::er &p);
140     int useMem();
141   };
142
143   BaseLB(const CkLBOptions &opt)  { initLB(opt); }
144   BaseLB(CkMigrateMessage *m):CBase_BaseLB(m) {}
145   virtual ~BaseLB();
146
147   void unregister(); 
148   inline const char *lbName() { return lbname; }
149   inline int step() { return theLbdb->step(); }
150   virtual void turnOff() { CmiAbort("turnOff not implemented"); }
151   virtual void turnOn()  { CmiAbort("turnOn not implemented"); }
152   virtual int  useMem()  { return 0; }
153   virtual void pup(PUP::er &p);
154   virtual void flushStates();
155
156   CkGroupID getGroupID() {return thisgroup;}
157 };
158
159 /// migration decision for an obj.
160 struct MigrateInfo {  
161     int index;   // object index in objData array
162     LDObjHandle obj;
163     int from_pe;
164     int to_pe;
165     int async_arrival;      // if an object is available for immediate migrate
166     MigrateInfo():  async_arrival(0) {}
167     void pup(PUP::er &p) {
168       p | index;
169       p | obj;
170       p | from_pe;
171       p | to_pe;
172       p | async_arrival;
173     }
174 };
175
176 /**
177   message contains the migration decision from LB strategies.
178 */
179 class LBMigrateMsg : public CMessage_LBMigrateMsg {
180 public:
181   int level;                    // which level in hierarchy, used in hybridLB
182
183   int n_moves;                  // number of moves
184   MigrateInfo* moves;
185
186   char * avail_vector;          // processor bit vector
187   int next_lb;                  // next load balancer
188
189   double * expectedLoad;        // expected load for future
190
191 public:
192 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
193         int step;
194         int lbDecisionCount;
195 #endif
196   LBMigrateMsg(): level(0), n_moves(0), next_lb(0) {}
197   void pup(PUP::er &p) {
198     int i;
199     p | level;
200     p | n_moves;
201     // Warning: it relies on the fact that the message has been allocated already
202     // with the correct number of moves!
203     p | next_lb;
204     int numPes = CkNumPes();
205     p | numPes;
206     CkAssert(numPes == CkNumPes());
207     for (i=0; i<n_moves; ++i) p | moves[i];
208     p(avail_vector, numPes);
209     for (i=0; i<numPes; ++i) p | expectedLoad[i];
210   }
211 };
212
213 struct VectorMigrateInfo {  
214     int from_pe;
215     int to_pe;
216     double load;
217     int async_arrival;      // if an object is available for immediate migrate
218     VectorMigrateInfo():  async_arrival(0) {}
219 };
220
221 class LBVectorMigrateMsg : public CMessage_LBVectorMigrateMsg {
222 public:
223   int level;                    // which level in hierarchy, used in hybridLB
224
225   int n_moves;                  // number of moves
226   VectorMigrateInfo* moves;
227
228 public:
229   LBVectorMigrateMsg(): level(0), n_moves(0) {}
230 };
231
232 // for a FooLB, the following macro defines these functions for each LB:
233 // CreateFooLB():        create BOC and register with LBDatabase with a 
234 //                       sequence ticket,
235 // AllocateFooLB():      allocate the class instead of a BOC
236 // static void lbinit(): an init call for charm module registration
237 #if CMK_LBDB_ON
238
239 #define CreateLBFunc_Def(x, str)                \
240 void Create##x(void) {  \
241   int seqno = LBDatabaseObj()->getLoadbalancerTicket(); \
242   CProxy_##x::ckNew(CkLBOptions(seqno));        \
243 }       \
244 \
245 BaseLB *Allocate##x(void) { \
246   return new x((CkMigrateMessage*)NULL);        \
247 }       \
248 \
249 static void lbinit(void) {      \
250   LBRegisterBalancer(#x,        \
251                      Create##x, \
252                      Allocate##x,       \
253                      str);      \
254 }
255
256 #else           /* CMK_LBDB_ON */
257
258 #define CreateLBFunc_Def(x, str)        \
259 void Create##x(void) {}         \
260 BaseLB *Allocate##x(void) { return NULL; }      \
261 static void lbinit(void) {}
262
263 #endif          /* CMK_LBDB_ON */
264
265 #endif
266
267 /*@}*/