Adding some new multicast strategies.
[charm.git] / src / ck-com / OneTimeMulticastStrategy.C
1 /**
2    @addtogroup ComlibCharmStrategy
3    @{
4    @file
5
6 */
7
8
9 #include "OneTimeMulticastStrategy.h"
10 #include <string>
11
12 CkpvExtern(CkGroupID, cmgrID);
13
14 OneTimeMulticastStrategy::OneTimeMulticastStrategy()
15   : Strategy(), CharmStrategy() {
16   //  ComlibPrintf("OneTimeMulticastStrategy constructor\n");
17   setType(ARRAY_STRATEGY);
18 }
19
20 OneTimeMulticastStrategy::~OneTimeMulticastStrategy() {
21 }
22
23 void OneTimeMulticastStrategy::pup(PUP::er &p){
24   Strategy::pup(p);
25   CharmStrategy::pup(p);
26 }
27
28
29 /** Called when the user invokes the entry method on the delegated proxy. */
30 void OneTimeMulticastStrategy::insertMessage(CharmMessageHolder *cmsg){
31   if(cmsg->dest_proc != IS_SECTION_MULTICAST && cmsg->sec_id == NULL) { 
32     CkAbort("OneTimeMulticastStrategy can only be used with an array section proxy");
33   }
34     
35   // Create a multicast message containing all information about remote destination objects 
36   int needSort = 0;
37   ComlibMulticastMsg * multMsg = sinfo.getNewMulticastMessage(cmsg, needSort, getInstance());
38   
39   // local multicast will re-extract a list of local destination objects (FIXME to make this more efficient)
40   localMulticast(cmsg);
41   
42   // The remote multicast method will send the message to the remote PEs, as specified in multMsg
43   remoteMulticast(multMsg, true);
44    
45   delete cmsg;    
46 }
47
48
49
50 /** Deliver the message to the local elements. */
51 void OneTimeMulticastStrategy::localMulticast(CharmMessageHolder *cmsg) {
52   CkSectionID *sec_id = cmsg->sec_id;
53   CkVec< CkArrayIndexMax > localIndices;
54   sinfo.getLocalIndices(sec_id->_nElems, sec_id->_elems, sec_id->_cookie.aid, localIndices);
55   deliverToIndices(cmsg->getCharmMessage(), localIndices );
56 }
57
58
59
60
61
62 /** 
63     Forward multicast message to our successor processors in the spanning tree. 
64     Uses CmiSyncListSendAndFree for delivery to this strategy's OneTimeMulticastStrategy::handleMessage method.
65 */
66 void OneTimeMulticastStrategy::remoteMulticast(ComlibMulticastMsg * multMsg, bool rootPE) {
67
68   envelope *env = UsrToEnv(multMsg);
69     
70   int npes;
71   int *pelist;   
72   
73   /// The index into the PE list in the message
74   int myIndex = -10000; 
75   const int totalDestPEs = multMsg->nPes;
76   const int myPe = CkMyPe();
77   
78   // Find my index in the list of all destination PEs
79   if(rootPE){
80     myIndex = -1;
81   } else {
82     for (int i=0; i<totalDestPEs; ++i) {
83       if(multMsg->indicesCount[i].pe == myPe){
84         myIndex = i;
85         break;
86       }
87     }
88   }
89   
90   CkAssert(myIndex != -10000); // Sanity check
91     
92   determineNextHopPEs(multMsg, myIndex, pelist, npes );
93   
94   if(npes == 0) {
95     CmiFree(env);
96     return;
97   }
98   
99   CmiSetHandler(env, CkpvAccess(comlib_handler));
100   ((CmiMsgHeaderBasic *) env)->stratid = getInstance();  
101   CkPackMessage(&env);
102
103   //Collect Multicast Statistics
104   RECORD_SENDM_STATS(getInstance(), env->getTotalsize(), pelist, npes);
105   
106
107 #if DEBUG
108   for(int i=0;i<npes;i++){
109     CkPrintf("[%d] Multicast to %d  rootPE=%d\n", CkMyPe(), pelist[i], (int)rootPE);
110   }
111 #endif
112
113   //  if(npes > 0)
114   CmiSyncListSendAndFree(npes, pelist, env->getTotalsize(), (char*)env);
115   
116   delete[] pelist;
117 }
118
119
120 /** 
121     Fill in pelist and npes to which the multicast message will be forwarded from this PE.
122     Caller should delete pelist if npes>0.
123 */
124 void OneTimeMulticastStrategy::determineNextHopPEs(ComlibMulticastMsg * multMsg, int myIndex, int * &pelist, int &npes ) {
125   if(myIndex==-1){
126     // We are at a root node of the spanning tree. 
127     // We will forward the message to all other PEs in the destination list.
128     npes = multMsg->nPes;
129     
130     pelist = new int[npes];
131     for (int i=0; i<npes; ++i) {
132       pelist[i] = multMsg->indicesCount[i].pe;
133     }
134   } else {
135     // We are at a leaf node of the spanning tree. 
136     npes = 0;
137   }
138   
139 }
140
141
142
143
144 /** 
145     Receive an incoming multicast message(sent from OneTimeMulticastStrategy::remoteMulticast).
146     Deliver the message to all local elements 
147 */
148 void OneTimeMulticastStrategy::handleMessage(void *msg){
149   envelope *env = (envelope *)msg;
150   CkUnpackMessage(&env);
151   
152   ComlibMulticastMsg* multMsg = (ComlibMulticastMsg*)EnvToUsr(env);
153   
154   // Don't use msg after this point. Instead use the unpacked env
155   
156   RECORD_RECV_STATS(getInstance(), env->getTotalsize(), env->getSrcPe());
157   
158   // Deliver to objects marked as local in the message
159   int localElems;
160   envelope *newenv;
161   CkArrayIndexMax *local_idx_list;  
162   sinfo.unpack(env, localElems, local_idx_list, newenv);
163   ComlibMulticastMsg *newmsg = (ComlibMulticastMsg *)EnvToUsr(newenv);  
164   deliverToIndices(newmsg, localElems, local_idx_list );
165   
166   // Forward on to other processors if necessary
167   remoteMulticast( multMsg, false);
168
169 }
170
171
172
173
174
175 /** 
176     Fill in pelist and npes to which the multicast message will be forwarded from this PE.
177     Caller should delete pelist if npes>0.
178 */
179 void OneTimeRingMulticastStrategy::determineNextHopPEs(ComlibMulticastMsg * multMsg, int myIndex, int * &pelist, int &npes ) {
180   const int totalDestPEs = multMsg->nPes;
181   const int myPe = CkMyPe();
182
183   if(myIndex == totalDestPEs-1){
184     // Final PE won't send to anyone
185     npes = 0;
186     return;
187   } else {
188     // All non-final PEs will send to next PE in list
189     npes = 1;
190     pelist = new int[1];
191     pelist[0] = multMsg->indicesCount[myIndex+1].pe;
192   }
193
194 }
195
196
197
198
199 /** 
200     Fill in pelist and npes to which the multicast message will be forwarded from this PE.
201     Caller should delete pelist if npes>0.
202 */
203 void OneTimeTreeMulticastStrategy::determineNextHopPEs(ComlibMulticastMsg * multMsg, int myIndex, int * &pelist, int &npes ) {
204   const int totalDestPEs = multMsg->nPes;
205   const int myPe = CkMyPe();
206   
207   // The logical indices start at 0 = root node. Logical index i corresponds to the entry i+1 in the array of PEs in the message
208   
209   // All non-final PEs will send to next PE in list
210   int sendLogicalIndexStart = degree*(myIndex+1) + 1;       // inclusive
211   int sendLogicalIndexEnd = sendLogicalIndexStart + degree - 1;   // inclusive
212   
213   if(sendLogicalIndexEnd-1 >= totalDestPEs){
214     sendLogicalIndexEnd = totalDestPEs;
215   }
216
217   int numSend = sendLogicalIndexEnd - sendLogicalIndexStart + 1;
218   if(numSend <= 0){
219     npes = 0;
220     return;
221   }
222   
223
224 #if DEBUG
225   if(numSend > 0)
226     CkPrintf("Tree logical index %d sending to logical %d to %d (totalDestPEs excluding root=%d)  numSend=%d\n",
227              myIndex+1, sendLogicalIndexStart, sendLogicalIndexEnd, totalDestPEs, numSend);
228 #endif
229
230   npes = numSend;
231   pelist = new int[npes];
232   
233   for(int i=0;i<numSend;i++){
234     CkAssert(sendLogicalIndexStart-1+i < totalDestPEs);
235     pelist[i] = multMsg->indicesCount[sendLogicalIndexStart-1+i].pe;
236 #if DEBUG
237     CkPrintf("Tree logical index %d sending to PE %d\n", myIndex+1, pelist[i]);
238 #endif
239     CkAssert(pelist[i] < CkNumPes());
240   }
241   
242 }
243
244
245
246 /*@}*/