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