Merging
[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     int is_prev_lb_refine;
106     double after_lb_max;
107     double after_lb_avg;
108     double local_comm;
109     double remote_comm;
110
111     LDStats(int c=0, int complete_flag=1);
112     /// the functions below should be used to obtain the number of processors
113     /// instead of accessing count directly
114     inline int nprocs() const { return count; }
115     inline int &nprocs() { return count; }
116
117     void assign(int oid, int pe) { CmiAssert(procs[pe].available); to_proc[oid] = pe; }
118     /// build hash table
119     void makeCommHash();
120     void deleteCommHash();
121     /// given an LDObjKey, returns the index in the objData vector
122     /// this index changes every time one does load balancing even within a run
123     int getHash(const LDObjKey &);
124     int getHash(const LDObjid &oid, const LDOMid &mid);
125     int getSendHash(LDCommData &cData);
126     int getRecvHash(LDCommData &cData);
127     void clearCommHash();
128     void clear() {
129       n_objs = n_migrateobjs = n_comm = 0;
130       objData.free();
131       commData.free();
132       from_proc.free();
133       to_proc.free();
134       deleteCommHash();
135     }
136     void clearBgLoad() {
137       for (int i=0; i<nprocs(); i++) procs[i].clearBgLoad();
138     }
139     void computeNonlocalComm(int &nmsgs, int &nbytes);
140     double computeAverageLoad();
141     void normalize_speed();
142     void print();
143     // edit functions
144     void removeObject(int obj);
145     void pup(PUP::er &p);
146     int useMem();
147   };
148
149   BaseLB(const CkLBOptions &opt)  { initLB(opt); }
150   BaseLB(CkMigrateMessage *m):CBase_BaseLB(m) {}
151   virtual ~BaseLB();
152
153   void unregister(); 
154   inline const char *lbName() { return lbname; }
155   inline int step() { return theLbdb->step(); }
156   virtual void turnOff() { CmiAbort("turnOff not implemented"); }
157   virtual void turnOn()  { CmiAbort("turnOn not implemented"); }
158   virtual int  useMem()  { return 0; }
159   virtual void pup(PUP::er &p);
160   virtual void flushStates();
161
162   CkGroupID getGroupID() {return thisgroup;}
163 };
164
165 /// migration decision for an obj.
166 struct MigrateInfo {  
167     int index;   // object index in objData array
168     LDObjHandle obj;
169     int from_pe;
170     int to_pe;
171     int async_arrival;      // if an object is available for immediate migrate
172     MigrateInfo():  async_arrival(0) {}
173     void pup(PUP::er &p) {
174       p | index;
175       p | obj;
176       p | from_pe;
177       p | to_pe;
178       p | async_arrival;
179     }
180 };
181
182 /**
183   message contains the migration decision from LB strategies.
184 */
185 class LBMigrateMsg : public CMessage_LBMigrateMsg {
186 public:
187   int level;                    // which level in hierarchy, used in hybridLB
188
189   int n_moves;                  // number of moves
190   MigrateInfo* moves;
191
192   char * avail_vector;          // processor bit vector
193   int next_lb;                  // next load balancer
194
195   double * expectedLoad;        // expected load for future
196
197 public:
198 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
199         int step;
200         int lbDecisionCount;
201 #endif
202   LBMigrateMsg(): level(0), n_moves(0), next_lb(0) {}
203   void pup(PUP::er &p) {
204     int i;
205     p | level;
206     p | n_moves;
207     // Warning: it relies on the fact that the message has been allocated already
208     // with the correct number of moves!
209     p | next_lb;
210     int numPes = CkNumPes();
211     p | numPes;
212     CkAssert(numPes == CkNumPes());
213     for (i=0; i<n_moves; ++i) p | moves[i];
214     p(avail_vector, numPes);
215     for (i=0; i<numPes; ++i) p | expectedLoad[i];
216   }
217 };
218
219 struct VectorMigrateInfo {  
220     int from_pe;
221     int to_pe;
222     double load;
223     int async_arrival;      // if an object is available for immediate migrate
224     VectorMigrateInfo():  async_arrival(0) {}
225 };
226
227 class LBVectorMigrateMsg : public CMessage_LBVectorMigrateMsg {
228 public:
229   int level;                    // which level in hierarchy, used in hybridLB
230
231   int n_moves;                  // number of moves
232   VectorMigrateInfo* moves;
233
234 public:
235   LBVectorMigrateMsg(): level(0), n_moves(0) {}
236 };
237
238 // for a FooLB, the following macro defines these functions for each LB:
239 // CreateFooLB():        create BOC and register with LBDatabase with a 
240 //                       sequence ticket,
241 // AllocateFooLB():      allocate the class instead of a BOC
242 // static void lbinit(): an init call for charm module registration
243 #if CMK_LBDB_ON
244
245 #define CreateLBFunc_Def(x, str)                \
246 void Create##x(void) {  \
247   int seqno = LBDatabaseObj()->getLoadbalancerTicket(); \
248   CProxy_##x::ckNew(CkLBOptions(seqno));        \
249 }       \
250 \
251 BaseLB *Allocate##x(void) { \
252   return new x((CkMigrateMessage*)NULL);        \
253 }       \
254 \
255 static void lbinit(void) {      \
256   LBRegisterBalancer(#x,        \
257                      Create##x, \
258                      Allocate##x,       \
259                      str);      \
260 }
261
262 #else           /* CMK_LBDB_ON */
263
264 #define CreateLBFunc_Def(x, str)        \
265 void Create##x(void) {}         \
266 BaseLB *Allocate##x(void) { return NULL; }      \
267 static void lbinit(void) {}
268
269 #endif          /* CMK_LBDB_ON */
270
271 #endif
272
273 /*@}*/