Adding some user events to trace the multicasts.
[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   double start = CmiWallTimer();
53   CkSectionID *sec_id = cmsg->sec_id;
54   CkVec< CkArrayIndexMax > localIndices;
55   sinfo.getLocalIndices(sec_id->_nElems, sec_id->_elems, sec_id->_cookie.aid, localIndices);
56   deliverToIndices(cmsg->getCharmMessage(), localIndices );
57   traceUserBracketEvent(10000, start, CmiWallTimer());
58 }
59
60
61
62
63
64 /** 
65     Forward multicast message to our successor processors in the spanning tree. 
66     Uses CmiSyncListSendAndFree for delivery to this strategy's OneTimeMulticastStrategy::handleMessage method.
67 */
68 void OneTimeMulticastStrategy::remoteMulticast(ComlibMulticastMsg * multMsg, bool rootPE) {
69   double start = CmiWallTimer();
70
71   envelope *env = UsrToEnv(multMsg);
72     
73   int npes;
74   int *pelist;   
75   
76   /// The index into the PE list in the message
77   int myIndex = -10000; 
78   const int totalDestPEs = multMsg->nPes;
79   const int myPe = CkMyPe();
80   
81   // Find my index in the list of all destination PEs
82   if(rootPE){
83     myIndex = -1;
84   } else {
85     for (int i=0; i<totalDestPEs; ++i) {
86       if(multMsg->indicesCount[i].pe == myPe){
87         myIndex = i;
88         break;
89       }
90     }
91   }
92   
93   CkAssert(myIndex != -10000); // Sanity check
94   
95   determineNextHopPEs(totalDestPEs, multMsg->indicesCount, myIndex, pelist, npes );
96   
97   if(npes == 0) {
98     traceUserBracketEvent(10001, start, CmiWallTimer());
99     CmiFree(env);
100     return;
101   }
102   
103   CmiSetHandler(env, CkpvAccess(comlib_handler));
104   ((CmiMsgHeaderBasic *) env)->stratid = getInstance();  
105   CkPackMessage(&env);
106
107   //Collect Multicast Statistics
108   RECORD_SENDM_STATS(getInstance(), env->getTotalsize(), pelist, npes);
109   
110
111 #if DEBUG
112   for(int i=0;i<npes;i++){
113     CkPrintf("[%d] Multicast to %d  rootPE=%d\n", CkMyPe(), pelist[i], (int)rootPE);
114   }
115 #endif
116
117   //  if(npes > 0)
118   CmiSyncListSendAndFree(npes, pelist, env->getTotalsize(), (char*)env);
119   
120   delete[] pelist;
121   traceUserBracketEvent(10001, start, CmiWallTimer());
122
123 }
124
125
126
127 /** 
128     Receive an incoming multicast message(sent from OneTimeMulticastStrategy::remoteMulticast).
129     Deliver the message to all local elements 
130 */
131 void OneTimeMulticastStrategy::handleMessage(void *msg){
132   envelope *env = (envelope *)msg;
133   CkUnpackMessage(&env);
134   
135   ComlibMulticastMsg* multMsg = (ComlibMulticastMsg*)EnvToUsr(env);
136   
137   // Don't use msg after this point. Instead use the unpacked env
138   
139   RECORD_RECV_STATS(getInstance(), env->getTotalsize(), env->getSrcPe());
140   
141   // Deliver to objects marked as local in the message
142   int localElems;
143   envelope *newenv;
144   CkArrayIndexMax *local_idx_list;  
145   sinfo.unpack(env, localElems, local_idx_list, newenv);
146   ComlibMulticastMsg *newmsg = (ComlibMulticastMsg *)EnvToUsr(newenv);  
147   deliverToIndices(newmsg, localElems, local_idx_list );
148   
149   // Forward on to other processors if necessary
150   remoteMulticast( multMsg, false);
151
152 }
153
154
155
156
157 void OneTimeMulticastStrategy::determineNextHopPEs(const int totalDestPEs, const ComlibMulticastIndexCount* destPEs, const int myIndex, int * &pelist, int &npes) {
158   if(myIndex==-1){
159     // We are at a root node of the spanning tree. 
160     // We will forward the message to all other PEs in the destination list.
161     npes = totalDestPEs;
162     
163     pelist = new int[npes];
164     for (int i=0; i<npes; ++i) {
165       pelist[i] = destPEs[i].pe;
166     }
167   } else {
168     // We are at a leaf node of the spanning tree. 
169     npes = 0;
170   }
171   
172 }
173
174
175 void OneTimeRingMulticastStrategy::determineNextHopPEs(const int totalDestPEs, const ComlibMulticastIndexCount* destPEs, const int myIndex, int * &pelist, int &npes) {
176   const int myPe = CkMyPe();
177
178   if(myIndex == totalDestPEs-1){
179     // Final PE won't send to anyone
180     npes = 0;
181     return;
182   } else {
183     // All non-final PEs will send to next PE in list
184     npes = 1;
185     pelist = new int[1];
186     pelist[0] = destPEs[myIndex+1].pe;
187   }
188
189 }
190
191
192 void OneTimeTreeMulticastStrategy::determineNextHopPEs(const int totalDestPEs, const ComlibMulticastIndexCount* destPEs, const int myIndex, int * &pelist, int &npes){
193   const int myPe = CkMyPe();
194   
195   // 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
196   
197   // All non-final PEs will send to next PE in list
198   int sendLogicalIndexStart = degree*(myIndex+1) + 1;       // inclusive
199   int sendLogicalIndexEnd = sendLogicalIndexStart + degree - 1;   // inclusive
200   
201   if(sendLogicalIndexEnd-1 >= totalDestPEs){
202     sendLogicalIndexEnd = totalDestPEs;
203   }
204
205   int numSend = sendLogicalIndexEnd - sendLogicalIndexStart + 1;
206   if(numSend <= 0){
207     npes = 0;
208     return;
209   }
210  
211 #if DEBUG
212   if(numSend > 0)
213     CkPrintf("Tree logical index %d sending to logical %d to %d (totalDestPEs excluding root=%d)  numSend=%d\n",
214              myIndex+1, sendLogicalIndexStart, sendLogicalIndexEnd, totalDestPEs, numSend);
215 #endif
216
217   npes = numSend;
218   pelist = new int[npes];
219   
220   for(int i=0;i<numSend;i++){
221     CkAssert(sendLogicalIndexStart-1+i < totalDestPEs);
222     pelist[i] = destPEs[sendLogicalIndexStart-1+i].pe;
223 #if DEBUG
224     CkPrintf("Tree logical index %d sending to PE %d\n", myIndex+1, pelist[i]);
225 #endif
226     CkAssert(pelist[i] < CkNumPes());
227   }
228   
229 }
230
231
232
233 /*@}*/