Fixed gatherflat problem.
[charm.git] / src / arch / exemplar / machine.c
1 /***************************************************************************
2  * RCS INFORMATION:
3  *
4  *      $RCSfile$
5  *      $Author$        $Locker$                $State$
6  *      $Revision$      $Date$
7  *
8  ***************************************************************************
9  * DESCRIPTION:
10  *
11  ***************************************************************************
12  * REVISION HISTORY:
13  *
14  * $Log$
15  * Revision 2.27  1997-08-01 22:38:50  milind
16  * Fixed gatherflat problem.
17  * Also fixed optimization flags.
18  *
19  * Revision 2.26  1997/07/29 16:09:48  milind
20  * Added CmiNodeLock macros and functions to the machine layer for all except
21  * solaris SMP.
22  *
23  * Revision 2.25  1997/07/29 16:00:06  milind
24  * changed cmi_nodesize into cmi_mynodesize.
25  *
26  * Revision 2.24  1997/07/23 18:40:24  milind
27  * Made charm++ to work on exemplar.
28  *
29  * Revision 2.23  1997/07/23 16:55:02  milind
30  * Made Converse run on Exemplar.
31  *
32  * Revision 2.22  1997/07/22 18:16:05  milind
33  * fixed some exemplar-related bugs.
34  *
35  * Revision 2.21  1996/11/23 02:25:36  milind
36  * Fixed several subtle bugs in the converse runtime for convex
37  * exemplar.
38  *
39  * Revision 2.20  1996/07/15 20:59:22  jyelon
40  * Moved much timer, signal, etc code into common.
41  *
42  * Revision 2.19  1995/11/09 22:00:55  gursoy
43  * fixed varsize related bug (CmiFreeSend...)
44  *
45  * Revision 2.18  1995/10/27  21:45:35  jyelon
46  * Changed CmiNumPe --> CmiNumPes
47  *
48  * Revision 2.17  1995/10/19  20:42:45  jyelon
49  * added void to CmiNodeBarrier
50  *
51  * Revision 2.16  1995/10/19  20:40:17  jyelon
52  * void * -> char *
53  *
54  * Revision 2.15  1995/10/19  20:38:08  jyelon
55  * unsigned int -> int
56  *
57  * Revision 2.14  1995/10/13  20:05:13  jyelon
58  * *** empty log message ***
59  *
60  * Revision 2.13  1995/10/10  06:10:58  jyelon
61  * removed program_name
62  *
63  * Revision 2.12  1995/09/29  09:50:07  jyelon
64  * CmiGet-->CmiDeliver, added protos, etc.
65  *
66  * Revision 2.11  1995/09/20  16:01:33  gursoy
67  * this time really made the arg of CmiFree and CmiSize void*
68  *
69  * Revision 2.10  1995/09/20  15:58:09  gursoy
70  * made the arg of CmiFree and CmiSize void*
71  *
72  * Revision 2.9  1995/09/14  18:50:10  milind
73  * fixed a small bug - a typo
74  *
75  * Revision 2.8  1995/09/07  22:40:22  gursoy
76  * Cmi_mype, Cmi_numpes and CmiLocalQueuea are accessed thru macros now
77  *
78  * Revision 2.7  1995/07/05  23:15:29  gursoy
79  * minor change in +p code
80  *
81  * Revision 2.6  1995/07/05  23:07:28  gursoy
82  * fixed +p option
83  *
84  * Revision 2.5  1995/07/03  17:57:37  gursoy
85  * changed charm_main to user_main
86  *
87  * Revision 2.4  1995/06/28  15:31:54  gursoy
88  * *** empty log message ***
89  *
90  * Revision 2.3  1995/06/16  21:42:10  gursoy
91  * fixed CmiSyncSend: size field is copied now
92  *
93  * Revision 2.2  1995/06/09  21:22:00  gursoy
94  * Cpv macros moved to converse
95  *
96  * Revision 2.1  1995/06/09  16:43:47  gursoy
97  * Initial implementation of CmiMyRank
98  *
99  * Revision 2.0  1995/06/08  16:35:12  gursoy
100  * Reorganized directory structure
101  *
102  ***************************************************************************/
103 static char ident[] = "@(#)$Header$";
104
105 #include <spp_prog_model.h>
106 #include <memory.h>
107 #include <cps.h>
108 #include <math.h>
109 #include "converse.h"
110
111
112 #define FreeFn          free
113 #define BLK_LEN         512
114 typedef struct
115         {
116                 mem_sema_t sema;
117                 void     **blk;
118                 unsigned int blk_len;
119                 unsigned int first;
120                 unsigned int len;
121                 unsigned int maxlen;
122 }McQueue;
123
124 static McQueue *McQueueCreate(void);
125 static void McQueueAddToBack(McQueue *queue, void *element);
126 static void *McQueueRemoveFromFront(McQueue *queue);
127 static McQueue **MsgQueue;
128 #define g_malloc(s)  memory_class_malloc(s,NEAR_SHARED_MEM)
129
130
131 CpvDeclare(void*, CmiLocalQueue);
132 int Cmi_numpes;
133 int Cmi_mynodesize;
134
135 static node_private barrier_t barrier;
136 static node_private barrier_t *barr;
137 static node_private int *nthreads;
138 static node_private int requested_npe;
139
140 static void threadInit();
141
142 void *CmiAlloc(size)
143 int size;
144 {
145   char *res;
146   res =(char *) malloc(size+8);
147   if (res==(char *)0) { CmiError("%d:Memory allocation failed.",CmiMyPe()); exit(1); }
148   ((int *)res)[0]=size;
149   return (void *)(res+8);
150 }
151
152 int CmiSize(blk)
153 void *blk;
154 {
155   return ((int *)( ((char *) blk) - 8))[0];
156 }
157
158 void CmiFree(blk)
159 void *blk;
160 {
161   free( ((char *)blk) - 8);
162 }
163
164
165 void *CmiSvAlloc(size)
166 int size;
167 {
168   char *res;
169   res =(char *)memory_class_malloc(size+8,NEAR_SHARED_MEM);
170   if (res==0) CmiError("Memory allocation failed.");
171   ((int *)res)[0]=size;
172   return (void *)(res+8);
173 }
174
175 void CmiSvFree(blk)
176 char *blk;
177 {
178   free(blk-8);
179 }
180
181
182
183 CmiNotifyIdle()
184 {
185 }
186
187 CmiNodeLock CmiCreateLock(void)
188 {
189   CmiNodeLock *plock = (CmiNodeLock *)malloc(sizeof(CmiNodeLock));
190   cps_mutex_alloc(*plock);
191   return *plock;
192 }
193
194 int CmiProbeLock(CmiNodeLock lock)
195 {
196   if(cps_mutex_trylock(lock) == 0){
197     cps_mutex_unlock(lock);
198     return 1;
199   } else {
200     return 0;
201   }
202 }
203
204
205 int CmiAsyncMsgSent(msgid)
206 CmiCommHandle msgid;
207 {
208    return 0;
209 }
210
211
212 typedef struct {
213    int argc;
214    void *argv;
215    int  npe;
216    CmiStartFn fn;
217    int usched;
218 } USER_PARAMETERS;
219
220
221
222 void ConverseInit(int argc, char** argv, CmiStartFn fn, int usched, int initret)
223 {
224     int i;
225     USER_PARAMETERS usrparam;
226     void *arg = & usrparam;
227  
228     spawn_sym_t request;
229
230
231     /* figure out number of processors required */
232     i =  0;
233     requested_npe = 0; 
234     while (argv[i] != 0)
235     {
236          if (strcmp(argv[i], "+p") == 0)
237            {
238                  sscanf(argv[i + 1], "%d", &requested_npe);
239                  break;
240            }
241          else if (sscanf(argv[i], "+p%d", &requested_npe) == 1) break;
242          i++;
243     }
244
245
246     if (requested_npe <= 0)
247     {
248        CmiError("Error: requested number of processors is invalid %d\n",requested_npe);
249        exit();
250     }
251
252
253     printf("Requested NP = %d\n", requested_npe);
254     usrparam.argc = argc;
255     usrparam.argv = (void *) argv;
256     usrparam.npe  = requested_npe;
257     usrparam.fn = fn;
258     usrparam.usched = usched;
259     request.node = CPS_ANY_NODE;
260     request.min  = requested_npe;
261     request.max  = requested_npe;
262     request.threadscope = CPS_THREAD_PARALLEL;
263
264    
265     nthreads = &requested_npe;
266     barr     = &barrier; 
267
268     cps_barrier_alloc(barr);
269
270     MsgQueue=(McQueue **)g_malloc(requested_npe*sizeof(McQueue *));
271     if (MsgQueue == (McQueue **)0) {
272         CmiError("Cannot Allocate Memory...\n");
273         exit(1);
274     }
275     for(i=0; i<requested_npe; i++) MsgQueue[i] = McQueueCreate();
276
277     if (cps_ppcall(&request, threadInit ,arg) < 0) {
278         CmiError("Cannot created threads...\n");
279         exit(1);
280     } 
281     cps_barrier_free(barr);
282
283 }
284
285 void CmiInitMc(char **);
286
287 void ConverseExit(void)
288 {
289    cps_barrier(barr,nthreads);
290 }
291
292 static void threadInit(arg)
293 void *arg;
294 {
295     USER_PARAMETERS *usrparam;
296     usrparam = (USER_PARAMETERS *) arg;
297
298     CpvInitialize(void*, CmiLocalQueue);
299
300     Cmi_numpes =  usrparam->npe;
301     Cmi_mynodesize  = Cmi_numpes;
302
303     ConverseCommonInit(usrparam->argv);
304     CthInit(usrparam->argv);
305     CmiInitMc(usrparam->argv);
306     usrparam->fn(usrparam->argc,usrparam->argv);
307     if (usrparam->usched==0) CsdScheduler(-1);
308     ConverseExit();
309 }
310
311
312 void CmiInitMc(argv)
313 char *argv[];
314 {
315     neighbour_init(CmiMyPe());
316     CpvAccess(CmiLocalQueue) = (void *) FIFO_Create();
317     CmiSpanTreeInit();
318     CmiTimerInit();
319 }
320
321
322
323 CmiExit()
324 {
325 }
326
327
328 CmiDeclareArgs()
329 {
330 }
331
332
333 void *CmiGetNonLocal()
334 {
335      return McQueueRemoveFromFront(MsgQueue[CmiMyPe()]);
336 }
337
338
339 void CmiSyncSendFn(destPE, size, msg)
340 int destPE;
341 int size;
342 char *msg;
343 {
344     /* Send the message of "size" bytes to the destPE.
345        Return only after the message has been sent, i.e.,
346        the buffer (msg) is free for re-use. */
347         char *buf;
348
349         buf=(void *)g_malloc(size+8);
350         if(buf==(void *)0)
351         {
352                 CmiError("Cannot allocate memory!\n");
353                 exit(1);
354         }
355         ((int *)buf)[0]=size;
356         buf += 8;
357
358
359         memcpy((double *)buf,(double *)msg,size);
360         McQueueAddToBack(MsgQueue[destPE],buf); 
361 }
362
363
364 CmiCommHandle CmiAsyncSendFn(destPE, size, msg)
365 int destPE;
366 int size;
367 char *msg;
368 {
369     CmiSyncSendFn(destPE, size, msg); 
370     return 0;
371 }
372
373
374 void CmiFreeSendFn(destPE, size, msg)
375 int destPE;
376 int size;
377 char  *msg;
378 {
379         McQueueAddToBack(MsgQueue[destPE],msg); 
380 }
381
382 void CmiSyncBroadcastFn(size, msg)
383 int  size;
384 char *msg;
385 {
386        int i;
387        for(i=0; i<CmiNumPes(); i++)
388          if (CmiMyPe() != i) CmiSyncSendFn(i,size,msg);
389 }
390
391 CmiCommHandle CmiAsyncBroadcastFn(size, msg)
392 int  size;
393 char *msg;
394 {
395     CmiSyncBroadcastFn(size, msg);
396     return 0;
397 }
398
399 void CmiFreeBroadcastFn(size, msg)
400 int  size;
401 char *msg;
402 {
403     CmiSyncBroadcastFn(size,msg);
404     CmiFree(msg);
405 }
406
407 void CmiSyncBroadcastAllFn(size, msg)
408 int  size;
409 char *msg;
410 {
411     int i;
412     for(i=0; i<CmiNumPes(); i++) CmiSyncSendFn(i,size,msg);
413 }
414
415
416 CmiCommHandle CmiAsyncBroadcastAllFn(size, msg)
417 int  size;
418 char *msg;
419 {
420     CmiSyncBroadcastAllFn(size, msg);
421     return 0; 
422 }
423
424
425 void CmiFreeBroadcastAllFn(size, msg)
426 int  size;
427 char *msg;
428 {
429     int i;
430     for(i=0; i<CmiNumPes(); i++)
431        if (CmiMyPe() != i) CmiSyncSendFn(i,size,msg);
432     FIFO_EnQueue(CpvAccess(CmiLocalQueue),msg);
433 }
434
435
436
437 void CmiNodeBarrier()
438 {
439    cps_barrier(barr,nthreads);
440 }
441
442
443
444
445
446 /* ********************************************************************** */
447 /* The following functions are required by the load balance modules       */
448 /* ********************************************************************** */
449
450 static thread_private int _MC_neighbour[4]; 
451 static thread_private int _MC_numofneighbour;
452
453 long CmiNumNeighbours(node)
454 int node;
455 {
456     if (node == CmiMyPe() ) 
457      return  _MC_numofneighbour;
458     else 
459      return 0;
460 }
461
462
463 CmiGetNodeNeighbours(node, neighbours)
464 int node, *neighbours;
465 {
466     int i;
467
468     if (node == CmiMyPe() )
469        for(i=0; i<_MC_numofneighbour; i++) neighbours[i] = _MC_neighbour[i];
470
471 }
472
473
474 int CmiNeighboursIndex(node, neighbour)
475 int node, neighbour;
476 {
477     int i;
478
479     for(i=0; i<_MC_numofneighbour; i++)
480        if (_MC_neighbour[i] == neighbour) return i;
481     return(-1);
482 }
483
484
485 static neighbour_init(p)
486 int p;
487 {
488     int a,b,n;
489
490     n = CmiNumPes();
491     a = (int)sqrt((double)n);
492     b = (int) ceil( ((double)n / (double)a) );
493
494    
495     _MC_numofneighbour = 0;
496    
497     /* east neighbour */
498     if ( (p+1)%b == 0 )
499            n = p-b+1;
500     else {
501            n = p+1;
502            if (n>=CmiNumPes()) n = (a-1)*b; /* west-south corner */
503     }
504     if (neighbour_check(p,n) ) _MC_neighbour[_MC_numofneighbour++] = n;
505
506     /* west neigbour */
507     if ( (p%b) == 0) {
508           n = p+b-1;
509           if (n >= CmiNumPes()) n = CmiNumPes()-1;
510        }
511     else
512           n = p-1;
513     if (neighbour_check(p,n) ) _MC_neighbour[_MC_numofneighbour++] = n;
514
515     /* north neighbour */
516     if ( (p/b) == 0) {
517           n = (a-1)*b+p;
518           if (n >= CmiNumPes()) n = n-b;
519        }
520     else
521           n = p-b;
522     if (neighbour_check(p,n) ) _MC_neighbour[_MC_numofneighbour++] = n;
523     
524     /* south neighbour */
525     if ( (p/b) == (a-1) )
526            n = p%b;
527     else {
528            n = p+b;
529            if (n >= CmiNumPes()) n = n%b;
530     } 
531     if (neighbour_check(p,n) ) _MC_neighbour[_MC_numofneighbour++] = n;
532
533 }
534
535 static neighbour_check(p,n)
536 int p,n;
537 {
538     int i; 
539     if (n==p) return 0;
540     for(i=0; i<_MC_numofneighbour; i++) if (_MC_neighbour[i] == n) return 0;
541     return 1; 
542 }
543
544
545
546
547
548
549
550
551
552
553
554 /* ****************************************************************** */
555 /*    The following internal functions implements FIFO queues for     */
556 /*    messages. These queues are shared among threads                 */
557 /* ****************************************************************** */
558
559
560
561 static void **
562 AllocBlock(len)
563 unsigned int len;
564 {
565         void ** blk;
566
567         blk=(void **)g_malloc(len*sizeof(void *));
568         if(blk==(void **)0)
569         {
570                 CmiError("Cannot Allocate Memory!\n");
571                 exit(1);
572         }
573         return blk;
574 }
575
576 static void
577 SpillBlock(srcblk, destblk, first, len)
578 void **srcblk, **destblk;
579 unsigned int first, len;
580 {
581         memcpy(destblk, &srcblk[first], (len-first)*sizeof(void *));
582         memcpy(&destblk[len-first],srcblk,first*sizeof(void *));
583 }
584
585 static
586 McQueue *
587 McQueueCreate()
588 {
589         McQueue *queue;
590         int one = 1;
591
592         queue = (McQueue *) g_malloc(sizeof(McQueue));
593         if(queue==(McQueue *)0)
594         {
595                 CmiError("Cannot Allocate Memory!\n");
596                 exit(1);
597         }
598         m_init32(&(queue->sema), &one);
599         queue->blk = AllocBlock(BLK_LEN);
600         queue->blk_len = BLK_LEN;
601         queue->first = 0;
602         queue->len = 0;
603         queue->maxlen = 0;
604         return queue;
605 }
606
607 static 
608 void
609 McQueueAddToBack(queue, element)
610 McQueue *queue;
611 void  *element;
612 {
613         m_lock(&(queue->sema));
614         if(queue->len==queue->blk_len)
615         {
616                 void **blk;
617
618                 queue->blk_len *= 3;
619                 blk = AllocBlock(queue->blk_len);
620                 SpillBlock(queue->blk, blk, queue->first, queue->len);
621                 FreeFn(queue->blk);
622                 queue->blk = blk;
623                 queue->first = 0;
624         }
625         queue->blk[(queue->first+queue->len++)%queue->blk_len] = element;
626         if(queue->len>queue->maxlen)
627                 queue->maxlen = queue->len;
628         m_unlock(&(queue->sema));
629 }
630
631
632 static
633 void *
634 McQueueRemoveFromFront(queue)
635 McQueue *queue;
636 {
637         void *element;
638         m_lock(&(queue->sema));
639         element = (void *) 0;
640         if(queue->len)
641         {
642                 element = queue->blk[queue->first++];
643                 queue->first = (queue->first+queue->blk_len)%queue->blk_len;
644                 queue->len--;
645         }
646         m_unlock(&(queue->sema));
647         return element;
648 }