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