fixing bugs to make subsets of processors working
[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     
185     if (InitCounter <0) {
186         ComlibPrintf("%d Sending to the lower hypercube\n", MyPe);
187         int nextpe=neighbor(MyPe, Dim);
188         int * pelist=(int *)CmiAlloc(NumPes*sizeof(int));
189         for (int i=0;i<NumPes;i++) {
190             pelist[i]=i;
191         }
192         
193         ComlibPrintf("Before Gmap %d\n", nextpe);
194         gmap(nextpe);
195         ComlibPrintf("%d: EachToMany Sending to %d\n", MyPe, nextpe);
196         HCUBESENDFN(id, Dim, Dim, NumPes, pelist, CkpvAccess(RecvHandle), nextpe, PeHcube);
197         CmiFree(pelist);
198         return;
199     }
200     
201     //Done: no more stages.
202     if (stage <0) {
203         //CmiPrintf("calling lp in multicast call %d\n", stage);
204         LocalProcMsg(id);
205         return;
206     }
207     
208     InitCounter++;
209     RecvManyMsg(id,NULL);
210 }
211
212 //Send the messages for the next stage to the next dimension neighbor
213 //If only numDirectStage's are left send messages directly using prefix send
214 void DimexRouter::RecvManyMsg(comID id, char *msg)
215 {
216     ComlibPrintf("%d recvmanymsg called\n", MyPe);
217     int msgstage;
218     if (msg) {
219         msgstage=PeHcube->UnpackAndInsert(msg);
220         //CmiPrintf("%d recvd msg for stage=%d\n", MyPe, msgstage);
221         if (msgstage == Dim) InitCounter++;
222         else buffer[msgstage]=1;
223     }
224   
225     //Check the buffers 
226     while ((InitCounter==2) || (stage >=numDirectSteps && buffer[stage+1])) {
227         InitCounter=setIC(Dim, MyPe, NumPes);
228         if (InitCounter != 2) { 
229             buffer[stage+1]=0;
230         }
231
232         //Send the data to the neighbor in this stage
233         int nextpe=neighbor(MyPe, stage);
234         
235         ComlibPrintf("Before Gmap %d\n", nextpe);
236         gmap(nextpe);
237         ComlibPrintf("%d RecvManyMsg Sending to %d\n", MyPe, nextpe);
238         HCUBESENDFN(id, stage, stage, penum[stage], next[stage], CkpvAccess(RecvHandle), nextpe, PeHcube);
239
240         //Go to the next stage
241         stage--; 
242     }        
243
244     if (stage < numDirectSteps && buffer[numDirectSteps]) {
245                 
246         InitCounter=setIC(Dim, MyPe, NumPes);
247         
248         //I am a processor in the smaller hypercube and there are some
249         //processors to send directly
250         if(InitCounter >= 0 && numDirectSteps > 0) {
251             //Sending through prefix send to save on copying overhead   
252             //of the hypercube algorithm            
253             
254             int *pelist = (int *)CmiAlloc(two_pow_ndirect * sizeof(int));
255             for(int count = 0; count < two_pow_ndirect; count ++){
256                 int nextpe = count ^ MyPe;
257                 gmap(nextpe);
258
259                 ComlibPrintf("%d Sending to %d\n", MyPe, nextpe);
260                 pelist[count] = nextpe;
261             }
262             
263             int len;
264             char *newmsg;
265             newmsg=PeHcube->ExtractAndPackAll(id, stage, &len);
266             if (newmsg) {
267                 CmiSetHandler(newmsg, CkpvAccess(ProcHandle));
268                 CmiSyncListSendAndFree(two_pow_ndirect, pelist, len, newmsg);
269             }
270             
271             stage -= numDirectSteps;
272
273             //if(procMsgCount == two_pow_ndirect)
274             //  LocalProcMsg();
275         }
276         else if(numDirectSteps == 0) {
277             LocalProcMsg(id);
278             ComlibPrintf("Calling local proc msg %d\n", 
279                          buffer[numDirectSteps]);
280         }
281         
282         buffer[numDirectSteps]=0;
283     }
284 }
285
286 void DimexRouter :: ProcManyMsg(comID id, char *m)
287 {
288     ComlibPrintf("%d: In procmanymsg\n", MyPe);
289     InitCounter=setIC(Dim, MyPe, NumPes);
290     if(id.isAllToAll) {
291         int pe_list[2];
292         int npes = 2;
293
294         if(InitCounter > 0)
295             npes = 1;
296         
297         pe_list[0] = MyPe;
298         pe_list[1] = neighbor(MyPe, Dim);
299         
300         PeHcube1->UnpackAndInsertAll(m, npes, pe_list);
301     }
302     else
303         PeHcube->UnpackAndInsert(m);
304     
305     procMsgCount ++;
306
307     if(InitCounter >= 0){
308         if((procMsgCount == two_pow_ndirect) && stage < 0) {
309             ComlibPrintf("%d Calling lp %d %d\n", MyPe, 
310                          procMsgCount, stage);
311             LocalProcMsg(id);
312         }
313     }
314     else
315         //CmiPrintf("calling lp in procmsg call\n");
316         LocalProcMsg(id);
317 }
318
319 void DimexRouter:: LocalProcMsg(comID id)
320 {
321     //CmiPrintf("%d local procmsg called\n", MyPe);
322
323     int mynext=neighbor(MyPe, Dim);
324     int mymax=1<<Dim;
325     
326     if (mynext >=mymax && mynext < NumPes) {
327         ComlibPrintf("Before Gmap %d\n", mynext);
328         int pelist[1];
329         pelist[0] = mynext;
330         ComlibPrintf("%d Sending to upper hypercube  %d\n", MyPe, mynext);
331         
332         if(id.isAllToAll){
333             gmap(mynext);
334             HCUBESENDFN(id, Dim, -1, 1, pelist, CkpvAccess(ProcHandle), mynext, PeHcube1);
335         }
336         else {
337             gmap(mynext);
338             HCUBESENDFN(id, Dim, -1, 1, pelist, CkpvAccess(ProcHandle), mynext, PeHcube);
339         }
340     }
341   
342     if(id.isAllToAll)
343         PeHcube1->ExtractAndDeliverLocalMsgs(MyPe);
344     else
345         PeHcube->ExtractAndDeliverLocalMsgs(MyPe);
346
347     PeHcube->Purge();
348     PeHcube1->Purge();
349     InitVars();
350     Done(id);
351 }
352
353 void DimexRouter::DummyEP(comID id, int msgstage)
354 {
355   if (msgstage >= 0) {
356         buffer[msgstage]=1;
357         RecvManyMsg(id, NULL);
358   }
359   else {
360         //CmiPrintf("%d Dummy calling lp\n", MyPe);
361         LocalProcMsg(id);
362   }
363 }
364
365 void DimexRouter::CreateStageTable(int numpes, int *destpes)
366 {
367   int *dir=new int[numpes];
368   int nextdim, j, i;
369   for (i=0;i<numpes;i++) {
370         dir[i]=MyPe ^ adjust(Dim, destpes[i]);
371   }
372   for (nextdim=Dim-1; nextdim>=0; nextdim--) {
373     int mask=1<<nextdim;
374     for (i=0;i<numpes;i++) {
375         if (dir[i] & mask) {
376                 dir[i]=0;
377                 for (j=0;(j<penum[nextdim]) && (destpes[i]!=next[nextdim][j]);j++);
378                 if (destpes[i]==next[nextdim][j]) { 
379                         //CmiPrintf("EQUAL %d\n", destpes[i]);
380                         continue;
381                 }
382                 next[nextdim][penum[nextdim]]=destpes[i];
383                 penum[nextdim]+=1;
384                 //CmiPrintf("%d next[%d][%d]=%d\n",MyPe, nextdim, penum[nextdim],destpes[i]);
385         }
386     }
387   }
388   delete dir;
389   return;
390 }
391
392 Router * newhcubeobject(int n, int me)
393 {
394     Router *obj=new DimexRouter(n, me);
395     return(obj);
396 }
397
398 //MOVE this CODE else where, this method has been depricated!!!
399 void DimexRouter::SetID(comID id) { 
400
401     if(id.isAllToAll) {
402         numDirectSteps = 2;
403         two_pow_ndirect = 1;
404           for(int count = 0; count < numDirectSteps; count ++)
405               two_pow_ndirect *= 2;
406     }
407 }