Adding a new simple Comlib Multicast strategy that does not cache array section infor...
[charm.git] / src / ck-com / ComlibStrategy.C
1 /**
2    @addtogroup CharmComlib
3    @{
4    @file
5    Implementations of ComlibStrategy.h
6 */
7
8 #include "ComlibStrategy.h"
9 #include "register.h"
10
11
12 void CharmStrategy::pup(PUP::er &p) {
13   //Strategy::pup(p);
14     p | nginfo;
15     p | ginfo;
16     p | ainfo;
17     //p | forwardOnMigration;
18     p | mflag;
19     p | onFinish;
20 }
21
22
23
24
25
26 /** Deliver a message to a set of indices using the array manager. Indices can be local or remote. */
27 void CharmStrategy::deliverToIndices(void *msg, int numDestIdxs, const CkArrayIndexMax* indices ){
28   
29   envelope *env = UsrToEnv(msg);
30   
31   CkArrayID destination_aid = env->getsetArrayMgr();
32   CkArray *a=(CkArray *)_localBranch(destination_aid);
33   int ep = env->getsetArrayEp();
34
35   //  CkPrintf("Delivering to %d objects\n", numDestIdxs);
36
37   if(numDestIdxs > 0){
38         
39     // SEND to all destination objects except the last one
40     for(int i=0; i<numDestIdxs-1;i++){
41       env->getsetArrayIndex() = indices[i];
42       
43       if(_entryTable[ep]->noKeep)
44         // don't make a copy for [nokeep] entry methods
45         a->deliver((CkArrayMessage *)msg, CkDeliver_inline, CK_MSG_KEEP);
46       else {
47         void *newmsg = CkCopyMsg(&msg);
48         a->deliver((CkArrayMessage *)newmsg, CkDeliver_queue);
49       }
50     }
51     
52     // SEND to the final destination object
53     env->getsetArrayIndex() = indices[numDestIdxs-1];
54     
55     if(_entryTable[ep]->noKeep){
56       a->deliver((CkArrayMessage *)msg, CkDeliver_inline, CK_MSG_KEEP);
57       CmiFree(env); // runtime frees the [nokeep] messages
58     }
59     else {
60       a->deliver((CkArrayMessage *)msg, CkDeliver_queue);
61     }
62     
63   }
64 }
65
66
67
68
69
70
71
72
73 void CharmMessageHolder::pup(PUP::er &p) {
74
75     //    CkPrintf("In CharmMessageHolder::pup \n"); 
76
77     MessageHolder::pup(p);
78
79     //Sec ID depends on the message
80     //Currently this pup is only being used for remote messages
81     sec_id = NULL;
82 }
83
84 //PUPable_def(CharmStrategy);
85 PUPable_def(CharmMessageHolder);
86
87 ComlibNodeGroupInfo::ComlibNodeGroupInfo() {
88     isNodeGroup = 0;
89     ngid.setZero();
90 };
91
92 void ComlibNodeGroupInfo::pup(PUP::er &p) {
93     p | isNodeGroup;
94     p | ngid;
95 }
96
97 ComlibGroupInfo::ComlibGroupInfo() {
98     
99     isSrcGroup = 0;
100     isDestGroup = 0;
101     nsrcpes = 0;
102     ndestpes = 0;
103     srcpelist = NULL;
104     destpelist = NULL;
105     sgid.setZero();
106     dgid.setZero();
107 };
108
109 ComlibGroupInfo::~ComlibGroupInfo() {
110     if(nsrcpes > 0 && srcpelist != NULL)
111         delete [] srcpelist;
112
113     if(ndestpes > 0 && destpelist != NULL)
114         delete [] destpelist;
115 }
116
117 void ComlibGroupInfo::pup(PUP::er &p){
118
119     p | sgid;
120     p | dgid;
121     p | nsrcpes;
122     p | ndestpes;
123
124     p | isSrcGroup;
125     p | isDestGroup;
126
127     if(p.isUnpacking()) {
128         if(nsrcpes > 0) 
129             srcpelist = new int[nsrcpes];
130
131         if(ndestpes > 0) 
132             destpelist = new int[ndestpes];
133     }
134
135     if(nsrcpes > 0) 
136         p(srcpelist, nsrcpes);
137
138     if(ndestpes > 0) 
139         p(destpelist, ndestpes);
140 }
141
142 void ComlibGroupInfo::setSourceGroup(CkGroupID gid, int *pelist, 
143                                          int npes) {
144     this->sgid = gid;
145     srcpelist = pelist;
146     nsrcpes = npes;
147     isSrcGroup = 1;
148
149     if(nsrcpes == 0) {
150         nsrcpes = CkNumPes();
151         srcpelist = new int[nsrcpes];
152         for(int count =0; count < nsrcpes; count ++)
153             srcpelist[count] = count;
154     }
155 }
156
157 void ComlibGroupInfo::getSourceGroup(CkGroupID &gid, int *&pelist, 
158                                          int &npes){
159     gid = this->sgid;
160     npes = nsrcpes;
161
162     pelist = new int [nsrcpes];
163     memcpy(pelist, srcpelist, npes * sizeof(int));
164 }
165
166 void ComlibGroupInfo::getSourceGroup(CkGroupID &gid){
167     gid = this->sgid;
168 }
169
170 void ComlibGroupInfo::setDestinationGroup(CkGroupID gid, int *pelist, 
171                                          int npes) {
172     this->dgid = gid;
173     destpelist = pelist;
174     ndestpes = npes;
175     isDestGroup = 1;
176
177     if(ndestpes == 0) {
178         ndestpes = CkNumPes();
179         destpelist = new int[ndestpes];
180         for(int count =0; count < ndestpes; count ++)
181             destpelist[count] = count;
182     }
183 }
184
185 void ComlibGroupInfo::getDestinationGroup(CkGroupID &gid, int *&pelist, 
186                                          int &npes) {
187     gid = this->dgid;
188     npes = ndestpes;
189
190     pelist = new int [ndestpes];
191     memcpy(pelist, destpelist, npes * sizeof(int));
192 }
193
194 void ComlibGroupInfo::getDestinationGroup(CkGroupID &gid) {
195     gid = this->dgid;
196 }
197
198 int *ComlibGroupInfo::getCombinedCountList() {
199   int *result = new int[CkNumPes()];
200   int i;
201   for (i=0; i<CkNumPes(); ++i) result[i] = 0;
202   if (nsrcpes != 0) {
203     for (i=0; i<nsrcpes; ++i) result[srcpelist[i]] |= 1;
204   } else {
205     for (i=0; i<CkNumPes(); ++i) result[i] |= 1;
206   }
207   if (ndestpes != 0) {
208     for (i=0; i<ndestpes; ++i) result[destpelist[i]] |= 2;
209   } else {
210     for (i=0; i<CkNumPes(); ++i) result[i] |= 2;
211   }
212   return result;
213 }
214
215 /*
216 void ComlibGroupInfo::getCombinedPeList(int *&pelist, int &npes) {
217     int count = 0;        
218     pelist = 0;
219     npes = 0;
220
221     pelist = new int[CkNumPes()];
222     if(nsrcpes == 0 || ndestpes == 0) {
223         npes = CkNumPes();        
224         for(count = 0; count < CkNumPes(); count ++) 
225             pelist[count] = count;                         
226     }
227     else {        
228         npes = ndestpes;
229         memcpy(pelist, destpelist, npes * sizeof(int));
230         
231         //Add source processors to the destination processors
232         //already obtained
233         for(int count = 0; count < nsrcpes; count++) {
234             int p = srcpelist[count];
235
236             for(count = 0; count < npes; count ++)
237                 if(pelist[count] == p)
238                     break;
239
240             if(count == npes)
241                 pelist[npes ++] = p;
242         }                        
243     }
244 }
245 */
246
247 ComlibArrayInfo::ComlibArrayInfo() {
248         
249     src_aid.setZero();
250     //nSrcIndices = -1;
251     //src_elements = NULL;
252     isAllSrc = 0;
253     totalSrc = 0;
254     isSrcArray = 0;
255
256     dest_aid.setZero();
257     //nDestIndices = -1;
258     //dest_elements = NULL;
259     isAllDest = 0;
260     totalDest = 0;
261     isDestArray = 0;
262 };
263
264 /*
265 ComlibArrayInfo::~ComlibArrayInfo() {
266     //CkPrintf("in comlibarrayinfo destructor\n");
267
268     if(nSrcIndices > 0)
269         delete [] src_elements;
270
271     if(nDestIndices > 0)
272         delete [] dest_elements;
273 }
274 */
275
276 /// Set the  source array used for this strategy. 
277 /// The list of array indices should be the whole portion of the array involved in the strategy.
278 /// The non-local array elements will be cleaned up inside purge() at migration of the strategy
279 void ComlibArrayInfo::setSourceArray(CkArrayID aid, 
280                                          CkArrayIndexMax *e, int nind){
281     src_aid = aid;
282     isSrcArray = 1;
283     /*
284     nSrcIndices = nind;
285     if(nind > 0) {
286         src_elements = new CkArrayIndexMax[nind];
287         memcpy(src_elements, e, sizeof(CkArrayIndexMax) * nind);
288     }
289     */
290     src_elements.removeAll();
291     
292     for (int i=0; i<nind; ++i) src_elements.push_back(e[i]);
293     
294     if (src_elements.size() == 0) 
295         isAllSrc = 1;
296     else 
297         isAllSrc = 0;
298     
299     totalSrc = src_elements.size();
300     
301 }
302
303
304 void ComlibArrayInfo::getSourceArray(CkArrayID &aid, 
305                                          CkArrayIndexMax *&e, int &nind){
306     aid = src_aid;
307     nind = src_elements.length();//nSrcIndices;
308     e = src_elements.getVec();//src_elements;
309 }
310
311
312 void ComlibArrayInfo::setDestinationArray(CkArrayID aid, 
313                                           CkArrayIndexMax *e, int nind){
314     dest_aid = aid;
315     isDestArray = 1;
316     /*
317     nDestIndices = nind;
318     if(nind > 0) {
319         dest_elements = new CkArrayIndexMax[nind];
320         memcpy(dest_elements, e, sizeof(CkArrayIndexMax) * nind);
321     }
322     */
323     dest_elements.removeAll();
324     for (int i=0; i<nind; ++i) dest_elements.push_back(e[i]);
325
326     if (dest_elements.size() == 0) 
327         isAllDest = 1;
328     else 
329         isAllDest = 0;
330     
331     totalDest = dest_elements.size();
332     
333 }
334
335
336 void ComlibArrayInfo::getDestinationArray(CkArrayID &aid, 
337                                           CkArrayIndexMax *&e, int &nind){
338     aid = dest_aid;
339     nind = dest_elements.length();
340     e = dest_elements.getVec();
341 }
342
343 /// @TODO fix the pup!
344 //Each strategy must define his own Pup interface.
345 void ComlibArrayInfo::pup(PUP::er &p){ 
346     p | src_aid;
347     //p | nSrcIndices;
348     p | isSrcArray;
349     p | isAllSrc;
350     p | totalSrc;
351     p | src_elements;
352     
353     p | dest_aid;
354     //p | nDestIndices;
355     p | isDestArray;
356     p | isAllDest;
357     p | totalDest;
358     p | dest_elements;
359
360     if (p.isPacking() || p.isUnpacking()) {
361       // calling purge both during packing (at the end) and during unpacking
362       // allows this code to be executed both on processor 0 (where the object
363       // is created) and on every other processor where it arrives through PUP.
364       purge();
365     }
366
367     /*    
368     if(p.isUnpacking() && nSrcIndices > 0) 
369         src_elements = new CkArrayIndexMax[nSrcIndices];
370     
371     if(p.isUnpacking() && nDestIndices > 0) 
372         dest_elements = new CkArrayIndexMax[nDestIndices];        
373     
374     if(nSrcIndices > 0)
375         p((char *)src_elements, nSrcIndices * sizeof(CkArrayIndexMax));    
376     else
377         src_elements = NULL;
378
379     if(nDestIndices > 0)
380         p((char *)dest_elements, nDestIndices * sizeof(CkArrayIndexMax));    
381     else
382         dest_elements = NULL;
383
384     localDestIndexVec.resize(0);
385     */
386     
387 }
388
389 void ComlibArrayInfo::newElement(CkArrayID &id, const CkArrayIndex &idx) {
390   ComlibPrintf("ComlibArrayInfo::newElement\n");
391   if (isAllSrc && id==src_aid) src_elements.push_back(idx);
392   if (isAllDest && id==dest_aid) dest_elements.push_back(idx);
393 }
394
395 void ComlibArrayInfo::purge() {
396         int i;
397         CkArray *a;
398 //      ComlibPrintf("[%d] ComlibArrayInfo::purge srcArray=%d (%d), destArray=%d (%d)\n",CkMyPe(),isSrcArray,isAllSrc,isDestArray,isAllDest);
399         if (isSrcArray) {
400                 a = (CkArray *)_localBranch(src_aid);
401                 if (isAllSrc) {
402                         // gather the information of all the elements that are currenly present here
403                         ComlibElementIterator iter(&src_elements);
404                         a->getLocMgr()->iterate(iter);
405
406                         // register to ComlibArrayListener for this array id
407 //                      ComlibManagerRegisterArrayListener(src_aid, this);
408                 } else {
409                         // delete all the elements of which we are not homePe
410                         for (i=src_elements.size()-1; i>=0; --i) {
411                                 if (a->homePe(src_elements[i]) != CkMyPe()) { 
412                                         
413 //                                      ComlibPrintf("[%d] removing home=%d src element %d  i=%d\n", CkMyPe(),a->homePe(src_elements[i]), src_elements[i].data()[0], i);
414                                         src_elements.remove(i); 
415                                 }
416                         }
417                 }
418         }
419         if (isDestArray) {
420                 a = (CkArray *)_localBranch(dest_aid);
421                 if (isAllDest) {
422                         // gather the information of all the elements that are currenly present here
423                         ComlibElementIterator iter(&dest_elements);
424                         a->getLocMgr()->iterate(iter);
425
426                         // register to ComlibArrayListener for this array id
427 //                      ComlibManagerRegisterArrayListener(dest_aid, this);
428                 } else {
429                         // delete all the elements of which we are not homePe
430                         for (i=dest_elements.size()-1; i>=0; --i) {
431                                 if (a->homePe(dest_elements[i]) != CkMyPe()) {
432 //                                      ComlibPrintf("[%d] removing home=%d dest element %d  i=%d\n", CkMyPe(), a->homePe(dest_elements[i]), dest_elements[i].data()[0], i);
433                                         dest_elements.remove(i); 
434                                 }
435                         }
436                 }
437         }
438 }
439
440 int *ComlibArrayInfo::getCombinedCountList() {
441   int *result = new int[CkNumPes()];
442   int i;
443   for (i=0; i<CkNumPes(); ++i) result[i] = 0;
444   CkArray *a = (CkArray *)_localBranch(src_aid);
445   if (src_elements.size() != 0) {
446     for (i=0; i<src_elements.size(); ++i) result[a->homePe(src_elements[i])] |= 1;
447   } else {
448     for (i=0; i<CkNumPes(); ++i) result[i] |= 1;
449   }
450   a = (CkArray *)_localBranch(dest_aid);
451   if (dest_elements.size() != 0) {
452     for (i=0; i<dest_elements.size(); ++i) result[a->homePe(dest_elements[i])] |= 2;
453   } else {
454     for (i=0; i<CkNumPes(); ++i) result[i] |= 2;
455   }
456   return result;
457 }
458
459 /*
460 //Get the list of destination processors
461 void ComlibArrayInfo::getDestinationPeList(int *&destpelist, int &ndestpes) {
462     
463     int count = 0, acount =0;
464     
465     //Destination has not been set
466     if(nDestIndices < 0) {
467         destpelist = 0;
468         ndestpes = 0;
469         return;
470     }
471
472     //Create an array of size CkNumPes()
473     //Inefficient in space
474     ndestpes = CkNumPes();
475     destpelist = new int[ndestpes];
476
477     memset(destpelist, 0, ndestpes * sizeof(int));    
478
479     if(nDestIndices == 0){
480         for(count =0; count < CkNumPes(); count ++) 
481             destpelist[count] = count;             
482         return;
483     }
484
485     ndestpes = 0;
486     CkArray *amgr = CkArrayID::CkLocalBranch(dest_aid);
487
488     //Find the last known processors of the array elements
489     for(acount = 0; acount < nDestIndices; acount++) {
490
491       //int p = ComlibGetLastKnown(dest_aid, dest_elements[acount]); 
492         int p = amgr->lastKnown(dest_elements[acount]);
493         
494         for(count = 0; count < ndestpes; count ++)
495             if(destpelist[count] == p)
496                 break;
497         
498         if(count == ndestpes) {
499             destpelist[ndestpes ++] = p; 
500         }       
501     }                            
502 }
503
504 void ComlibArrayInfo::getSourcePeList(int *&srcpelist, int &nsrcpes) {
505     
506     int count = 0, acount =0;
507
508     if(nSrcIndices < 0) {
509         srcpelist = 0;
510         nsrcpes = 0;
511         return;
512     }
513
514     nsrcpes = CkNumPes();
515     srcpelist = new int[nsrcpes];
516
517     memset(srcpelist, 0, nsrcpes * sizeof(int));    
518
519     if(nSrcIndices == 0){
520         for(count =0; count < CkNumPes(); count ++) 
521             srcpelist[count] = count;             
522         return;
523     }
524
525     nsrcpes = 0;
526     CkArray *amgr = CkArrayID::CkLocalBranch(src_aid);
527
528     for(acount = 0; acount < nSrcIndices; acount++) {
529         
530       //int p = ComlibGetLastKnown(src_aid, src_elements[acount]); 
531         int p = amgr->lastKnown(src_elements[acount]);
532         
533         for(count = 0; count < nsrcpes; count ++)
534             if(srcpelist[count] == p)
535                 break;
536         
537         if(count == nsrcpes) {
538             srcpelist[nsrcpes ++] = p; 
539         }       
540     }                            
541 }
542
543 void ComlibArrayInfo::getCombinedPeList(int *&pelist, int &npes) {
544
545     int count = 0;        
546     pelist = 0;
547     npes = 0;
548     
549     //Both arrays empty;
550     //Sanity check, this should really not happen
551     if(nSrcIndices < 0 && nDestIndices < 0) {
552         CkAbort("Arrays have not been set\n");
553         return;
554     }
555     
556     //One of them is the entire array Hence set the number of
557     //processors to all Currently does not work for the case where
558     //number of array elements less than number of processors
559     //Will fix it later!
560     if(nSrcIndices == 0 || nDestIndices == 0) {
561         npes = CkNumPes();        
562         pelist = new int[npes];
563         for(count = 0; count < CkNumPes(); count ++) 
564             pelist[count] = count;                         
565     }
566     else {
567         getDestinationPeList(pelist, npes);
568         
569         //Destination has not been set
570         //Strategy does not care about destination
571         //Is an error case
572         if(npes == 0)
573             pelist = new int[CkNumPes()];
574         
575         CkArray *amgr = CkArrayID::CkLocalBranch(src_aid);
576
577         //Add source processors to the destination processors
578         //already obtained
579         for(int acount = 0; acount < nSrcIndices; acount++) {
580           //int p = ComlibGetLastKnown(src_aid, src_elements[acount]);
581             int p = amgr->lastKnown(src_elements[acount]);
582
583             for(count = 0; count < npes; count ++)
584                 if(pelist[count] == p)
585                     break;
586             if(count == npes)
587                 pelist[npes ++] = p;
588         }                        
589     }
590 }
591 */
592
593 /// Broadcast the message to all local elements
594 void ComlibArrayInfo::localBroadcast(envelope *env) {
595   int count = localMulticast(&dest_elements, env);
596   ComlibPrintf("[%d] ComlibArrayInfo::localBroadcast to %d elements (%d non local)\n",CmiMyPe(),dest_elements.size(),count);
597
598 //  char buf[100000];
599 //  buf[0] = '\0';
600 //  for(int i=0;i<dest_elements.size();i++){
601 //        sprintf(buf+strlen(buf), " %d", dest_elements[i].data()[0]);
602 //  }
603 //  ComlibPrintf("dest_elements = %s\n", buf);
604
605 }
606
607 /**
608   This method multicasts the message to all the indices in vec.  It
609   also takes care to check if the entry method is readonly or not. If
610   readonly (nokeep) the message is not copied.
611
612   It also makes sure that the entry methods are logged in projections
613   and that the array manager is notified about array element
614   migrations.  Hence this function should be used extensively in the
615   communication library strategies
616
617   This method is more general than just ComlibArrayInfo dest_aid since it takes
618   the destination array id directly form the message envelope.
619
620   @return the number of destination objects which were not local (information
621   retrieved from the array/location manager)
622 */
623
624 #include "register.h"
625 int ComlibArrayInfo::localMulticast(CkVec<CkArrayIndexMax>*vec,
626                                      envelope *env){
627   int count = 0;
628     //Multicast the messages to all elements in vec
629     int nelements = vec->size();
630     if(nelements == 0) {
631         CmiFree(env);
632         return 0;
633     }
634
635     void *msg = EnvToUsr(env);
636     int ep = env->getsetArrayEp();
637     CkUnpackMessage(&env);
638
639     CkArrayID destination_aid = env->getsetArrayMgr();
640     env->setPacked(0);
641     env->getsetArrayHops()=1;
642     env->setUsed(0);
643
644     CkArrayIndexMax idx;
645
646     //ComlibPrintf("sending to %d elements\n",nelements);
647     for(int i = 0; i < nelements-1; i ++){
648         idx = (*vec)[i];
649         //if(com_debug) idx.print();
650
651         env->getsetArrayIndex() = idx;
652         //ComlibPrintf("sending to: "); idx.print();
653         
654         CkArray *a=(CkArray *)_localBranch(destination_aid);
655         if(_entryTable[ep]->noKeep)
656             count += a->deliver((CkArrayMessage *)msg, CkDeliver_inline, CK_MSG_KEEP);
657         else {
658             void *newmsg = CkCopyMsg(&msg);
659             count += a->deliver((CkArrayMessage *)newmsg, CkDeliver_queue);
660         }
661
662     }
663
664     idx = (*vec)[nelements-1];
665     //if(com_debug) idx.print();
666     env->getsetArrayIndex() = idx;
667     //ComlibPrintf("sending to: "); idx.print();
668     
669     CkArray *a=(CkArray *)_localBranch(destination_aid);
670     if(_entryTable[ep]->noKeep) {
671         count += a->deliver((CkArrayMessage *)msg, CkDeliver_inline, CK_MSG_KEEP);
672         CmiFree(env);
673     }
674     else
675         count += a->deliver((CkArrayMessage *)msg, CkDeliver_queue);
676
677     return count;
678 }
679
680 /** Delivers a message to an array element, making sure that
681     projections is notified */
682 void ComlibArrayInfo::deliver(envelope *env){
683     ComlibPrintf("In ComlibArrayInfo::deliver()\n");
684                 
685     env->setUsed(0);
686     env->getsetArrayHops()=1;
687     CkUnpackMessage(&env);
688     
689     CkArray *a=(CkArray *)_localBranch(env->getsetArrayMgr());
690     a->deliver((CkArrayMessage *)EnvToUsr(env), CkDeliver_queue);
691 }
692
693
694 /*@}*/