modified the registration of the converse handlers for propagate and propagate_frag.
[charm.git] / src / conv-com / de.C
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7
8 /*************************************************
9  * File : de.C
10  *
11  * Author : Krishnan V.
12  *
13  * Dimensional Exchange (Hypercube) Router 
14  *  
15  * Modified to send last k stages directly for all to all multicast by
16  * Sameer Kumar 9/07/03 
17  *
18  * Adapted to the new communication library 05/14/04
19  ************************************************/
20
21 #include "de.h"
22
23 #define gmap(pe) {if (gpes) pe=gpes[pe];}
24
25 //#define gmap(pe) (gpes ? gpes[pe] : pe)
26
27 /**The only communication op used. Modify this to use
28  ** vector send */
29
30 #define HCUBESENDFN(kid, u1, u2, knpe, kpelist, khndl, knextpe, pehcube)  \
31         {int len;\
32         char *newmsg;\
33         newmsg=pehcube->ExtractAndPack(kid, u1, knpe, kpelist, &len);\
34         if (newmsg) {\
35           CmiSetHandler(newmsg, khndl);\
36           CmiSyncSendAndFree(knextpe, len, newmsg);\
37         }\
38         else {\
39           SendDummyMsg(kid, knextpe, u2);\
40         }\
41 }
42
43 inline int maxdim(int n)
44 {
45   int maxpes=1, dim=0;
46
47   while (maxpes< n) {
48         maxpes *=2;
49         dim++;
50   }
51   if (maxpes==n) return(dim);
52   else return(dim-1);
53 }
54
55 inline int neighbor(int pe, int dim)
56 {
57   return(pe ^ (1<<dim));
58 }
59
60 inline int adjust(int dim, int pe)
61 {
62   int mymax=1<<dim;
63   if (pe >= mymax) return(neighbor(pe, dim));
64   else return(pe);
65 }
66
67 inline int setIC(int dim, int pe, int N)
68 {
69   int mymax= 1<< dim;
70   int initCounter=1, myneighb;
71   if (mymax < N) {
72         myneighb= neighbor(pe, dim);
73         if (myneighb < N && myneighb >= mymax) {
74               initCounter=0;
75         }
76   }
77   if (pe >= mymax) initCounter = -1;
78   return(initCounter);
79 }
80
81 /*********************************************************************
82  * Total preallocated memory=(P+Dim+Dim*P)ints + MAXNUMMSGS msgstruct
83  **********************************************************************/
84 DimexRouter::DimexRouter(int n, int me, int ndirect)
85 {
86   int i;
87  
88   //last ndirect steps will be sent directly
89   numDirectSteps = ndirect;
90   //2 raised to the power of ndirect
91   two_pow_ndirect = 1;
92   for(int count = 0; count < ndirect; count ++)
93       two_pow_ndirect *= 2;
94
95   //Initialize the no: of pes and my Pe number
96   NumPes=n;
97   MyPe=me;
98   gpes=NULL;
99
100   //Initialize Dimension and no: of stages
101   Dim=maxdim(NumPes);
102
103   PeHcube=new PeTable(NumPes);
104   PeHcube1 = new PeTable(NumPes);
105
106   InitVars();
107
108   //Create the message array, buffer and the next stage table
109   buffer=new int[Dim+1];
110   next=(int **)CmiAlloc(sizeof(int *)*Dim);
111   for (i=0;i<Dim;i++) {
112         next[i]=new int[NumPes];
113         buffer[i]=0;
114         for (int j=0;j<NumPes;j++) next[i][j]=-1;
115   }
116   buffer[Dim]=0;
117
118   //Create and initialize the indexes to the above table
119   penum=new int[NumPes];
120   int *dp=new int[NumPes];
121   for (i=0;i<NumPes;i++) {
122         penum[i]=0;
123         dp[i]=i;
124   }
125
126   CreateStageTable(NumPes, dp);
127   delete(dp);
128
129   //CmiPrintf("%d DE constructor done dim=%d, mymax=%d IC=%d\n", MyPe, Dim, 1<<Dim, InitCounter);
130
131   if(numDirectSteps > Dim - 1)
132       numDirectSteps = Dim - 1;
133 }
134  
135 DimexRouter :: ~DimexRouter()
136 {
137   int i;
138   delete PeHcube;
139   delete PeHcube1;
140   delete buffer;
141   for (i=0;i<Dim;i++) {
142         delete next[i];
143   }
144   delete next;
145 }
146
147 void DimexRouter :: SetMap(int *pes)
148 {
149   gpes=pes;
150 }
151
152 void DimexRouter :: InitVars()
153 {
154   stage=Dim-1;
155   InitCounter=setIC(Dim, MyPe, NumPes);
156   procMsgCount = 0;
157 }
158
159 void DimexRouter::EachToAllMulticast(comID id, int size, void *msg, int more)
160 {
161   int npe=NumPes;
162   int * destpes=(int *)CmiAlloc(sizeof(int)*npe);
163   for (int i=0;i<npe;i++) destpes[i]=i;
164   EachToManyMulticast(id, size, msg, npe, destpes, more);
165   CmiFree(destpes);
166 }
167
168 void DimexRouter::NumDeposits(comID, int num)
169 {
170   //CmiPrintf("Deposit=%d\n", num);
171 }
172
173 void DimexRouter::EachToManyMulticast(comID id, int size, void *msg, int numpes, int *destpes, int more)
174 {
175
176     SetID(id);
177
178     //Create the message
179     if (msg && size) {
180         PeHcube->InsertMsgs(numpes, destpes, size, msg);
181     }
182     
183     if (more) return;
184     start_hcube(id);
185 }
186
187 void DimexRouter::EachToManyMulticastQ(comID id, CkQ<MessageHolder *> &msgq) {
188     SetID(id);
189
190     int count = 0;
191     int length = msgq.length();
192
193     for(count = 0; count < length; count ++) {
194         MessageHolder *mhdl = msgq.deq();
195         PeHcube->InsertMsgs(mhdl->npes, mhdl->pelist, mhdl->size, 
196                             mhdl->getMessage());
197         delete mhdl;
198     }
199     
200     start_hcube(id);
201 }
202
203 void DimexRouter::start_hcube(comID id) {
204
205     if (InitCounter <0) {
206         ComlibPrintf("%d Sending to the lower hypercube\n", MyPe);
207         int nextpe=neighbor(MyPe, Dim);
208         int * pelist=(int *)CmiAlloc(NumPes*sizeof(int));
209         for (int i=0;i<NumPes;i++) {
210             pelist[i]=i;
211         }
212         
213         ComlibPrintf("Before Gmap %d\n", nextpe);
214         gmap(nextpe);
215         ComlibPrintf("%d: EachToMany Sending to %d\n", MyPe, nextpe);
216         HCUBESENDFN(id, Dim, Dim, NumPes, pelist, CkpvAccess(RecvHandle), nextpe, PeHcube);
217         CmiFree(pelist);
218         return;
219     }
220     
221     //Done: no more stages.
222     if (stage <0) {
223         //CmiPrintf("calling lp in multicast call %d\n", stage);
224         LocalProcMsg(id);
225         return;
226     }
227     
228     InitCounter++;
229     RecvManyMsg(id,NULL);
230 }
231
232 //Send the messages for the next stage to the next dimension neighbor
233 //If only numDirectStage's are left send messages directly using prefix send
234 void DimexRouter::RecvManyMsg(comID id, char *msg)
235 {
236     ComlibPrintf("%d recvmanymsg called\n", MyPe);
237     int msgstage;
238     if (msg) {
239         msgstage=PeHcube->UnpackAndInsert(msg);
240         //CmiPrintf("%d recvd msg for stage=%d\n", MyPe, msgstage);
241         if (msgstage == Dim) InitCounter++;
242         else buffer[msgstage]=1;
243     }
244   
245     //Check the buffers 
246     while ((InitCounter==2) || (stage >=numDirectSteps && buffer[stage+1])) {
247         InitCounter=setIC(Dim, MyPe, NumPes);
248         if (InitCounter != 2) { 
249             buffer[stage+1]=0;
250         }
251
252         //Send the data to the neighbor in this stage
253         int nextpe=neighbor(MyPe, stage);
254         
255         ComlibPrintf("Before Gmap %d\n", nextpe);
256         gmap(nextpe);
257         ComlibPrintf("%d RecvManyMsg Sending to %d\n", MyPe, nextpe);
258         HCUBESENDFN(id, stage, stage, penum[stage], next[stage], CkpvAccess(RecvHandle), nextpe, PeHcube);
259
260         //Go to the next stage
261         stage--; 
262     }        
263
264     if (stage < numDirectSteps && buffer[numDirectSteps]) {
265                 
266         InitCounter=setIC(Dim, MyPe, NumPes);
267         
268         //I am a processor in the smaller hypercube and there are some
269         //processors to send directly
270         if(InitCounter >= 0 && numDirectSteps > 0) {
271             //Sending through prefix send to save on copying overhead   
272             //of the hypercube algorithm            
273             
274             int *pelist = (int *)CmiAlloc(two_pow_ndirect * sizeof(int));
275             for(int count = 0; count < two_pow_ndirect; count ++){
276                 int nextpe = count ^ MyPe;
277                 gmap(nextpe);
278
279                 ComlibPrintf("%d Sending to %d\n", MyPe, nextpe);
280                 pelist[count] = nextpe;
281             }
282             
283             int len;
284             char *newmsg;
285             newmsg=PeHcube->ExtractAndPackAll(id, stage, &len);
286             if (newmsg) {
287                 CmiSetHandler(newmsg, CkpvAccess(ProcHandle));
288                 CmiSyncListSendAndFree(two_pow_ndirect, pelist, len, newmsg);
289             }
290             
291             stage -= numDirectSteps;
292
293             //if(procMsgCount == two_pow_ndirect)
294             //  LocalProcMsg();
295         }
296         else if(numDirectSteps == 0) {
297             LocalProcMsg(id);
298             ComlibPrintf("Calling local proc msg %d\n", 
299                          buffer[numDirectSteps]);
300         }
301         
302         buffer[numDirectSteps]=0;
303     }
304 }
305
306 void DimexRouter :: ProcManyMsg(comID id, char *m)
307 {
308     ComlibPrintf("%d: In procmanymsg\n", MyPe);
309     InitCounter=setIC(Dim, MyPe, NumPes);
310     if(id.isAllToAll) {
311         int pe_list[2];
312         int npes = 2;
313
314         if(InitCounter > 0)
315             npes = 1;
316         
317         pe_list[0] = MyPe;
318         pe_list[1] = neighbor(MyPe, Dim);
319         
320         PeHcube1->UnpackAndInsertAll(m, npes, pe_list);
321     }
322     else
323         PeHcube->UnpackAndInsert(m);
324     
325     procMsgCount ++;
326
327     if(InitCounter >= 0){
328         if((procMsgCount == two_pow_ndirect) && stage < 0) {
329             ComlibPrintf("%d Calling lp %d %d\n", MyPe, 
330                          procMsgCount, stage);
331             LocalProcMsg(id);
332         }
333     }
334     else
335         //CmiPrintf("calling lp in procmsg call\n");
336         LocalProcMsg(id);
337 }
338
339 void DimexRouter:: LocalProcMsg(comID id)
340 {
341     //CmiPrintf("%d local procmsg called\n", MyPe);
342
343     int mynext=neighbor(MyPe, Dim);
344     int mymax=1<<Dim;
345     
346     if (mynext >=mymax && mynext < NumPes) {
347         ComlibPrintf("Before Gmap %d\n", mynext);
348         int pelist[1];
349         pelist[0] = mynext;
350         ComlibPrintf("%d Sending to upper hypercube  %d\n", MyPe, mynext);
351         
352         if(id.isAllToAll){
353             gmap(mynext);
354             HCUBESENDFN(id, Dim, -1, 1, pelist, CkpvAccess(ProcHandle), mynext, PeHcube1);
355         }
356         else {
357             gmap(mynext);
358             HCUBESENDFN(id, Dim, -1, 1, pelist, CkpvAccess(ProcHandle), mynext, PeHcube);
359         }
360     }
361   
362     if(id.isAllToAll)
363         PeHcube1->ExtractAndDeliverLocalMsgs(MyPe);
364     else
365         PeHcube->ExtractAndDeliverLocalMsgs(MyPe);
366
367     PeHcube->Purge();
368     PeHcube1->Purge();
369     InitVars();
370     Done(id);
371 }
372
373 void DimexRouter::DummyEP(comID id, int msgstage)
374 {
375   if (msgstage >= 0) {
376         buffer[msgstage]=1;
377         RecvManyMsg(id, NULL);
378   }
379   else {
380         //CmiPrintf("%d Dummy calling lp\n", MyPe);
381         LocalProcMsg(id);
382   }
383 }
384
385 void DimexRouter::CreateStageTable(int numpes, int *destpes)
386 {
387   int *dir=new int[numpes];
388   int nextdim, j, i;
389   for (i=0;i<numpes;i++) {
390         dir[i]=MyPe ^ adjust(Dim, destpes[i]);
391   }
392   for (nextdim=Dim-1; nextdim>=0; nextdim--) {
393     int mask=1<<nextdim;
394     for (i=0;i<numpes;i++) {
395         if (dir[i] & mask) {
396                 dir[i]=0;
397                 for (j=0;(j<penum[nextdim]) && (destpes[i]!=next[nextdim][j]);j++);
398                 if (destpes[i]==next[nextdim][j]) { 
399                         //CmiPrintf("EQUAL %d\n", destpes[i]);
400                         continue;
401                 }
402                 next[nextdim][penum[nextdim]]=destpes[i];
403                 penum[nextdim]+=1;
404                 //CmiPrintf("%d next[%d][%d]=%d\n",MyPe, nextdim, penum[nextdim],destpes[i]);
405         }
406     }
407   }
408   delete dir;
409   return;
410 }
411
412 Router * newhcubeobject(int n, int me)
413 {
414     Router *obj=new DimexRouter(n, me);
415     return(obj);
416 }
417
418 //MOVE this CODE else where, this method has been depricated!!!
419 void DimexRouter::SetID(comID id) { 
420
421     if(id.isAllToAll) {
422         numDirectSteps = 2;
423         two_pow_ndirect = 1;
424           for(int count = 0; count < numDirectSteps; count ++)
425               two_pow_ndirect *= 2;
426     }
427 }