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