a modification in LDStats database, changed pointer to array to CkVec for easier...
[charm.git] / src / ck-ldb / BaseLB.C
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7
8 /**
9  * \addtogroup CkLdb
10 */
11 /*@{*/
12
13 #include "charm++.h"
14 #include "BaseLB.h"
15 #include "LBSimulation.h"
16
17 #if CMK_LBDB_ON
18
19 void BaseLB::initLB(const CkLBOptions &opt) {
20   seqno = opt.getSeqNo();
21   CkpvAccess(numLoadBalancers) ++;
22 /*
23   if (CkpvAccess(numLoadBalancers) - CkpvAccess(hasNullLB) > 1)
24     CmiAbort("Error: try to create more than one load balancer strategies!");
25 */
26   theLbdb = CProxy_LBDatabase(_lbdb).ckLocalBranch();
27   lbname = "Unknown";
28   // register this load balancer to LBDatabase at the sequence number
29   theLbdb->addLoadbalancer(this, seqno);
30 }
31
32 BaseLB::~BaseLB() {
33   CkpvAccess(numLoadBalancers) --;
34 }
35
36 void BaseLB::unregister() {
37   theLbdb->RemoveLocalBarrierReceiver(receiver);
38   CkpvAccess(numLoadBalancers) --;
39 }
40
41 void BaseLB::pup(PUP::er &p) { 
42   IrrGroup::pup(p); 
43   p|seqno;
44   if (p.isUnpacking())
45   {
46     if (CkMyPe()==0) {
47       if (seqno!=-1) {
48         int newseq = LBDatabaseObj()->getLoadbalancerTicket();
49         CmiAssert(newseq == seqno);
50       }
51     }
52     initLB(seqno);
53   }
54 }
55
56 void BaseLB::flushStates() {
57   theLbdb->ClearLoads();
58 }
59
60 #else
61 BaseLB::~BaseLB() {} 
62 void BaseLB::initLB(const CkLBOptions &) {}
63 void BaseLB::unregister() {}
64 void BaseLB::pup(PUP::er &p) {}
65 void BaseLB::flushStates() {}
66 #endif
67
68 static inline int i_abs(int c) { return c>0?c:-c; }
69
70 // assume integer is 32 bits
71 inline static int ObjKey(const LDObjid &oid, const int hashSize) {
72   // make sure all positive
73   return (((i_abs(oid.id[2]) & 0x7F)<<24)
74          |((i_abs(oid.id[1]) & 0xFF)<<16)
75          |i_abs(oid.id[0])) % hashSize;
76 }
77
78 BaseLB::LDStats::LDStats()
79         : n_objs(0), n_migrateobjs(0), n_comm(0), 
80           objHash(NULL) 
81 {
82   procs = new ProcStats[CkNumPes()]; 
83 }
84
85 const static unsigned int doublingPrimes[] = {
86 3,
87 7,
88 17,
89 37,
90 73,
91 157,
92 307,
93 617,
94 1217,
95 2417,
96 4817,
97 9677,
98 20117,
99 40177,
100 80177,
101 160117,
102 320107,
103 640007,
104 1280107,
105 2560171,
106 5120117,
107 10000079,
108 20000077,
109 40000217,
110 80000111,
111 160000177,
112 320000171,
113 640000171,
114 1280000017,
115 2560000217u,
116 4200000071u
117 /* extra primes larger than an unsigned 32-bit integer:
118 51200000077,
119 100000000171,
120 200000000171,
121 400000000171,
122 800000000117,
123 1600000000021,
124 3200000000051,
125 6400000000081,
126 12800000000003,
127 25600000000021,
128 51200000000077,
129 100000000000067,
130 200000000000027,
131 400000000000063,
132 800000000000017,
133 1600000000000007,
134 3200000000000059,
135 6400000000000007,
136 12800000000000009,
137 25600000000000003,
138 51200000000000023,
139 100000000000000003,
140 200000000000000003,
141 400000000000000013,
142 800000000000000119,
143 1600000000000000031,
144 3200000000000000059 //This is a 62-bit number
145 */
146 };
147
148 //This routine returns an arbitrary prime larger than x
149 static unsigned int primeLargerThan(unsigned int x)
150 {
151         int i=0;
152         while (doublingPrimes[i]<=x) i++;
153         return doublingPrimes[i];
154 }
155
156 void BaseLB::LDStats::makeCommHash() {
157   // hash table is already build
158   if (objHash) return;
159    
160   int i;
161   hashSize = n_objs*2;
162   hashSize = primeLargerThan(hashSize);
163   objHash = new int[hashSize];
164   for(i=0;i<hashSize;i++)
165         objHash[i] = -1;
166    
167   for(i=0;i<n_objs;i++){
168         const LDObjid &oid = objData[i].objID();
169         int hash = ObjKey(oid, hashSize);
170         CmiAssert(hash != -1);
171         while(objHash[hash] != -1)
172             hash = (hash+1)%hashSize;
173         objHash[hash] = i;
174   }
175 }
176
177 void BaseLB::LDStats::deleteCommHash() {
178   if (objHash) delete [] objHash;
179   objHash = NULL;
180 }
181
182 int BaseLB::LDStats::getHash(const LDObjid &oid, const LDOMid &mid)
183 {
184 #if CMK_LBDB_ON
185     CmiAssert(hashSize > 0);
186     int hash = ObjKey(oid, hashSize);
187
188     for(int id=0;id<hashSize;id++){
189         int index = (id+hash)%hashSize;
190         if (index == -1 || objHash[index] == -1) return -1;
191         if (LDObjIDEqual(objData[objHash[index]].objID(), oid) &&
192             LDOMidEqual(objData[objHash[index]].omID(), mid))
193             return objHash[index];
194     }
195     //  CkPrintf("not found \n");
196 #endif
197     return -1;
198 }
199
200 int BaseLB::LDStats::getHash(const LDObjKey &objKey)
201 {
202   const LDObjid &oid = objKey.objID();
203   const LDOMid  &mid = objKey.omID();
204   return getHash(oid, mid);
205 }
206
207 int BaseLB::LDStats::getSendHash(LDCommData &cData)
208 {
209   if (cData.sendHash == -1) {
210     cData.sendHash = getHash(cData.sender);
211   }
212   return cData.sendHash;
213 }
214
215 int BaseLB::LDStats::getRecvHash(LDCommData &cData)
216 {
217   if (cData.recvHash == -1) {
218     cData.recvHash =  getHash(cData.receiver.get_destObj());
219   }
220   return cData.recvHash;
221 }
222
223 void BaseLB::LDStats::print()
224 {
225 #if CMK_LBDB_ON
226   int i;
227   CkPrintf("------------- Processor Data: %d -------------\n", count);
228   for(int pe=0; pe < count; pe++) {
229     struct ProcStats &proc = procs[pe];
230
231     CkPrintf(
232       "Proc %d Sp %d Total(wall,cpu) = (%f %f) Idle = %f Bg = (%f %f) nObjs = %d\n",
233       pe,proc.pe_speed,proc.total_walltime,proc.total_cputime,
234       proc.idletime,proc.bg_walltime,proc.bg_cputime,proc.n_objs);
235   }
236
237   CkPrintf("------------- Object Data: %d objects -------------\n", n_objs);
238   for(i=0; i < n_objs; i++) {
239       LDObjData &odata = objData[i];
240       CkPrintf("Object %d\n",i);
241       CkPrintf("     id = %d %d %d %d\n",odata.objID().id[0],odata.objID().id[1
242 ], odata.objID().id[2], odata.objID().id[3]);
243       CkPrintf("  OM id = %d\t",odata.omID().id);
244       CkPrintf("   Mig. = %d\n",odata.migratable);
245       CkPrintf("    CPU = %f\t",odata.cpuTime);
246       CkPrintf("   Wall = %f\n",odata.wallTime);
247   }
248
249   CkPrintf("------------- Comm Data: %d records -------------\n", n_comm);
250   CkVec<LDCommData> &cdata = commData;
251   for(i=0; i < n_comm; i++) {
252       CkPrintf("Link %d\n",i);
253
254       LDObjid &sid = cdata[i].sender.objID();
255       if (cdata[i].from_proc())
256         CkPrintf("    sender PE = %d\t",cdata[i].src_proc);
257       else
258         CkPrintf("    sender id = %d:[%d %d %d %d]\t",
259                  cdata[i].sender.omID().id,sid.id[0], sid.id[1], sid.id[2], sid.id[3]);
260
261       LDObjid &rid = cdata[i].receiver.get_destObj().objID();
262       if (cdata[i].recv_type() == LD_PROC_MSG)
263         CkPrintf("  receiver PE = %d\n",cdata[i].receiver.proc());
264       else      
265         CkPrintf("  receiver id = %d:[%d %d %d %d]\n",
266                  cdata[i].receiver.get_destObj().omID().id,rid.id[0],rid.id[1],rid.id[2],rid.id[3]);
267       
268       CkPrintf("     messages = %d\t",cdata[i].messages);
269       CkPrintf("        bytes = %d\n",cdata[i].bytes);
270   }
271   CkPrintf("------------- Object to PE mapping -------------\n");
272   for (i=0; i<n_objs; i++) CkPrintf(" %d", from_proc[i]);
273   CkPrintf("\n");
274 #endif
275 }
276
277 double BaseLB::LDStats::computeAverageLoad()
278 {
279   int i, numAvail=0;
280   double total = 0;
281   for (i=0; i<n_objs; i++) total += objData[i].wallTime;
282                                                                                 
283   for (i=0; i<count; i++)
284     if (procs[i].available == CmiTrue) {
285         total += procs[i].bg_walltime;
286         numAvail++;
287     }
288                                                                                 
289   double averageLoad = total/numAvail;
290   return averageLoad;
291 }
292
293 void BaseLB::LDStats::pup(PUP::er &p)
294 {
295   int i;
296   p(count);  
297   p(n_objs);
298   p(n_migrateobjs);
299   p(n_comm);
300   if (p.isUnpacking()) {
301     // user can specify simulated processors other than the real # of procs.
302     int maxpe = count>LBSimulation::simProcs?count:LBSimulation::simProcs;
303     procs = new ProcStats[maxpe];
304     objData.resize(n_objs);
305     commData.resize(n_comm);
306     from_proc.resize(n_objs);
307     to_proc.resize(n_objs);
308     objHash = NULL;
309   }
310   // ignore the background load when unpacking if the user change the # of procs
311   // otherwise load everything
312   if (p.isUnpacking() && LBSimulation::procsChanged) {
313     ProcStats dummy;
314     for (i=0; i<count; i++) p|dummy; 
315   }
316   else
317     for (i=0; i<count; i++) p|procs[i];
318   for (i=0; i<n_objs; i++) p|objData[i]; 
319   for (i=0; i<n_objs; i++) p|from_proc[i]; 
320   for (i=0; i<n_objs; i++) p|to_proc[i]; 
321   // reset to_proc when unpacking
322   if (p.isUnpacking())
323     for (i=0; i<n_objs; i++) to_proc[i] = from_proc[i];
324   for (i=0; i<n_comm; i++) p|commData[i];
325   if (p.isUnpacking())
326     count = LBSimulation::simProcs;
327   if (p.isUnpacking()) {
328     objHash = NULL;
329   }
330 }
331
332 int BaseLB::LDStats::useMem() { 
333   // calculate the memory usage of this LB (superclass).
334   return sizeof(LDStats) + sizeof(ProcStats)*count + 
335          (sizeof(LDObjData) + 2*sizeof(int)) * n_objs +
336          sizeof(LDCommData) * n_comm;
337 }
338
339 #include "BaseLB.def.h"
340
341 /*@}*/