Several new changes
[charm.git] / src / ck-com / ComlibStrategy.C
1
2 #include "charm++.h"
3 #include "envelope.h"
4
5 //calls ComlibNotifyMigrationDone(). Even compiles when -module comlib
6 //is not included. Hack to make loadbalancer work without comlib
7 //currently.
8 CkpvDeclare(int, migrationDoneHandlerID);
9
10 //Class that defines the entry methods that a Charm level strategy
11 //must define.  To write a new strategy inherit from this class and
12 //define the virtual methods.  Every strategy can also define its own
13 //constructor and have any number of arguments. Also call the parent
14 //class methods in those methods.
15
16 void CharmStrategy::insertMessage(MessageHolder *mh){
17     insertMessage((CharmMessageHolder *)mh);
18 }
19
20 void CharmStrategy::pup(PUP::er &p) {
21     Strategy::pup(p);
22     p | nginfo;
23     p | ginfo;
24     p | ainfo;
25     p | forwardOnMigration;
26     p | mflag;
27 }
28
29 CharmMessageHolder::CharmMessageHolder(char * msg, int proc) 
30     : MessageHolder((char *)UsrToEnv(msg), proc, 
31                     UsrToEnv(msg)->getTotalsize()){
32     
33     sec_id = NULL;    
34 }
35
36 CharmMessageHolder::~CharmMessageHolder() { 
37 }
38
39 void CharmMessageHolder::pup(PUP::er &p) {
40
41     //    CkPrintf("In CharmMessageHolder::pup \n"); 
42
43     MessageHolder::pup(p);
44
45     //Sec ID depends on the message
46     //Currently this pup is only being used for remote messages
47     sec_id = NULL;
48 }
49
50 PUPable_def(CharmStrategy);
51 PUPable_def(CharmMessageHolder);
52
53 ComlibNodeGroupInfo::ComlibNodeGroupInfo() {
54     isNodeGroup = 0;
55     ngid.setZero();
56 };
57
58 void ComlibNodeGroupInfo::pup(PUP::er &p) {
59     p | isNodeGroup;
60     p | ngid;
61 }
62
63 ComlibGroupInfo::ComlibGroupInfo() {
64     
65     isSrcGroup = 0;
66     isDestGroup = 0;
67     nsrcpes = 0;
68     ndestpes = 0;
69     srcpelist = NULL;
70     destpelist = NULL;
71     sgid.setZero();
72     dgid.setZero();
73 };
74
75 ComlibGroupInfo::~ComlibGroupInfo() {
76     if(nsrcpes > 0 && srcpelist != NULL)
77         delete [] srcpelist;
78
79     if(ndestpes > 0 && destpelist != NULL)
80         delete [] destpelist;
81 }
82
83 void ComlibGroupInfo::pup(PUP::er &p){
84
85     p | sgid;
86     p | dgid;
87     p | nsrcpes;
88     p | ndestpes;
89
90     p | isSrcGroup;
91     p | isDestGroup;
92
93     if(p.isUnpacking()) {
94         if(nsrcpes > 0) 
95             srcpelist = new int[nsrcpes];
96
97         if(ndestpes > 0) 
98             destpelist = new int[ndestpes];
99     }
100
101     if(nsrcpes > 0) 
102         p(srcpelist, nsrcpes);
103
104     if(ndestpes > 0) 
105         p(destpelist, ndestpes);
106 }
107
108 void ComlibGroupInfo::setSourceGroup(CkGroupID gid, int *pelist, 
109                                          int npes) {
110     this->sgid = gid;
111     srcpelist = pelist;
112     nsrcpes = npes;
113     isSrcGroup = 1;
114
115     if(nsrcpes == 0) {
116         nsrcpes = CkNumPes();
117         srcpelist = new int[nsrcpes];
118         for(int count =0; count < nsrcpes; count ++)
119             srcpelist[count] = count;
120     }
121 }
122
123 void ComlibGroupInfo::getSourceGroup(CkGroupID &gid, int *&pelist, 
124                                          int &npes){
125     gid = this->sgid;
126     npes = nsrcpes;
127
128     pelist = new int [nsrcpes];
129     memcpy(pelist, srcpelist, npes * sizeof(int));
130 }
131
132 void ComlibGroupInfo::getSourceGroup(CkGroupID &gid){
133     gid = this->sgid;
134 }
135
136 void ComlibGroupInfo::setDestinationGroup(CkGroupID gid, int *pelist, 
137                                          int npes) {
138     this->dgid = gid;
139     destpelist = pelist;
140     ndestpes = npes;
141     isDestGroup = 1;
142
143     if(ndestpes == 0) {
144         ndestpes = CkNumPes();
145         destpelist = new int[ndestpes];
146         for(int count =0; count < ndestpes; count ++)
147             destpelist[count] = count;
148     }
149 }
150
151 void ComlibGroupInfo::getDestinationGroup(CkGroupID &gid, int *&pelist, 
152                                          int &npes){
153     gid = this->dgid;
154     npes = ndestpes;
155
156     pelist = new int [ndestpes];
157     memcpy(pelist, destpelist, npes * sizeof(int));
158 }
159
160 void ComlibGroupInfo::getDestinationGroup(CkGroupID &gid){
161     gid = this->dgid;
162 }
163
164 void ComlibGroupInfo::getCombinedPeList(int *&pelist, int &npes) {
165     int count = 0;        
166     pelist = 0;
167     npes = 0;
168
169     pelist = new int[CkNumPes()];
170     if(nsrcpes == 0 || ndestpes == 0) {
171         npes = CkNumPes();        
172         for(count = 0; count < CkNumPes(); count ++) 
173             pelist[count] = count;                         
174     }
175     else {        
176         npes = ndestpes;
177         memcpy(pelist, destpelist, npes * sizeof(int));
178         
179         //Add source processors to the destination processors
180         //already obtained
181         for(int count = 0; count < nsrcpes; count++) {
182             int p = srcpelist[count];
183
184             for(count = 0; count < npes; count ++)
185                 if(pelist[count] == p)
186                     break;
187
188             if(count == npes)
189                 pelist[npes ++] = p;
190         }                        
191     }
192 }
193
194 ComlibArrayInfo::ComlibArrayInfo() {
195
196     src_aid.setZero();
197     nSrcIndices = -1;
198     src_elements = NULL;
199     isSrcArray = 0;
200
201     dest_aid.setZero();
202     nDestIndices = -1;
203     dest_elements = NULL;
204     isDestArray = 0;
205 };
206
207 ComlibArrayInfo::~ComlibArrayInfo() {
208     //CkPrintf("in comlibarrayinfo destructor\n");
209
210     if(nSrcIndices > 0)
211         delete [] src_elements;
212
213     if(nDestIndices > 0)
214         delete [] dest_elements;
215 }
216
217 void ComlibArrayInfo::setSourceArray(CkArrayID aid, 
218                                          CkArrayIndexMax *e, int nind){
219     src_aid = aid;
220     isSrcArray = 1;    
221     nSrcIndices = nind;
222     if(nind > 0) {
223         src_elements = new CkArrayIndexMax[nind];
224         memcpy(src_elements, e, sizeof(CkArrayIndexMax) * nind);
225     }
226 }
227
228
229 void ComlibArrayInfo::getSourceArray(CkArrayID &aid, 
230                                          CkArrayIndexMax *&e, int &nind){
231     aid = src_aid;
232     nind = nSrcIndices;
233     e = src_elements;
234 }
235
236
237 void ComlibArrayInfo::setDestinationArray(CkArrayID aid, 
238                                           CkArrayIndexMax *e, int nind){
239     dest_aid = aid;
240     isDestArray = 1;    
241     nDestIndices = nind;
242     if(nind > 0) {
243         dest_elements = new CkArrayIndexMax[nind];
244         memcpy(dest_elements, e, sizeof(CkArrayIndexMax) * nind);
245     }
246 }
247
248
249 void ComlibArrayInfo::getDestinationArray(CkArrayID &aid, 
250                                           CkArrayIndexMax *&e, int &nind){
251     aid = dest_aid;
252     nind = nDestIndices;
253     e = dest_elements;
254 }
255
256
257 //Each strategy must define his own Pup interface.
258 void ComlibArrayInfo::pup(PUP::er &p){ 
259     p | src_aid;
260     p | nSrcIndices;
261     p | isSrcArray;
262     
263     p | dest_aid;
264     p | nDestIndices;
265     p | isDestArray;
266     
267     if(p.isUnpacking() && nSrcIndices > 0) 
268         src_elements = new CkArrayIndexMax[nSrcIndices];
269     
270     if(p.isUnpacking() && nDestIndices > 0) 
271         dest_elements = new CkArrayIndexMax[nDestIndices];        
272     
273     if(nSrcIndices > 0)
274         p((char *)src_elements, nSrcIndices * sizeof(CkArrayIndexMax));    
275     else
276         src_elements = NULL;
277
278     if(nDestIndices > 0)
279         p((char *)dest_elements, nDestIndices * sizeof(CkArrayIndexMax));    
280     else
281         dest_elements = NULL;
282
283     localDestIndexVec.resize(0);
284 }
285
286 //Get the list of destination processors
287 void ComlibArrayInfo::getDestinationPeList(int *&destpelist, int &ndestpes) {
288     
289     int count = 0, acount =0;
290     
291     //Destination has not been set
292     if(nDestIndices < 0) {
293         destpelist = 0;
294         ndestpes = 0;
295         return;
296     }
297
298     //Create an array of size CkNumPes()
299     //Inefficient in space
300     ndestpes = CkNumPes();
301     destpelist = new int[ndestpes];
302
303     memset(destpelist, 0, ndestpes * sizeof(int));    
304
305     if(nDestIndices == 0){
306         for(count =0; count < CkNumPes(); count ++) 
307             destpelist[count] = count;             
308         return;
309     }
310
311     ndestpes = 0;
312
313     //Find the last known processors of the array elements
314     for(acount = 0; acount < nDestIndices; acount++) {
315
316         int p = ComlibGetLastKnown(dest_aid, dest_elements[acount]); 
317         
318         for(count = 0; count < ndestpes; count ++)
319             if(destpelist[count] == p)
320                 break;
321         
322         if(count == ndestpes) {
323             destpelist[ndestpes ++] = p; 
324         }       
325     }                            
326 }
327
328 void ComlibArrayInfo::getSourcePeList(int *&srcpelist, int &nsrcpes) {
329     
330     int count = 0, acount =0;
331
332     if(nSrcIndices < 0) {
333         srcpelist = 0;
334         nsrcpes = 0;
335         return;
336     }
337
338     nsrcpes = CkNumPes();
339     srcpelist = new int[nsrcpes];
340
341     memset(srcpelist, 0, nsrcpes * sizeof(int));    
342
343     if(nSrcIndices == 0){
344         for(count =0; count < CkNumPes(); count ++) 
345             srcpelist[count] = count;             
346         return;
347     }
348
349     nsrcpes = 0;
350     for(acount = 0; acount < nSrcIndices; acount++) {
351         
352         int p = ComlibGetLastKnown(src_aid, src_elements[acount]); 
353         
354         for(count = 0; count < nsrcpes; count ++)
355             if(srcpelist[count] == p)
356                 break;
357         
358         if(count == nsrcpes) {
359             srcpelist[nsrcpes ++] = p; 
360         }       
361     }                            
362 }
363
364 void ComlibArrayInfo::getCombinedPeList(int *&pelist, int &npes) {
365
366     int count = 0;        
367     pelist = 0;
368     npes = 0;
369     
370     //Both arrays empty;
371     //Sanity check, this should really not happen
372     if(nSrcIndices < 0 && nDestIndices < 0) {
373         CkAbort("Arrays have not been set\n");
374         return;
375     }
376     
377     //One of them is the entire array Hence set the number of
378     //processors to all Currently does not work for the case where
379     //number of array elements less than number of processors
380     //Will fix it later!
381     if(nSrcIndices == 0 || nDestIndices == 0) {
382         npes = CkNumPes();        
383         pelist = new int[npes];
384         for(count = 0; count < CkNumPes(); count ++) 
385             pelist[count] = count;                         
386     }
387     else {
388         getDestinationPeList(pelist, npes);
389         
390         //Destination has not been set
391         //Strategy does not care about destination
392         //Is an error case
393         if(npes == 0)
394             pelist = new int[CkNumPes()];
395         
396         //Add source processors to the destination processors
397         //already obtained
398         for(int acount = 0; acount < nSrcIndices; acount++) {
399             int p = ComlibGetLastKnown(src_aid, src_elements[acount]);
400
401             for(count = 0; count < npes; count ++)
402                 if(pelist[count] == p)
403                     break;
404             if(count == npes)
405                 pelist[npes ++] = p;
406         }                        
407     }
408 }
409
410 void ComlibArrayInfo::localBroadcast(envelope *env) {
411     //Insert all local elements into a vector
412     if(localDestIndexVec.size()==0 && !dest_aid.isZero()) {
413         CkArray *dest_array = CkArrayID::CkLocalBranch(dest_aid);
414         
415         if(nDestIndices == 0){            
416             dest_array->getComlibArrayListener()->getLocalIndices
417                 (localDestIndexVec);
418         }
419         else {
420             for(int count = 0; count < nDestIndices; count++) {
421                 if(ComlibGetLastKnown(dest_aid, dest_elements[count])
422                    == CkMyPe())
423                     localDestIndexVec.insertAtEnd(dest_elements[count]);
424             }
425         }
426     }
427
428     ComlibArrayInfo::localMulticast(&localDestIndexVec, env);
429 }
430
431 /*
432   This method multicasts the message to all the indices in vec.  It
433   also takes care to check if the entry method is readonly or not? If
434   readonly (nokeep) the message is not copied.
435
436   It also makes sure that the entry methods are logged in projections
437   and that the array manager is notified about array element
438   migrations.  Hence this function should be used extensively in the
439   communication library strategies */
440
441 #include "register.h"
442 void ComlibArrayInfo::localMulticast(CkVec<CkArrayIndexMax>*vec,
443                                      envelope *env){
444
445     //Multicast the messages to all elements in vec
446     int nelements = vec->size();
447     if(nelements == 0) {
448         CmiFree(env);
449         return;
450     }
451
452     void *msg = EnvToUsr(env);
453     int ep = env->getsetArrayEp();
454     CkUnpackMessage(&env);
455
456     CkArrayID dest_aid = env->getsetArrayMgr();
457     env->setPacked(0);
458     env->getsetArrayHops()=1;
459     env->setUsed(0);
460
461     CkArrayIndexMax idx;
462     
463     for(int count = 0; count < nelements-1; count ++){
464         idx = (*vec)[count];
465         //if(comm_debug) idx.print();
466
467         env->getsetArrayIndex() = idx;
468         
469         CkArray *a=(CkArray *)_localBranch(dest_aid);
470         if(_entryTable[ep]->noKeep)
471             a->deliver((CkArrayMessage *)msg, CkDeliver_inline, CK_MSG_KEEP);
472         else {
473             void *newmsg = CkCopyMsg(&msg);
474             a->deliver((CkArrayMessage *)newmsg, CkDeliver_queue);
475         }
476
477     }
478
479     idx = (*vec)[nelements-1];
480     //if(comm_debug) idx.print();
481     env->getsetArrayIndex() = idx;
482     
483     CkArray *a=(CkArray *)_localBranch(dest_aid);
484     if(_entryTable[ep]->noKeep) {
485         a->deliver((CkArrayMessage *)msg, CkDeliver_inline, CK_MSG_KEEP);
486         CmiFree(env);
487     }
488     else
489         a->deliver((CkArrayMessage *)msg, CkDeliver_queue);
490 }
491
492 /* Delivers a message to an array element, making sure that
493    projections is notified */
494 void ComlibArrayInfo::deliver(envelope *env){
495     
496     env->setUsed(0);
497     env->getsetArrayHops()=1;
498     CkUnpackMessage(&env);
499     
500     CkArray *a=(CkArray *)_localBranch(env->getsetArrayMgr());
501     a->deliver((CkArrayMessage *)EnvToUsr(env), CkDeliver_queue);    
502 }
503
504 void ComlibNotifyMigrationDone() {
505     if(CkpvInitialized(migrationDoneHandlerID)) 
506         if(CkpvAccess(migrationDoneHandlerID) > 0) {
507             char *msg = (char *)CmiAlloc(CmiReservedHeaderSize);
508             CmiSetHandler(msg, CkpvAccess(migrationDoneHandlerID));
509 #if CMK_BLUEGENE_CHARM
510             // bluegene charm should avoid directly calling converse
511             CmiSyncSendAndFree(CkMyPe(), CmiReservedHeaderSize, msg);
512 #else
513             CmiHandleMessage(msg);
514 #endif
515         }
516 }
517
518
519 //Stores the location of many array elements used by the
520 //strategies.  Since hash table returns a reference to the object
521 //and for an int that will be 0, the actual value stored is pe +
522 //CkNumPes so 0 would mean processor -CkNumPes which is invalid.
523 CkpvDeclare(ClibLocationTableType *, locationTable);
524
525 CkpvDeclare(CkArrayIndexMax, cache_index);
526 CkpvDeclare(int, cache_pe);
527 CkpvDeclare(CkArrayID, cache_aid);
528
529 int ComlibGetLastKnown(CkArrayID aid, CkArrayIndexMax idx) {
530     //CProxy_ComlibManager cgproxy(CkpvAccess(cmgrID));
531     //return (cgproxy.ckLocalBranch())->getLastKnown(aid, idx);
532
533     if(!CpvInitialized(locationTable)) {
534         CkAbort("Uninitialized table\n");
535     }
536     CkAssert(CkpvAccess(locationTable) != NULL);
537
538     if(CkpvAccess(cache_index) == idx && CkpvAccess(cache_aid) == aid)
539         return CkpvAccess(cache_pe);
540
541     ClibGlobalArrayIndex cidx;
542     cidx.aid = aid;
543     cidx.idx = idx;
544     int pe = CkpvAccess(locationTable)->get(cidx);
545     
546     if(pe == 0) {
547         //Array element does not exist in the table
548         
549         CkArray *array = CkArrayID::CkLocalBranch(aid);
550         pe = array->lastKnown(idx) + CkNumPes();
551         CkpvAccess(locationTable)->put(cidx) = pe;
552     }
553     //CkPrintf("last pe = %d \n", pe - CkNumPes());
554     
555     CkpvAccess(cache_index) = idx;
556     CkpvAccess(cache_aid) = aid;
557     CkpvAccess(cache_pe) = pe - CkNumPes();
558
559     return pe - CkNumPes();
560 }