7db2ccca91fcc49d33aea6f5545aee0de03d47ee
[charm.git] / src / conv-core / convcore.c
1 /** 
2   @defgroup Converse
3   \brief Converse--a parallel portability layer.
4
5   Converse is the lowest level inside the Charm++ hierarchy. It stands on top
6   of the machine layer, and it provides all the common functionality across
7   platforms.
8
9   One converse program is running on every processor (or node in the smp
10   version). it manages the message transmission, and the memory allocation.
11   Charm++, which is on top of Converse, uses its functionality for
12   interprocess *communication.
13
14   In order to maintain multiple independent objects inside a single user space
15   program, it uses a personalized version of threads, which can be executed,
16   suspended, and migrated across processors.
17
18   It provides a scheduler for message delivery: methods can be registered to
19   the scheduler, and then messages allocated through CmiAlloc can be sent to
20   the correspondent method in a remote processor. This is done through the
21   converse header (which has few common fields, but is architecture dependent).
22
23   @defgroup ConverseScheduler 
24   \brief The portion of Converse responsible for scheduling the execution of 
25   incoming messages.
26   
27   Converse provides a scheduler for message delivery: methods can be registered to 
28   the scheduler, and then messages allocated through CmiAlloc can be sent to 
29   the correspondent method in a remote processor. This is done through the
30   converse header (which has few common fields, but is architecture dependent).
31
32   In converse the CsdScheduleForever() routine will run an infinite while loop that
33   looks for available messages to process from the unprocessed message queues. The
34   details of the queues and the order in which they are emptied is hidden behind
35   CsdNextMessage(), which is used to dequeue the next message for processing by the
36   converse scheduler. When a message is taken from the queue it is then passed into
37   CmiHandleMessage() which calls the handler associated with the message.
38
39   Incoming messages that are destined for Charm++ will be passed to the 
40   \ref CharmScheduler "charm scheduling routines".
41
42   @file
43   converse main core
44   @ingroup Converse
45   @ingroup ConverseScheduler
46  
47   @addtogroup Converse
48   @{
49
50 */
51
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <errno.h>
56 #ifndef _WIN32
57 #include <sys/time.h>
58 #include <sys/resource.h>
59 #endif
60
61 #include "converse.h"
62 #include "conv-trace.h"
63 #include "sockRoutines.h"
64 #include "queueing.h"
65 #include "conv-ccs.h"
66 #include "ccs-server.h"
67 #include "memory-isomalloc.h"
68 #if CMK_PROJECTOR
69 #include "converseEvents.h"             /* projector */
70 #include "traceCoreCommon.h"    /* projector */
71 #include "machineEvents.h"     /* projector */
72 #endif
73
74 extern const char * const CmiCommitID;
75
76 #if CMK_OUT_OF_CORE
77 #include "conv-ooc.h"
78 #endif
79
80 #if CONVERSE_POOL
81 #include "cmipool.h"
82 #endif
83
84 #if CMK_CONDS_USE_SPECIAL_CODE
85 CmiSwitchToPEFnPtr CmiSwitchToPE;
86 #endif
87
88 CpvExtern(int, _traceCoreOn);   /* projector */
89 extern void CcdModuleInit(char **);
90 extern void CmiMemoryInit(char **);
91 extern void CldModuleInit(char **);
92
93 #if CMK_WHEN_PROCESSOR_IDLE_USLEEP
94 #include <sys/types.h>
95 #include <sys/time.h>
96 #endif
97
98 #if CMK_TIMER_USE_TIMES
99 #include <sys/times.h>
100 #include <limits.h>
101 #include <unistd.h>
102 #endif
103
104 #if CMK_TIMER_USE_GETRUSAGE
105 #include <sys/time.h>
106 #include <sys/resource.h>
107 #endif
108
109 #if CMK_TIMER_USE_RDTSC
110 #include <string.h>
111 #include <unistd.h>
112 #include <time.h>
113 #include <stdio.h>
114 #include <sys/time.h>
115 #include <sys/resource.h>
116 #endif
117
118 #ifdef CMK_TIMER_USE_WIN32API
119 #include <stdlib.h>
120 #include <time.h>
121 #include <sys/types.h>
122 #include <sys/timeb.h>
123 #endif
124
125 #ifdef CMK_HAS_ASCTIME
126 #include <time.h>
127 #endif
128
129 #ifdef CMK_CUDA
130 #include "cuda-hybrid-api.h"
131 #endif
132
133 #include "quiescence.h"
134
135 #if USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
136 #include <mpi.h>
137 #endif
138
139 //int cur_restart_phase = 1;      /* checkpointing/restarting phase counter */
140 CpvDeclare(int,_curRestartPhase);
141 static int CsdLocalMax = CSD_LOCAL_MAX_DEFAULT;
142
143 int CharmLibInterOperate = 0;
144 CpvDeclare(int,charmLibExitFlag);
145
146 CpvStaticDeclare(int, CmiMainHandlerIDP); /* Main handler for _CmiMultipleSend that is run on every node */
147
148 #if CMK_MEM_CHECKPOINT
149 void (*notify_crash_fn)(int) = NULL;
150 #endif
151
152 CpvDeclare(char *, _validProcessors);
153
154 /*****************************************************************************
155  *
156  * Unix Stub Functions
157  *
158  ****************************************************************************/
159
160 #ifdef MEMMONITOR
161 typedef unsigned long mmulong;
162 CpvDeclare(mmulong,MemoryUsage);
163 CpvDeclare(mmulong,HiWaterMark);
164 CpvDeclare(mmulong,ReportedHiWaterMark);
165 CpvDeclare(int,AllocCount);
166 CpvDeclare(int,BlocksAllocated);
167 #endif
168
169 #define MAX_HANDLERS 512
170
171 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
172 CpvDeclare(int,expIOFlushFlag);
173 #if CMI_IO_BUFFER_EXPLICIT
174 /* 250k not too large depending on how slow terminal IO is */
175 #define DEFAULT_IO_BUFFER_SIZE 250000
176 CpvDeclare(char*,explicitIOBuffer);
177 CpvDeclare(int,expIOBufferSize);
178 #endif
179 #endif
180
181 #if CMK_NODE_QUEUE_AVAILABLE
182 void  *CmiGetNonLocalNodeQ();
183 #endif
184
185 CpvDeclare(void*, CsdSchedQueue);
186
187 #if CMK_OUT_OF_CORE
188 /* The Queue where the Prefetch Thread puts the messages from CsdSchedQueue  */
189 CpvDeclare(void*, CsdPrefetchQueue);
190 pthread_mutex_t prefetchLock;
191 #endif
192
193 #if CMK_NODE_QUEUE_AVAILABLE
194 CsvDeclare(void*, CsdNodeQueue);
195 CsvDeclare(CmiNodeLock, CsdNodeQueueLock);
196 #endif
197 CpvDeclare(int,   CsdStopFlag);
198 CpvDeclare(int,   CsdLocalCounter);
199
200 CpvDeclare(int,   _urgentSend);
201
202 CmiNodeLock _smp_mutex;               /* for smp */
203
204 #if CONVERSE_VERSION_VMI
205 void *CMI_VMI_CmiAlloc (int size);
206 void CMI_VMI_CmiFree (void *ptr);
207 #endif
208
209 #if CONVERSE_VERSION_ELAN
210 void* elan_CmiAlloc(int size);
211 #endif
212
213 #if CMK_USE_IBVERBS | CMK_USE_IBUD
214 void *infi_CmiAlloc(int size);
215 void infi_CmiFree(void *ptr);
216 void infi_freeMultipleSend(void *ptr);
217 void infi_unregAndFreeMeta(void *ch);
218 #endif
219
220 #if CMK_BLUEGENEQ && CMK_USE_L2ATOMICS
221 void * CmiAlloc_bgq (int     size);
222 void   CmiFree_bgq  (void  * buf);
223 #endif
224
225 #if CMK_GRID_QUEUE_AVAILABLE
226 CpvDeclare(void *, CkGridObject);
227 CpvDeclare(void *, CsdGridQueue);
228 #endif
229
230 #if CMK_CRAYXE
231 void* LrtsAlloc(int, int);
232 void  LrtsFree(void*);
233 #endif
234
235 CpvStaticDeclare(int, cmiMyPeIdle);
236 int CmiIsMyNodeIdle();
237
238 /*****************************************************************************
239  *
240  * Command-Line Argument (CLA) parsing routines.
241  *
242  *****************************************************************************/
243
244 static int usageChecked=0; /* set when argv has been searched for a usage request */
245 static int printUsage=0; /* if set, print command-line usage information */
246 static const char *CLAformatString="%20s %10s %s\n";
247
248 /** This little list of CLA's holds the argument descriptions until it's
249    safe to print them--it's needed because the net- versions don't have 
250    printf until they're pretty well started.
251  */
252 typedef struct {
253         const char *arg; /* Flag name, like "-foo"*/
254         const char *param; /* Argument's parameter type, like "integer" or "none"*/
255         const char *desc; /* Human-readable description of what it does */
256 } CLA;
257 static int CLAlistLen=0;
258 static int CLAlistMax=0;
259 static CLA *CLAlist=NULL;
260
261 /** Add this CLA */
262 static void CmiAddCLA(const char *arg,const char *param,const char *desc) {
263         int i;
264         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
265         if (desc==NULL) return; /*It's an internal argument*/
266         if (usageChecked) { /* Printf should work now */
267                 if (printUsage)
268                         CmiPrintf(CLAformatString,arg,param,desc);
269         }
270         else { /* Printf doesn't work yet-- just add to the list.
271                 This assumes the const char *'s are static references,
272                 which is probably reasonable. */
273                 i=CLAlistLen++;
274                 if (CLAlistLen>CLAlistMax) { /*Grow the CLA list */
275                         CLAlistMax=16+2*CLAlistLen;
276                         CLAlist=realloc(CLAlist,sizeof(CLA)*CLAlistMax);\
277                 }
278                 CLAlist[i].arg=arg;
279                 CLAlist[i].param=param;
280                 CLAlist[i].desc=desc;
281         }
282 }
283
284 /** Print out the stored list of CLA's */
285 static void CmiPrintCLAs(void) {
286         int i;
287         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
288         CmiPrintf("Converse Machine Command-line Parameters:\n ");
289         CmiPrintf(CLAformatString,"Option:","Parameter:","Description:");
290         for (i=0;i<CLAlistLen;i++) {
291                 CLA *c=&CLAlist[i];
292                 CmiPrintf(CLAformatString,c->arg,c->param,c->desc);
293         }
294 }
295
296 /**
297  * Determines if command-line usage information should be printed--
298  * that is, if a "-?", "-h", or "--help" flag is present.
299  * Must be called after printf is setup.
300  */
301 void CmiArgInit(char **argv) {
302         int i;
303         for (i=0;argv[i]!=NULL;i++)
304         {
305                 if (0==strcmp(argv[i],"-?") ||
306                     0==strcmp(argv[i],"-h") ||
307                     0==strcmp(argv[i],"--help")) 
308                 {
309                         printUsage=1;
310                         /* Don't delete arg:  CmiDeleteArgs(&argv[i],1);
311                           Leave it there for user program to see... */
312                         CmiPrintCLAs();
313                 }
314         }
315         if (CmiMyPe()==0) { /* Throw away list of stored CLA's */
316                 CLAlistLen=CLAlistMax=0;
317                 free(CLAlist); CLAlist=NULL;
318         }
319         usageChecked=1;
320 }
321
322 /** Return 1 if we're currently printing command-line usage information. */
323 int CmiArgGivingUsage(void) {
324         return (CmiMyPe()==0) && printUsage;
325 }
326
327 /** Identifies the module that accepts the following command-line parameters */
328 void CmiArgGroup(const char *parentName,const char *groupName) {
329         if (CmiArgGivingUsage()) {
330                 if (groupName==NULL) groupName=parentName; /* Start of a new group */
331                 CmiPrintf("\n%s Command-line Parameters:\n",groupName);
332         }
333 }
334
335 /** Count the number of non-NULL arguments in list*/
336 int CmiGetArgc(char **argv)
337 {
338         int i=0,argc=0;
339         if (argv)
340         while (argv[i++]!=NULL)
341                 argc++;
342         return argc;
343 }
344
345 /** Return a new, heap-allocated copy of the argv array*/
346 char **CmiCopyArgs(char **argv)
347 {
348         int argc=CmiGetArgc(argv);
349         char **ret=(char **)malloc(sizeof(char *)*(argc+1));
350         int i;
351         for (i=0;i<argc;i++) {
352                 //printf("Copyin argc %d/%d of lenght %d\n",i,argc,strlen(argv[i]));
353                 ret[i] = (char*)malloc(strlen(argv[i])*sizeof(char));
354                 memcpy(ret[i],argv[i],strlen(argv[i])*sizeof(char)); 
355         }
356         return ret;
357 }
358
359 /** Delete the first k argument from the given list, shifting
360 all other arguments down by k spaces.
361 e.g., argv=={"a","b","c","d",NULL}, k==3 modifies
362 argv={"d",NULL,"c","d",NULL}
363 */
364 void CmiDeleteArgs(char **argv,int k)
365 {
366         int i=0;
367         while ((argv[i]=argv[i+k])!=NULL)
368                 i++;
369 }
370
371 /** Find the given argment and string option in argv.
372 If the argument is present, set the string option and
373 delete both from argv.  If not present, return NULL.
374 e.g., arg=="-name" returns "bob" from
375 argv=={"a.out","foo","-name","bob","bar"},
376 and sets argv={"a.out","foo","bar"};
377 */
378 int CmiGetArgStringDesc(char **argv,const char *arg,char **optDest,const char *desc)
379 {
380         int i;
381         CmiAddCLA(arg,"string",desc);
382         for (i=0;argv[i]!=NULL;i++)
383                 if (0==strcmp(argv[i],arg))
384                 {/*We found the argument*/
385                         if (argv[i+1]==NULL) CmiAbort("Argument not complete!");
386                         *optDest=argv[i+1];
387                         CmiDeleteArgs(&argv[i],2);
388                         return 1;
389                 }
390         return 0;/*Didn't find the argument*/
391 }
392 int CmiGetArgString(char **argv,const char *arg,char **optDest) {
393         return CmiGetArgStringDesc(argv,arg,optDest,"");
394 }
395
396 /** Find the given argument and floating-point option in argv.
397 Remove it and return 1; or return 0.
398 */
399 int CmiGetArgDoubleDesc(char **argv,const char *arg,double *optDest,const char *desc) {
400         char *number=NULL;
401         CmiAddCLA(arg,"number",desc);
402         if (!CmiGetArgStringDesc(argv,arg,&number,NULL)) return 0;
403         if (1!=sscanf(number,"%lg",optDest)) return 0;
404         return 1;
405 }
406 int CmiGetArgDouble(char **argv,const char *arg,double *optDest) {
407         return CmiGetArgDoubleDesc(argv,arg,optDest,"");
408 }
409
410 /** Find the given argument and integer option in argv.
411 If the argument is present, parse and set the numeric option,
412 delete both from argv, and return 1. If not present, return 0.
413 e.g., arg=="-pack" matches argv=={...,"-pack","27",...},
414 argv=={...,"-pack0xf8",...}, and argv=={...,"-pack=0777",...};
415 but not argv=={...,"-packsize",...}.
416 */
417 int CmiGetArgIntDesc(char **argv,const char *arg,int *optDest,const char *desc)
418 {
419         int i;
420         int argLen=strlen(arg);
421         CmiAddCLA(arg,"integer",desc);
422         for (i=0;argv[i]!=NULL;i++)
423                 if (0==strncmp(argv[i],arg,argLen))
424                 {/*We *may* have found the argument*/
425                         const char *opt=NULL;
426                         int nDel=0;
427                         switch(argv[i][argLen]) {
428                         case 0: /* like "-p","27" */
429                                 opt=argv[i+1]; nDel=2; break;
430                         case '=': /* like "-p=27" */
431                                 opt=&argv[i][argLen+1]; nDel=1; break;
432                         case '-':case '+':
433                         case '0':case '1':case '2':case '3':case '4':
434                         case '5':case '6':case '7':case '8':case '9':
435                                 /* like "-p27" */
436                                 opt=&argv[i][argLen]; nDel=1; break;
437                         default:
438                                 continue; /*False alarm-- skip it*/
439                         }
440                         if (opt==NULL) continue; /*False alarm*/
441                         if (sscanf(opt,"%i",optDest)<1) {
442                         /*Bad command line argument-- die*/
443                                 fprintf(stderr,"Cannot parse %s option '%s' "
444                                         "as an integer.\n",arg,opt);
445                                 CmiAbort("Bad command-line argument\n");
446                         }
447                         CmiDeleteArgs(&argv[i],nDel);
448                         return 1;
449                 }
450         return 0;/*Didn't find the argument-- dest is unchanged*/       
451 }
452 int CmiGetArgInt(char **argv,const char *arg,int *optDest) {
453         return CmiGetArgIntDesc(argv,arg,optDest,"");
454 }
455
456 int CmiGetArgLongDesc(char **argv,const char *arg,CmiInt8 *optDest,const char *desc)
457 {
458         int i;
459         int argLen=strlen(arg);
460         CmiAddCLA(arg,"integer",desc);
461         for (i=0;argv[i]!=NULL;i++)
462                 if (0==strncmp(argv[i],arg,argLen))
463                 {/*We *may* have found the argument*/
464                         const char *opt=NULL;
465                         int nDel=0;
466                         switch(argv[i][argLen]) {
467                         case 0: /* like "-p","27" */
468                                 opt=argv[i+1]; nDel=2; break;
469                         case '=': /* like "-p=27" */
470                                 opt=&argv[i][argLen+1]; nDel=1; break;
471                         case '-':case '+':
472                         case '0':case '1':case '2':case '3':case '4':
473                         case '5':case '6':case '7':case '8':case '9':
474                                 /* like "-p27" */
475                                 opt=&argv[i][argLen]; nDel=1; break;
476                         default:
477                                 continue; /*False alarm-- skip it*/
478                         }
479                         if (opt==NULL) continue; /*False alarm*/
480                         if (sscanf(opt,"%ld",optDest)<1) {
481                         /*Bad command line argument-- die*/
482                                 fprintf(stderr,"Cannot parse %s option '%s' "
483                                         "as a long integer.\n",arg,opt);
484                                 CmiAbort("Bad command-line argument\n");
485                         }
486                         CmiDeleteArgs(&argv[i],nDel);
487                         return 1;
488                 }
489         return 0;/*Didn't find the argument-- dest is unchanged*/       
490 }
491 int CmiGetArgLong(char **argv,const char *arg,CmiInt8 *optDest) {
492         return CmiGetArgLongDesc(argv,arg,optDest,"");
493 }
494
495 /** Find the given argument in argv.  If present, delete
496 it and return 1; if not present, return 0.
497 e.g., arg=="-foo" matches argv=={...,"-foo",...} but not
498 argv={...,"-foobar",...}.
499 */
500 int CmiGetArgFlagDesc(char **argv,const char *arg,const char *desc)
501 {
502         int i;
503         CmiAddCLA(arg,"",desc);
504         for (i=0;argv[i]!=NULL;i++)
505                 if (0==strcmp(argv[i],arg))
506                 {/*We found the argument*/
507                         CmiDeleteArgs(&argv[i],1);
508                         return 1;
509                 }
510         return 0;/*Didn't find the argument*/
511 }
512 int CmiGetArgFlag(char **argv,const char *arg) {
513         return CmiGetArgFlagDesc(argv,arg,"");
514 }
515
516
517 /*****************************************************************************
518  *
519  * Stack tracing routines.
520  *
521  *****************************************************************************/
522 #include "cmibacktrace.c"
523
524 /*
525 Convert "X(Y) Z" to "Y Z"-- remove text prior to first '(', and supress
526 the next parenthesis.  Operates in-place on the character data.
527 or Convert X(Y) to "Y" only, when trimname=1
528 */
529 static char *_implTrimParenthesis(char *str, int trimname) {
530   char *lParen=str, *ret=NULL, *rParen=NULL;
531   while (*lParen!='(') {
532     if (*lParen==0) return str; /* No left parenthesis at all. */
533     lParen++;
534   }
535   /* now *lParen=='(', so trim it*/
536   ret=lParen+1;
537   rParen=ret;
538   while (*rParen!=')') {
539     if (*rParen==0) return ret; /* No right parenthesis at all. */
540     rParen++;
541   }
542   /* now *rParen==')', so trim it*/
543   *rParen=trimname?0:' ';
544   return ret;  
545 }
546
547 /*
548 Return the text description of this trimmed routine name, if 
549 it's a system-generated routine where we should stop printing. 
550 This is probably overkill, but improves the appearance of callbacks.
551 */
552 static const char* _implGetBacktraceSys(const char *name) {
553   if (0==strncmp(name,"_call",5)) 
554   { /*it might be something we're interested in*/
555     if (0==strncmp(name,"_call_",6)) return "Call Entry Method";
556     if (0==strncmp(name,"_callthr_",9)) return "Call Threaded Entry Method";
557   }
558   if (0==strncmp(name,"CthResume",9)) return "Resumed thread";
559   if (0==strncmp(name,"qt_args",7)) return "Converse thread";
560   
561   return 0; /*ordinary user routine-- just print normally*/
562 }
563
564 /** Print out the names of these function pointers. */
565 void CmiBacktracePrint(void **retPtrs,int nLevels) {
566   if (nLevels>0) {
567     int i;
568     char **names=CmiBacktraceLookup(retPtrs,nLevels);
569     if (names==NULL) return;
570     CmiPrintf("[%d] Stack Traceback:\n", CmiMyPe());
571     for (i=0;i<nLevels;i++) {
572       if (names[i] == NULL) continue;
573       {
574       const char *trimmed=_implTrimParenthesis(names[i], 0);
575       const char *print=trimmed;
576       const char *sys=_implGetBacktraceSys(print);
577       if (sys) {
578           CmiPrintf("  [%d] Charm++ Runtime: %s (%s)\n",i,sys,print);
579           break; /*Stop when we hit Charm++ runtime.*/
580       } else {
581           CmiPrintf("  [%d:%d] %s\n",CmiMyPe(),i,print);
582       }
583      }
584     }
585     free(names);
586   }
587 }
588
589 /* Print (to stdout) the names of the functions that have been 
590    called up to this point. nSkip is the number of routines on the
591    top of the stack to *not* print out. */
592 void CmiPrintStackTrace(int nSkip) {
593 #if CMK_USE_BACKTRACE
594         int nLevels=max_stack;
595         void *stackPtrs[max_stack];
596         CmiBacktraceRecord(stackPtrs,1+nSkip,&nLevels);
597         CmiBacktracePrint(stackPtrs,nLevels);
598 #endif
599 }
600
601 int CmiIsFortranLibraryCall() {
602 #if CMK_USE_BACKTRACE
603   int ret = 0;
604   int nLevels=9;
605   void *stackPtrs[18];
606   CmiBacktraceRecord(stackPtrs,1,&nLevels);
607   if (nLevels>0) {
608     int i;
609     char **names=CmiBacktraceLookup(stackPtrs,nLevels);
610     if (names==NULL) return 0;
611     for (i=0;i<nLevels;i++) {
612       if (names[i] == NULL) continue;
613       const char *trimmed=_implTrimParenthesis(names[i], 1);
614       if (strncmp(trimmed, "for__", 5) == 0                /* ifort */
615           || strncmp(trimmed, "_xlf", 4) == 0               /* xlf90 */
616           || strncmp(trimmed, "_xlfBeginIO", 11) == 0 
617           || strncmp(trimmed, "_gfortran_", 10) == 0 
618          )
619           {  /* CmiPrintf("[%d] NAME:%s\n", CmiMyPe(), trimmed); */
620              ret = 1; break; }
621     }
622     free(names);
623   }
624   return ret;
625 #else
626   return 0;
627 #endif
628 }
629
630 /*****************************************************************************
631  *
632  * Statistics: currently, the following statistics are not updated by converse.
633  *
634  *****************************************************************************/
635
636 CpvDeclare(int, CstatsMaxChareQueueLength);
637 CpvDeclare(int, CstatsMaxForChareQueueLength);
638 CpvDeclare(int, CstatsMaxFixedChareQueueLength);
639 CpvStaticDeclare(int, CstatPrintQueueStatsFlag);
640 CpvStaticDeclare(int, CstatPrintMemStatsFlag);
641
642 void CstatsInit(argv)
643 char **argv;
644 {
645
646 #ifdef MEMMONITOR
647   CpvInitialize(mmulong,MemoryUsage);
648   CpvAccess(MemoryUsage) = 0;
649   CpvInitialize(mmulong,HiWaterMark);
650   CpvAccess(HiWaterMark) = 0;
651   CpvInitialize(mmulong,ReportedHiWaterMark);
652   CpvAccess(ReportedHiWaterMark) = 0;
653   CpvInitialize(int,AllocCount);
654   CpvAccess(AllocCount) = 0;
655   CpvInitialize(int,BlocksAllocated);
656   CpvAccess(BlocksAllocated) = 0;
657 #endif
658
659   CpvInitialize(int, CstatsMaxChareQueueLength);
660   CpvInitialize(int, CstatsMaxForChareQueueLength);
661   CpvInitialize(int, CstatsMaxFixedChareQueueLength);
662   CpvInitialize(int, CstatPrintQueueStatsFlag);
663   CpvInitialize(int, CstatPrintMemStatsFlag);
664
665   CpvAccess(CstatsMaxChareQueueLength) = 0;
666   CpvAccess(CstatsMaxForChareQueueLength) = 0;
667   CpvAccess(CstatsMaxFixedChareQueueLength) = 0;
668   CpvAccess(CstatPrintQueueStatsFlag) = 0;
669   CpvAccess(CstatPrintMemStatsFlag) = 0;
670
671 #if 0
672   if (CmiGetArgFlagDesc(argv,"+mems", "Print memory statistics at shutdown"))
673     CpvAccess(CstatPrintMemStatsFlag)=1;
674   if (CmiGetArgFlagDesc(argv,"+qs", "Print queue statistics at shutdown"))
675     CpvAccess(CstatPrintQueueStatsFlag)=1;
676 #endif
677 }
678
679 int CstatMemory(i)
680 int i;
681 {
682   return 0;
683 }
684
685 int CstatPrintQueueStats()
686 {
687   return CpvAccess(CstatPrintQueueStatsFlag);
688 }
689
690 int CstatPrintMemStats()
691 {
692   return CpvAccess(CstatPrintMemStatsFlag);
693 }
694
695 /*****************************************************************************
696  *
697  * Cmi handler registration
698  *
699  *****************************************************************************/
700
701 CpvDeclare(CmiHandlerInfo*, CmiHandlerTable);
702 CpvStaticDeclare(int  , CmiHandlerCount);
703 CpvStaticDeclare(int  , CmiHandlerLocal);
704 CpvStaticDeclare(int  , CmiHandlerGlobal);
705 CpvDeclare(int,         CmiHandlerMax);
706
707 static void CmiExtendHandlerTable(int atLeastLen) {
708     int max = CpvAccess(CmiHandlerMax);
709     int newmax = (atLeastLen+(atLeastLen>>2)+32);
710     int bytes = max*sizeof(CmiHandlerInfo);
711     int newbytes = newmax*sizeof(CmiHandlerInfo);
712     CmiHandlerInfo *nu = (CmiHandlerInfo*)malloc(newbytes);
713     CmiHandlerInfo *tab = CpvAccess(CmiHandlerTable);
714     _MEMCHECK(nu);
715     memcpy(nu, tab, bytes);
716     memset(((char *)nu)+bytes, 0, (newbytes-bytes));
717     free(tab); tab=nu;
718     CpvAccess(CmiHandlerTable) = tab;
719     CpvAccess(CmiHandlerMax) = newmax;
720 }
721
722 void CmiNumberHandler(int n, CmiHandler h)
723 {
724   CmiHandlerInfo *tab;
725   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
726   tab = CpvAccess(CmiHandlerTable);
727   tab[n].hdlr = (CmiHandlerEx)h; /* LIE!  This assumes extra pointer will be ignored!*/
728   tab[n].userPtr = 0;
729 }
730 void CmiNumberHandlerEx(int n, CmiHandlerEx h,void *userPtr) {
731   CmiHandlerInfo *tab;
732   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
733   tab = CpvAccess(CmiHandlerTable);
734   tab[n].hdlr = h;
735   tab[n].userPtr=userPtr;
736 }
737
738 #if CMI_LOCAL_GLOBAL_AVAILABLE /*Leave room for local and global handlers*/
739 #  define DIST_BETWEEN_HANDLERS 3
740 #else /*No local or global handlers; ordinary handlers are back-to-back*/
741 #  define DIST_BETWEEN_HANDLERS 1
742 #endif
743
744 int CmiRegisterHandler(CmiHandler h)
745 {
746   int Count = CpvAccess(CmiHandlerCount);
747   CmiNumberHandler(Count, h);
748   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
749   return Count;
750 }
751 int CmiRegisterHandlerEx(CmiHandlerEx h,void *userPtr)
752 {
753   int Count = CpvAccess(CmiHandlerCount);
754   CmiNumberHandlerEx(Count, h, userPtr);
755   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
756   return Count;
757 }
758
759 #if CMI_LOCAL_GLOBAL_AVAILABLE
760 int CmiRegisterHandlerLocal(h)
761 CmiHandler h;
762 {
763   int Local = CpvAccess(CmiHandlerLocal);
764   CmiNumberHandler(Local, h);
765   CpvAccess(CmiHandlerLocal) = Local+3;
766   return Local;
767 }
768
769 int CmiRegisterHandlerGlobal(h)
770 CmiHandler h;
771 {
772   int Global = CpvAccess(CmiHandlerGlobal);
773   if (CmiMyPe()!=0) 
774     CmiError("CmiRegisterHandlerGlobal must only be called on PE 0.\n");
775   CmiNumberHandler(Global, h);
776   CpvAccess(CmiHandlerGlobal) = Global+3;
777   return Global;
778 }
779 #endif
780
781 static void _cmiZeroHandler(void *msg) {
782         CmiAbort("Converse zero handler executed-- was a message corrupted?\n");
783 }
784
785 static void CmiHandlerInit()
786 {
787   CpvInitialize(CmiHandlerInfo *, CmiHandlerTable);
788   CpvInitialize(int         , CmiHandlerCount);
789   CpvInitialize(int         , CmiHandlerLocal);
790   CpvInitialize(int         , CmiHandlerGlobal);
791   CpvInitialize(int         , CmiHandlerMax);
792   CpvAccess(CmiHandlerCount)  = 0;
793   CpvAccess(CmiHandlerLocal)  = 1;
794   CpvAccess(CmiHandlerGlobal) = 2;
795   CpvAccess(CmiHandlerMax) = 0; /* Table will be extended on the first registration*/
796   CpvAccess(CmiHandlerTable) = NULL;
797   CmiRegisterHandler((CmiHandler)_cmiZeroHandler);
798 }
799
800
801 /******************************************************************************
802  *
803  * CmiTimer
804  *
805  * Here are two possible implementations of CmiTimer.  Some machines don't
806  * select either, and define the timer in machine.c instead.
807  *
808  *****************************************************************************/
809
810 #if CMK_HAS_ASCTIME
811
812 char *CmiPrintDate()
813 {
814   struct tm *local;
815   time_t t;
816
817   t = time(NULL);
818   local = localtime(&t);
819   return asctime(local);
820 }
821
822 #else
823
824 char *CmiPrintDate()
825 {
826   return "N/A";
827 }
828
829 #endif
830
831 static int _absoluteTime = 0;
832
833 #if CMK_TIMER_USE_TIMES
834
835 CpvStaticDeclare(double, clocktick);
836 CpvStaticDeclare(int,inittime_wallclock);
837 CpvStaticDeclare(int,inittime_virtual);
838
839 int CmiTimerIsSynchronized()
840 {
841   return 0;
842 }
843
844 int CmiTimerAbsolute()
845 {
846   return 0;
847 }
848
849 double CmiStartTimer()
850 {
851   return 0.0;
852 }
853
854 double CmiInitTime()
855 {
856   return CpvAccess(inittime_wallclock);
857 }
858
859 void CmiTimerInit(char **argv)
860 {
861   struct tms temp;
862   CpvInitialize(double, clocktick);
863   CpvInitialize(int, inittime_wallclock);
864   CpvInitialize(int, inittime_virtual);
865   CpvAccess(inittime_wallclock) = times(&temp);
866   CpvAccess(inittime_virtual) = temp.tms_utime + temp.tms_stime;
867   CpvAccess(clocktick) = 1.0 / (sysconf(_SC_CLK_TCK));
868 }
869
870 double CmiWallTimer()
871 {
872   struct tms temp;
873   double currenttime;
874   int now;
875
876   now = times(&temp);
877   currenttime = (now - CpvAccess(inittime_wallclock)) * CpvAccess(clocktick);
878   return (currenttime);
879 }
880
881 double CmiCpuTimer()
882 {
883   struct tms temp;
884   double currenttime;
885   int now;
886
887   times(&temp);
888   now = temp.tms_stime + temp.tms_utime;
889   currenttime = (now - CpvAccess(inittime_virtual)) * CpvAccess(clocktick);
890   return (currenttime);
891 }
892
893 double CmiTimer()
894 {
895   return CmiCpuTimer();
896 }
897
898 #endif
899
900 #if CMK_TIMER_USE_GETRUSAGE
901
902 #if CMK_SMP
903 # if CMK_HAS_RUSAGE_THREAD
904 #define RUSAGE_WHO        1   /* RUSAGE_THREAD, only in latest Linux kernels */
905 #else
906 #undef RUSAGE_WHO
907 #endif
908 #else
909 #define RUSAGE_WHO        0
910 #endif
911
912 static double inittime_wallclock;
913 CpvStaticDeclare(double, inittime_virtual);
914
915 int CmiTimerIsSynchronized()
916 {
917   return 0;
918 }
919
920 int CmiTimerAbsolute()
921 {
922   return _absoluteTime;
923 }
924
925 double CmiStartTimer()
926 {
927   return 0.0;
928 }
929
930 double CmiInitTime()
931 {
932   return inittime_wallclock;
933 }
934
935 void CmiTimerInit(char **argv)
936 {
937   struct timeval tv;
938   struct rusage ru;
939   CpvInitialize(double, inittime_virtual);
940
941   _absoluteTime = CmiGetArgFlagDesc(argv,"+useAbsoluteTime", "Use system's absolute time as wallclock time.");
942
943 #if !CMK_MEM_CHECKPOINT && !_FAULT_MLOG_ && !_FAULT_CAUSAL_
944   /* try to synchronize calling barrier */
945   CmiBarrier();
946   CmiBarrier();
947   CmiBarrier();
948 #endif
949
950   gettimeofday(&tv,0);
951   inittime_wallclock = (tv.tv_sec * 1.0) + (tv.tv_usec*0.000001);
952 #ifndef RUSAGE_WHO
953   CpvAccess(inittime_virtual) = inittime_wallclock;
954 #else
955   getrusage(RUSAGE_WHO, &ru); 
956   CpvAccess(inittime_virtual) =
957     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
958     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
959 #endif
960
961 #if ! CMK_MEM_CHECKPOINT && !_FAULT_MLOG_ && !_FAULT_CAUSAL_
962   CmiBarrier();
963 /*  CmiBarrierZero(); */
964 #endif
965 }
966
967 double CmiCpuTimer()
968 {
969 #ifndef RUSAGE_WHO
970   return CmiWallTimer();
971 #else
972   struct rusage ru;
973   double currenttime;
974
975   getrusage(RUSAGE_WHO, &ru);
976   currenttime =
977     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
978     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
979   
980   return currenttime - CpvAccess(inittime_virtual);
981 #endif
982 }
983
984 static double lastT = -1.0;
985
986 double CmiWallTimer()
987 {
988   struct timeval tv;
989   double currenttime;
990
991   gettimeofday(&tv,0);
992   currenttime = (tv.tv_sec * 1.0) + (tv.tv_usec * 0.000001);
993 #if CMK_ERROR_CHECKING
994   if (lastT > 0.0 && currenttime < lastT) {
995     currenttime = lastT;
996   }
997   lastT = currenttime;
998 #endif
999   return _absoluteTime?currenttime:currenttime - inittime_wallclock;
1000 }
1001
1002 double CmiTimer()
1003 {
1004   return CmiCpuTimer();
1005 }
1006
1007 #endif
1008
1009 #if CMK_TIMER_USE_RDTSC
1010
1011 static double readMHz(void)
1012 {
1013   double x;
1014   char str[1000];
1015   char buf[100];
1016   FILE *fp;
1017   CmiLock(_smp_mutex);
1018   fp = fopen("/proc/cpuinfo", "r");
1019   if (fp != NULL)
1020   while(fgets(str, 1000, fp)!=0) {
1021     if(sscanf(str, "cpu MHz%[^:]",buf)==1)
1022     {
1023       char *s = strchr(str, ':'); s=s+1;
1024       sscanf(s, "%lf", &x);
1025       fclose(fp);
1026       CmiUnlock(_smp_mutex);
1027       return x;
1028     }
1029   }
1030   CmiUnlock(_smp_mutex);
1031   CmiAbort("Cannot read CPU MHz from /proc/cpuinfo file.");
1032   return 0.0;
1033 }
1034
1035 double _cpu_speed_factor;
1036 CpvStaticDeclare(double, inittime_virtual);
1037 CpvStaticDeclare(double, inittime_walltime);
1038
1039 double  CmiStartTimer(void)
1040 {
1041   return CpvAccess(inittime_walltime);
1042 }
1043
1044 double CmiInitTime()
1045 {
1046   return CpvAccess(inittime_walltime);
1047 }
1048
1049 void CmiTimerInit(char **argv)
1050 {
1051   struct rusage ru;
1052
1053   CmiBarrier();
1054   CmiBarrier();
1055
1056   _cpu_speed_factor = 1.0/(readMHz()*1.0e6); 
1057   rdtsc(); rdtsc(); rdtsc(); rdtsc(); rdtsc();
1058   CpvInitialize(double, inittime_walltime);
1059   CpvAccess(inittime_walltime) = CmiWallTimer();
1060   CpvInitialize(double, inittime_virtual);
1061   getrusage(0, &ru); 
1062   CpvAccess(inittime_virtual) =
1063     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1064     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1065
1066   CmiBarrierZero();
1067 }
1068
1069 double CmiCpuTimer()
1070 {
1071   struct rusage ru;
1072   double currenttime;
1073
1074   getrusage(0, &ru);
1075   currenttime =
1076     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1077     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1078   return currenttime - CpvAccess(inittime_virtual);
1079 }
1080
1081 #endif
1082
1083 #if CMK_BLUEGENEL || CMK_BLUEGENEP
1084 #include "dcopy.h"
1085 #endif
1086
1087 #if CMK_TIMER_USE_BLUEGENEL
1088
1089 #include "rts.h"
1090
1091 #if 0 
1092 #define SPRN_TBRL 0x10C  /* Time Base Read Lower Register (user & sup R/O) */
1093 #define SPRN_TBRU 0x10D  /* Time Base Read Upper Register (user & sup R/O) */
1094 #define SPRN_PIR  0x11E  /* CPU id */
1095
1096 static inline unsigned long long BGLTimebase(void)
1097 {
1098   unsigned volatile u1, u2, lo;
1099   union
1100   {
1101     struct { unsigned hi, lo; } w;
1102     unsigned long long d;
1103   } result;
1104                                                                                 
1105   do {
1106     asm volatile ("mfspr %0,%1" : "=r" (u1) : "i" (SPRN_TBRU));
1107     asm volatile ("mfspr %0,%1" : "=r" (lo) : "i" (SPRN_TBRL));
1108     asm volatile ("mfspr %0,%1" : "=r" (u2) : "i" (SPRN_TBRU));
1109   } while (u1!=u2);
1110                                                                                 
1111   result.w.lo = lo;
1112   result.w.hi = u2;
1113   return result.d;
1114 }
1115 #endif
1116
1117 static unsigned long long inittime_wallclock = 0;
1118 CpvStaticDeclare(double, clocktick);
1119
1120 int CmiTimerIsSynchronized()
1121 {
1122   return 0;
1123 }
1124
1125 int CmiTimerAbsolute()
1126 {
1127   return 1;
1128 }
1129
1130 double CmiStartTimer()
1131 {
1132   return 0.0;
1133 }
1134
1135 double CmiInitTime()
1136 {
1137   return inittime_wallclock;
1138 }
1139
1140 void CmiTimerInit(char **argv)
1141 {
1142   BGLPersonality dst;
1143   CpvInitialize(double, clocktick);
1144   int size = sizeof(BGLPersonality);
1145   rts_get_personality(&dst, size);
1146   CpvAccess(clocktick) = 1.0 / dst.clockHz;
1147
1148   /* try to synchronize calling barrier */
1149   CmiBarrier();
1150   CmiBarrier();
1151   CmiBarrier();
1152
1153   /* inittime_wallclock = rts_get_timebase(); */
1154   inittime_wallclock = 0.0;    /* use bgl absolute time */
1155 }
1156
1157 double CmiWallTimer()
1158 {
1159   unsigned long long currenttime;
1160   currenttime = rts_get_timebase();
1161   //return CpvAccess(clocktick)*(currenttime-inittime_wallclock);
1162   return CpvAccess(clocktick)*(currenttime);
1163 }
1164
1165 double CmiCpuTimer()
1166 {
1167   return CmiWallTimer();
1168 }
1169
1170 double CmiTimer()
1171 {
1172   return CmiWallTimer();
1173 }
1174
1175 #endif
1176
1177 #if CMK_TIMER_USE_BLUEGENEP  /* This module just compiles with GCC charm. */
1178
1179 int CmiTimerAbsolute()
1180 {
1181   return 0;
1182 }
1183
1184 double CmiStartTimer()
1185 {
1186   return 0.0;
1187 }
1188
1189 double CmiInitTime()
1190 {
1191   return 0.0;
1192 }
1193
1194 void CmiTimerInit(char **argv) {}
1195
1196 #include "dcmf.h"
1197
1198 double CmiWallTimer () {
1199   return DCMF_Timer();
1200 }
1201
1202 double CmiCpuTimer()
1203 {
1204   return CmiWallTimer();
1205 }
1206
1207 double CmiTimer()
1208 {
1209   return CmiWallTimer();
1210 }
1211 #endif
1212
1213
1214 #if CMK_TIMER_USE_BLUEGENEQ  /* This module just compiles with GCC charm. */
1215
1216 CpvStaticDeclare(unsigned long, inittime);
1217 CpvStaticDeclare(double, clocktick);
1218
1219 int CmiTimerIsSynchronized()
1220 {
1221   return 1;
1222 }
1223
1224 int CmiTimerAbsolute()
1225 {
1226   return 0;
1227 }
1228
1229 #include "hwi/include/bqc/A2_inlines.h"
1230 #include "spi/include/kernel/process.h"
1231
1232 double CmiStartTimer()
1233 {
1234   return 0.0;
1235 }
1236
1237 double CmiInitTime()
1238 {
1239   return CpvAccess(inittime);
1240 }
1241
1242 void CmiTimerInit(char **argv)
1243 {
1244   CpvInitialize(double, clocktick);
1245   CpvInitialize(unsigned long, inittime);
1246
1247   Personality_t  pers;
1248   Kernel_GetPersonality(&pers, sizeof(pers));
1249   uint32_t clockMhz = pers.Kernel_Config.FreqMHz;
1250   CpvAccess(clocktick) = 1.0 / (clockMhz * 1e6); 
1251
1252   /*fprintf(stderr, "Blue Gene/Q running at clock speed of %d Mhz\n", clockMhz);*/
1253
1254   /* try to synchronize calling barrier */
1255 #if !CMK_MEM_CHECKPOINT && !_FAULT_MLOG_ && !_FAULT_CAUSAL_
1256   CmiBarrier();
1257   CmiBarrier();
1258   CmiBarrier();
1259 #endif
1260   CpvAccess(inittime) = GetTimeBase (); 
1261 }
1262
1263 double CmiWallTimer()
1264 {
1265   unsigned long long currenttime;
1266   currenttime = GetTimeBase();
1267   return CpvAccess(clocktick)*(currenttime-CpvAccess(inittime));
1268 }
1269
1270 double CmiCpuTimer()
1271 {
1272   return CmiWallTimer();
1273 }
1274
1275 double CmiTimer()
1276 {
1277   return CmiWallTimer();
1278 }
1279
1280 #endif
1281
1282
1283 #if CMK_TIMER_USE_WIN32API
1284
1285 CpvStaticDeclare(double, inittime_wallclock);
1286 CpvStaticDeclare(double, inittime_virtual);
1287
1288 double CmiStartTimer()
1289 {
1290   return 0.0;
1291 }
1292
1293 int CmiTimerAbsolute()
1294 {
1295   return 0;
1296 }
1297
1298 double CmiInitTime()
1299 {
1300   return CpvAccess(inittime_wallclock);
1301 }
1302
1303 void CmiTimerInit(char **argv)
1304 {
1305 #ifdef __CYGWIN__
1306         struct timeb tv;
1307 #else
1308         struct _timeb tv;
1309 #endif
1310         clock_t       ru;
1311
1312         CpvInitialize(double, inittime_wallclock);
1313         CpvInitialize(double, inittime_virtual);
1314         _ftime(&tv);
1315         CpvAccess(inittime_wallclock) = tv.time*1.0 + tv.millitm*0.001;
1316         ru = clock();
1317         CpvAccess(inittime_virtual) = ((double) ru)/CLOCKS_PER_SEC;
1318 }
1319
1320 double CmiCpuTimer()
1321 {
1322         clock_t ru;
1323         double currenttime;
1324
1325         ru = clock();
1326         currenttime = (double) ru/CLOCKS_PER_SEC;
1327
1328         return currenttime - CpvAccess(inittime_virtual);
1329 }
1330
1331 double CmiWallTimer()
1332 {
1333 #ifdef __CYGWIN__
1334         struct timeb tv;
1335 #else
1336         struct _timeb tv;
1337 #endif
1338         double currenttime;
1339
1340         _ftime(&tv);
1341         currenttime = tv.time*1.0 + tv.millitm*0.001;
1342
1343         return currenttime - CpvAccess(inittime_wallclock);
1344 }
1345         
1346
1347 double CmiTimer()
1348 {
1349         return CmiCpuTimer();
1350 }
1351
1352 #endif
1353
1354 #if CMK_TIMER_USE_RTC
1355
1356 #if __crayx1
1357  /* For _rtc() on Cray X1 */
1358 #include <intrinsics.h>
1359 #endif
1360
1361 static double clocktick;
1362 CpvStaticDeclare(long long, inittime_wallclock);
1363
1364 double CmiStartTimer()
1365 {
1366   return 0.0;
1367 }
1368
1369 double CmiInitTime()
1370 {
1371   return CpvAccess(inittime_wallclock);
1372 }
1373
1374 void CmiTimerInit(char **argv)
1375 {
1376   CpvInitialize(long long, inittime_wallclock);
1377   CpvAccess(inittime_wallclock) = _rtc();
1378   clocktick = 1.0 / (double)(sysconf(_SC_SV2_USER_TIME_RATE));
1379 }
1380
1381 int CmiTimerAbsolute()
1382 {
1383   return 0;
1384 }
1385
1386 double CmiWallTimer()
1387 {
1388   long long now;
1389
1390   now = _rtc();
1391   return (clocktick * (now - CpvAccess(inittime_wallclock)));
1392 }
1393
1394 double CmiCpuTimer()
1395 {
1396   return CmiWallTimer();
1397 }
1398
1399 double CmiTimer()
1400 {
1401   return CmiCpuTimer();
1402 }
1403
1404 #endif
1405
1406 #if CMK_TIMER_USE_AIX_READ_TIME
1407
1408 #include <sys/time.h>
1409
1410 static timebasestruct_t inittime_wallclock;
1411 static double clocktick;
1412 CpvStaticDeclare(double, inittime_virtual);
1413
1414 double CmiStartTimer()
1415 {
1416   return 0.0;
1417 }
1418
1419 double CmiInitTime()
1420 {
1421   return inittime_wallclock;
1422 }
1423
1424 void CmiTimerInit(char **argv)
1425 {
1426   struct rusage ru;
1427
1428   if (CmiMyRank() == 0) {
1429     read_wall_time(&inittime_wallclock, TIMEBASE_SZ);
1430     time_base_to_time(&inittime_wallclock, TIMEBASE_SZ);
1431   }
1432
1433   CpvInitialize(double, inittime_virtual);
1434   getrusage(0, &ru);
1435   CpvAccess(inittime_virtual) =
1436     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1437     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1438 }
1439
1440 int CmiTimerAbsolute()
1441 {
1442   return 0;
1443 }
1444
1445 double CmiWallTimer()
1446 {
1447   int secs, n_secs;
1448   double curt;
1449   timebasestruct_t now;
1450   read_wall_time(&now, TIMEBASE_SZ);
1451   time_base_to_time(&now, TIMEBASE_SZ);
1452
1453   secs = now.tb_high - inittime_wallclock.tb_high;
1454   n_secs = now.tb_low - inittime_wallclock.tb_low;
1455   if (n_secs < 0)  {
1456     secs--;
1457     n_secs += 1000000000;
1458   }
1459   curt = secs*1.0 + n_secs*1e-9;
1460   return curt;
1461 }
1462
1463 double CmiCpuTimer()
1464 {
1465   struct rusage ru;
1466   double currenttime;
1467
1468   getrusage(0, &ru);
1469   currenttime =
1470     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1471     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1472   return currenttime - CpvAccess(inittime_virtual);
1473 }
1474
1475 double CmiTimer()
1476 {
1477   return CmiWallTimer();
1478 }
1479
1480 #endif
1481
1482 #ifndef CMK_USE_SPECIAL_MESSAGE_QUEUE_CHECK
1483 /** Return 1 if our outgoing message queue 
1484    for this node is longer than this many bytes. */
1485 int CmiLongSendQueue(int forNode,int longerThanBytes) {
1486   return 0;
1487 }
1488 #endif
1489
1490 #if CMK_SIGNAL_USE_SIGACTION
1491 #include <signal.h>
1492 void CmiSignal(int sig1, int sig2, int sig3, void (*handler)())
1493 {
1494   struct sigaction in, out ;
1495   in.sa_handler = handler;
1496   sigemptyset(&in.sa_mask);
1497   if (sig1) sigaddset(&in.sa_mask, sig1);
1498   if (sig2) sigaddset(&in.sa_mask, sig2);
1499   if (sig3) sigaddset(&in.sa_mask, sig3);
1500   in.sa_flags = 0;
1501   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1502   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1503   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1504 }
1505 #endif
1506
1507 #if CMK_SIGNAL_USE_SIGACTION_WITH_RESTART
1508 #include <signal.h>
1509 void CmiSignal(sig1, sig2, sig3, handler)
1510 int sig1, sig2, sig3;
1511 void (*handler)();
1512 {
1513   struct sigaction in, out ;
1514   in.sa_handler = handler;
1515   sigemptyset(&in.sa_mask);
1516   if (sig1) sigaddset(&in.sa_mask, sig1);
1517   if (sig2) sigaddset(&in.sa_mask, sig2);
1518   if (sig3) sigaddset(&in.sa_mask, sig3);
1519   in.sa_flags = SA_RESTART;
1520   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1521   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1522   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1523 }
1524 #endif
1525
1526 /** 
1527  *  @addtogroup ConverseScheduler
1528  *  @{
1529  */
1530
1531 /*****************************************************************************
1532  * 
1533  * The following is the CsdScheduler function.  A common
1534  * implementation is provided below.  The machine layer can provide an
1535  * alternate implementation if it so desires.
1536  *
1537  * void CmiDeliversInit()
1538  *
1539  *      - CmiInit promises to call this before calling CmiDeliverMsgs
1540  *        or any of the other functions in this section.
1541  *
1542  * int CmiDeliverMsgs(int maxmsgs)
1543  *
1544  *      - CmiDeliverMsgs will retrieve up to maxmsgs that were transmitted
1545  *        with the Cmi, and will invoke their handlers.  It does not wait
1546  *        if no message is unavailable.  Instead, it returns the quantity
1547  *        (maxmsgs-delivered), where delivered is the number of messages it
1548  *        delivered.
1549  *
1550  * void CmiDeliverSpecificMsg(int handlerno)
1551  *
1552  *      - Waits for a message with the specified handler to show up, then
1553  *        invokes the message's handler.  Note that unlike CmiDeliverMsgs,
1554  *        This function _does_ wait.
1555  *
1556  * For this common implementation to work, the machine layer must provide the
1557  * following:
1558  *
1559  * void *CmiGetNonLocal()
1560  *
1561  *      - returns a message just retrieved from some other PE, not from
1562  *        local.  If no such message exists, returns 0.
1563  *
1564  * CpvExtern(CdsFifo, CmiLocalQueue);
1565  *
1566  *      - a FIFO queue containing all messages from the local processor.
1567  *
1568  *****************************************************************************/
1569
1570 void CsdBeginIdle(void)
1571 {
1572   CcdCallBacks();
1573 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1574   _LOG_E_PROC_IDLE();   /* projector */
1575 #endif
1576
1577   CpvAccess(cmiMyPeIdle) = 1;
1578
1579   CcdRaiseCondition(CcdPROCESSOR_BEGIN_IDLE) ;
1580 }
1581
1582 void CsdStillIdle(void)
1583 {
1584   CcdRaiseCondition(CcdPROCESSOR_STILL_IDLE);
1585 }
1586
1587 void CsdEndIdle(void)
1588 {
1589 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1590   _LOG_E_PROC_BUSY();   /* projector */
1591 #endif
1592
1593   CpvAccess(cmiMyPeIdle) = 0;
1594
1595   CcdRaiseCondition(CcdPROCESSOR_BEGIN_BUSY) ;
1596 }
1597
1598 extern int _exitHandlerIdx;
1599
1600 /** Takes a message and calls its corresponding handler. */
1601 void CmiHandleMessage(void *msg)
1602 {
1603 /* this is wrong because it counts the Charm++ messages in sched queue
1604         CpvAccess(cQdState)->mProcessed++;
1605 */
1606         CmiHandlerInfo *h;
1607 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1608         CmiUInt2 handler=CmiGetHandler(msg); /* Save handler for use after msg is gone */
1609         _LOG_E_HANDLER_BEGIN(handler); /* projector */
1610         /* setMemoryStatus(1) */ /* charmdebug */
1611 #endif
1612
1613 /*
1614         FAULT_EVAC
1615 */
1616 /*      if((!CpvAccess(_validProcessors)[CmiMyPe()]) && handler != _exitHandlerIdx){
1617                 return;
1618         }*/
1619         
1620         MESSAGE_PHASE_CHECK(msg)
1621
1622         h=&CmiGetHandlerInfo(msg);
1623         (h->hdlr)(msg,h->userPtr);
1624 #if CMK_TRACE_ENABLED
1625         /* setMemoryStatus(0) */ /* charmdebug */
1626         //_LOG_E_HANDLER_END(handler);  /* projector */
1627 #endif
1628 }
1629
1630 #if CMK_CMIDELIVERS_USE_COMMON_CODE
1631
1632 void CmiDeliversInit()
1633 {
1634 }
1635
1636 int CmiDeliverMsgs(int maxmsgs)
1637 {
1638   return CsdScheduler(maxmsgs);
1639 }
1640
1641 #if CMK_OBJECT_QUEUE_AVAILABLE
1642 CpvDeclare(void *, CsdObjQueue);
1643 #endif
1644
1645 void CsdSchedulerState_new(CsdSchedulerState_t *s)
1646 {
1647 #if CMK_OBJECT_QUEUE_AVAILABLE
1648         s->objQ=CpvAccess(CsdObjQueue);
1649 #endif
1650         s->localQ=CpvAccess(CmiLocalQueue);
1651         s->schedQ=CpvAccess(CsdSchedQueue);
1652         s->localCounter=&(CpvAccess(CsdLocalCounter));
1653 #if CMK_NODE_QUEUE_AVAILABLE
1654         s->nodeQ=CsvAccess(CsdNodeQueue);
1655         s->nodeLock=CsvAccess(CsdNodeQueueLock);
1656 #endif
1657 #if CMK_GRID_QUEUE_AVAILABLE
1658         s->gridQ=CpvAccess(CsdGridQueue);
1659 #endif
1660 }
1661
1662
1663 /** Dequeue and return the next message from the unprocessed message queues.
1664  *
1665  * This function encapsulates the multiple queues that exist for holding unprocessed
1666  * messages and the rules for the order in which to check them. There are five (5)
1667  * different Qs that converse uses to store and retrieve unprocessed messages. These
1668  * are:
1669  *     Q Purpose                  Type      internal DeQ logic
1670  * -----------------------------------------------------------
1671  * - PE offnode                   pcQ             FIFO
1672  * - PE onnode                    CkQ             FIFO
1673  * - Node offnode                 pcQ             FIFO
1674  * - Node onnode                  prioQ           prio-based
1675  * - Scheduler                    prioQ           prio-based
1676  *
1677  * The PE queues hold messages that are destined for a specific PE. There is one such
1678  * queue for every PE within a charm node. The node queues hold messages that are
1679  * destined to that node. There is only one of each node queue within a charm node.
1680  * Finally there is also a charm++ message queue for each PE.
1681  *
1682  * The offnode queues are meant for holding messages that arrive from outside the
1683  * node. The onnode queues hold messages that are generated within the same charm
1684  * node.
1685  *
1686  * The PE and node level offnode queues are accessed via functions CmiGetNonLocal()
1687  * and CmiGetNonLocalNodeQ(). These are implemented separately by each machine layer
1688  * and hide the implementation specifics for each layer.
1689  *
1690  * The PE onnode queue is implemented as a FIFO CkQ and is initialized via a call to
1691  * CdsFifo_Create(). The node local queue and the scheduler queue are both priority
1692  * queues. They are initialized via calls to CqsCreate() which gives each of them
1693  * three separate internal queues for different priority ranges (-ve, 0 and +ve).
1694  * Access to these queues is via pointers stored in the struct CsdSchedulerState that
1695  * is passed into this function.
1696  *
1697  * The order in which these queues are checked is described below. The function
1698  * proceeds to the next queue in the list only if it does not find any messages in
1699  * the current queue. The first message that is found is returned, terminating the
1700  * call.
1701  * (1) offnode queue for this PE
1702  * (2) onnode queue for this PE
1703  * (3) offnode queue for this node
1704  * (4) highest priority msg from onnode queue or scheduler queue
1705  *
1706  * @note: Across most (all?) machine layers, the two GetNonLocal functions simply
1707  * access (after observing adequate locking rigor) structs representing the scheduler
1708  * state, to dequeue from the queues stored within them. The structs (CmiStateStruct
1709  * and CmiNodeStateStruct) implement these queues as \ref Machine "pc (producer-consumer)
1710  * queues". The functions also perform other necessary actions like PumpMsgs() etc.
1711  *
1712  */
1713 void *CsdNextMessage(CsdSchedulerState_t *s) {
1714         void *msg;
1715         if((*(s->localCounter))-- >0)
1716           {
1717               /* This avoids a race condition with migration detected by megatest*/
1718               msg=CdsFifo_Dequeue(s->localQ);
1719               if (msg!=NULL)
1720                 {
1721                   CpvAccess(cQdState)->mProcessed++;
1722                   return msg;       
1723                 }
1724               CqsDequeue(s->schedQ,(void **)&msg);
1725               if (msg!=NULL) return msg;
1726           }
1727         
1728         *(s->localCounter)=CsdLocalMax;
1729         if ( NULL!=(msg=CmiGetNonLocal()) || 
1730              NULL!=(msg=CdsFifo_Dequeue(s->localQ)) ) {
1731             CpvAccess(cQdState)->mProcessed++;
1732             return msg;
1733         }
1734 #if CMK_GRID_QUEUE_AVAILABLE
1735         /*#warning "CsdNextMessage: CMK_GRID_QUEUE_AVAILABLE" */
1736         CqsDequeue (s->gridQ, (void **) &msg);
1737         if (msg != NULL) {
1738           return (msg);
1739         }
1740 #endif
1741 #if CMK_NODE_QUEUE_AVAILABLE
1742         /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1743         if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;
1744         if (!CqsEmpty(s->nodeQ)
1745          && !CqsPrioGT(CqsGetPriority(s->nodeQ),
1746                        CqsGetPriority(s->schedQ))) {
1747           CmiLock(s->nodeLock);
1748           CqsDequeue(s->nodeQ,(void **)&msg);
1749           CmiUnlock(s->nodeLock);
1750           if (msg!=NULL) return msg;
1751         }
1752 #endif
1753 #if CMK_OBJECT_QUEUE_AVAILABLE
1754         /*#warning "CsdNextMessage: CMK_OBJECT_QUEUE_AVAILABLE"   */
1755         if (NULL!=(msg=CdsFifo_Dequeue(s->objQ))) {
1756           return msg;
1757         }
1758 #endif
1759         if(!CsdLocalMax) {
1760           CqsDequeue(s->schedQ,(void **)&msg);
1761           if (msg!=NULL) return msg;        
1762         }
1763         return NULL;
1764 }
1765
1766
1767 void *CsdNextLocalNodeMessage(CsdSchedulerState_t *s) {
1768         void *msg;
1769 #if CMK_NODE_QUEUE_AVAILABLE
1770         /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1771         /*if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;*/
1772         if (!CqsEmpty(s->nodeQ))
1773         {
1774           CmiLock(s->nodeLock);
1775           CqsDequeue(s->nodeQ,(void **)&msg);
1776           CmiUnlock(s->nodeLock);
1777           if (msg!=NULL) return msg;
1778         }
1779 #endif
1780         return NULL;
1781
1782 }
1783
1784 int CsdScheduler(int maxmsgs)
1785 {
1786         if (maxmsgs<0) CsdScheduleForever();    
1787         else if (maxmsgs==0)
1788                 CsdSchedulePoll();
1789         else /*(maxmsgs>0)*/ 
1790                 return CsdScheduleCount(maxmsgs);
1791         return 0;
1792 }
1793
1794 /*Declare the standard scheduler housekeeping*/
1795 #define SCHEDULE_TOP \
1796       void *msg;\
1797       int *CsdStopFlag_ptr = &CpvAccess(CsdStopFlag); \
1798       int cycle = CpvAccess(CsdStopFlag); \
1799       CsdSchedulerState_t state;\
1800       CsdSchedulerState_new(&state);
1801
1802 /*A message is available-- process it*/
1803 #define SCHEDULE_MESSAGE \
1804       CmiHandleMessage(msg);\
1805       if (*CsdStopFlag_ptr != cycle) break;
1806
1807 /*No message available-- go (or remain) idle*/
1808 #define SCHEDULE_IDLE \
1809       if (!isIdle) {isIdle=1;CsdBeginIdle();}\
1810       else CsdStillIdle();\
1811       if (*CsdStopFlag_ptr != cycle) {\
1812         CsdEndIdle();\
1813         break;\
1814       }
1815
1816 /*
1817         EVAC
1818 */
1819 extern void CkClearAllArrayElements();
1820
1821
1822 extern void machine_OffloadAPIProgress();
1823
1824 /** The main scheduler loop that repeatedly executes messages from a queue, forever. */
1825 void CsdScheduleForever(void)
1826 {
1827   #if CMK_CELL
1828     #define CMK_CELL_PROGRESS_FREQ  96  /* (MSG-Q Entries x1.5) */
1829     int progressCount = CMK_CELL_PROGRESS_FREQ;
1830   #endif
1831
1832   #ifdef CMK_CUDA
1833     #define CMK_CUDA_PROGRESS_FREQ 50
1834     int cudaProgressCount = CMK_CUDA_PROGRESS_FREQ;
1835   #endif
1836
1837   int isIdle=0;
1838   SCHEDULE_TOP
1839   while (1) {
1840     /* The interoperation will cost this little overhead in scheduling */
1841     if(CharmLibInterOperate) {
1842       if(CpvAccess(charmLibExitFlag)) {
1843         CpvAccess(charmLibExitFlag) = 0;
1844         break;
1845       }
1846     }
1847     msg = CsdNextMessage(&state);
1848     if (msg!=NULL) { /*A message is available-- process it*/
1849       if (isIdle) {isIdle=0;CsdEndIdle();}
1850       SCHEDULE_MESSAGE
1851
1852       #if CMK_CELL
1853         if (progressCount <= 0) {
1854           /*OffloadAPIProgress();*/
1855           machine_OffloadAPIProgress();
1856           progressCount = CMK_CELL_PROGRESS_FREQ;
1857         }
1858         progressCount--;
1859       #endif
1860
1861       #ifdef CMK_CUDA
1862         if (cudaProgressCount == 0) {
1863           gpuProgressFn(); 
1864           cudaProgressCount = CMK_CUDA_PROGRESS_FREQ; 
1865         }
1866         cudaProgressCount--; 
1867       #endif
1868
1869     } else { /*No message available-- go (or remain) idle*/
1870       SCHEDULE_IDLE
1871
1872       #if CMK_CELL
1873         /*OffloadAPIProgress();*/
1874         machine_OffloadAPIProgress();
1875         progressCount = CMK_CELL_PROGRESS_FREQ;
1876       #endif
1877
1878       #ifdef CMK_CUDA
1879         gpuProgressFn(); 
1880         cudaProgressCount = CMK_CUDA_PROGRESS_FREQ;
1881       #endif
1882
1883     }
1884     CsdPeriodic();
1885   }
1886 }
1887 int CsdScheduleCount(int maxmsgs)
1888 {
1889   int isIdle=0;
1890   SCHEDULE_TOP
1891   while (1) {
1892     msg = CsdNextMessage(&state);
1893     if (msg!=NULL) { /*A message is available-- process it*/
1894       if (isIdle) {isIdle=0;CsdEndIdle();}
1895       maxmsgs--; 
1896       SCHEDULE_MESSAGE
1897       if (maxmsgs==0) break;
1898     } else { /*No message available-- go (or remain) idle*/
1899       SCHEDULE_IDLE
1900     }
1901     CsdPeriodic();
1902   }
1903   return maxmsgs;
1904 }
1905
1906 void CsdSchedulePoll(void)
1907 {
1908   SCHEDULE_TOP
1909   while (1)
1910   {
1911         CsdPeriodic();
1912         /*CmiMachineProgressImpl(); ??? */
1913         if (NULL!=(msg = CsdNextMessage(&state)))
1914         {
1915              SCHEDULE_MESSAGE 
1916         }
1917         else break;
1918   }
1919 }
1920
1921 void CsdScheduleNodePoll(void)
1922 {
1923   SCHEDULE_TOP
1924   while (1)
1925   {
1926         /*CsdPeriodic();*/
1927         /*CmiMachineProgressImpl(); ??? */
1928         if (NULL!=(msg = CsdNextLocalNodeMessage(&state)))
1929         {
1930              SCHEDULE_MESSAGE 
1931         }
1932         else break;
1933   }
1934 }
1935
1936 void CmiDeliverSpecificMsg(handler)
1937 int handler;
1938 {
1939   int *msg; int side;
1940   void *localqueue = CpvAccess(CmiLocalQueue);
1941  
1942   side = 0;
1943   while (1) {
1944     CsdPeriodic();
1945     side ^= 1;
1946     if (side) msg = CmiGetNonLocal();
1947     else      msg = CdsFifo_Dequeue(localqueue);
1948     if (msg) {
1949       if (CmiGetHandler(msg)==handler) {
1950         CpvAccess(cQdState)->mProcessed++;
1951         CmiHandleMessage(msg);
1952         return;
1953       } else {
1954         CdsFifo_Enqueue(localqueue, msg);
1955       }
1956     }
1957   }
1958 }
1959  
1960 #endif /* CMK_CMIDELIVERS_USE_COMMON_CODE */
1961
1962 /***************************************************************************
1963  *
1964  * Standin Schedulers.
1965  *
1966  * We use the following strategy to make sure somebody's always running
1967  * the scheduler (CsdScheduler).  Initially, we assume the main thread
1968  * is responsible for this.  If the main thread blocks, we create a
1969  * "standin scheduler" thread to replace it.  If the standin scheduler
1970  * blocks, we create another standin scheduler to replace that one,
1971  * ad infinitum.  Collectively, the main thread and all the standin
1972  * schedulers are called "scheduling threads".
1973  *
1974  * Suppose the main thread is blocked waiting for data, and a standin
1975  * scheduler is running instead.  Suppose, then, that the data shows
1976  * up and the main thread is CthAwakened.  This causes a token to be
1977  * pushed into the queue.  When the standin pulls the token from the
1978  * queue and handles it, the standin goes to sleep, and control shifts
1979  * back to the main thread.  In this way, unnecessary standins are put
1980  * back to sleep.  These sleeping standins are stored on the
1981  * CthSleepingStandins list.
1982  *
1983  ***************************************************************************/
1984
1985 CpvStaticDeclare(CthThread, CthMainThread);
1986 CpvStaticDeclare(CthThread, CthSchedulingThread);
1987 CpvStaticDeclare(CthThread, CthSleepingStandins);
1988 CpvDeclare(int      , CthResumeNormalThreadIdx);
1989 CpvStaticDeclare(int      , CthResumeSchedulingThreadIdx);
1990
1991
1992 void CthStandinCode()
1993 {
1994   while (1) CsdScheduler(0);
1995 }
1996
1997 /* this fix the function pointer for thread migration and pup */
1998 static CthThread CthSuspendNormalThread()
1999 {
2000   return CpvAccess(CthSchedulingThread);
2001 }
2002
2003 void CthEnqueueSchedulingThread(CthThreadToken *token, int, int, unsigned int*);
2004 CthThread CthSuspendSchedulingThread();
2005
2006 CthThread CthSuspendSchedulingThread()
2007 {
2008   CthThread succ = CpvAccess(CthSleepingStandins);
2009
2010   if (succ) {
2011     CpvAccess(CthSleepingStandins) = CthGetNext(succ);
2012   } else {
2013     succ = CthCreate(CthStandinCode, 0, 256000);
2014     CthSetStrategy(succ,
2015                    CthEnqueueSchedulingThread,
2016                    CthSuspendSchedulingThread);
2017   }
2018   
2019   CpvAccess(CthSchedulingThread) = succ;
2020   return succ;
2021 }
2022
2023 /* Notice: For changes to the following function, make sure the function CthResumeNormalThreadDebug is also kept updated. */
2024 void CthResumeNormalThread(CthThreadToken* token)
2025 {
2026   CthThread t = token->thread;
2027
2028   /* BIGSIM_OOC DEBUGGING
2029   CmiPrintf("Resume normal thread with token[%p] ==> thread[%p]\n", token, t);
2030   */
2031
2032   if(t == NULL){
2033     free(token);
2034     return;
2035   }
2036 #if CMK_TRACE_ENABLED
2037 #if ! CMK_TRACE_IN_CHARM
2038   if(CpvAccess(traceOn))
2039     CthTraceResume(t);
2040 /*    if(CpvAccess(_traceCoreOn)) 
2041                 resumeTraceCore();*/
2042 #endif
2043 #endif
2044   
2045   /* BIGSIM_OOC DEBUGGING
2046   CmiPrintf("In CthResumeNormalThread:   ");
2047   CthPrintThdMagic(t);
2048   */
2049
2050 //  if(CmiMyPartition()==0&& CmiMyPe()==1)
2051 //    CmiPrintf("[%d][%d]In CthResumeNormalThread:\n",CmiMyPartition(),CmiMyPe());
2052   fflush(stdout);
2053   CthResume(t);
2054 //  if(CmiMyPartition()==0&& CmiMyPe()==1)
2055 //    CmiPrintf("[%d][%d]In CthResumeNormalThread end:\n",CmiMyPartition(),CmiMyPe());
2056   fflush(stdout);
2057 }
2058
2059 void CthResumeSchedulingThread(CthThreadToken  *token)
2060 {
2061   CthThread t = token->thread;
2062   CthThread me = CthSelf();
2063   if (me == CpvAccess(CthMainThread)) {
2064     CthEnqueueSchedulingThread(CthGetToken(me),CQS_QUEUEING_FIFO, 0, 0);
2065   } else {
2066     CthSetNext(me, CpvAccess(CthSleepingStandins));
2067     CpvAccess(CthSleepingStandins) = me;
2068   }
2069   CpvAccess(CthSchedulingThread) = t;
2070 #if CMK_TRACE_ENABLED
2071 #if ! CMK_TRACE_IN_CHARM
2072   if(CpvAccess(traceOn))
2073     CthTraceResume(t);
2074 /*    if(CpvAccess(_traceCoreOn)) 
2075                 resumeTraceCore();*/
2076 #endif
2077 #endif
2078   CthResume(t);
2079 }
2080
2081 void CthEnqueueNormalThread(CthThreadToken* token, int s, 
2082                                    int pb,unsigned int *prio)
2083 {
2084   CmiSetHandler(token, CpvAccess(CthResumeNormalThreadIdx));
2085   CsdEnqueueGeneral(token, s, pb, prio);
2086 }
2087
2088 void CthEnqueueSchedulingThread(CthThreadToken* token, int s, 
2089                                        int pb,unsigned int *prio)
2090 {
2091   CmiSetHandler(token, CpvAccess(CthResumeSchedulingThreadIdx));
2092   CsdEnqueueGeneral(token, s, pb, prio);
2093 }
2094
2095 void CthSetStrategyDefault(CthThread t)
2096 {
2097   CthSetStrategy(t,
2098                  CthEnqueueNormalThread,
2099                  CthSuspendNormalThread);
2100 }
2101
2102 void CthSchedInit()
2103 {
2104   CpvInitialize(CthThread, CthMainThread);
2105   CpvInitialize(CthThread, CthSchedulingThread);
2106   CpvInitialize(CthThread, CthSleepingStandins);
2107   CpvInitialize(int      , CthResumeNormalThreadIdx);
2108   CpvInitialize(int      , CthResumeSchedulingThreadIdx);
2109
2110   CpvAccess(CthMainThread) = CthSelf();
2111   CpvAccess(CthSchedulingThread) = CthSelf();
2112   CpvAccess(CthSleepingStandins) = 0;
2113   CpvAccess(CthResumeNormalThreadIdx) =
2114     CmiRegisterHandler((CmiHandler)CthResumeNormalThread);
2115   CpvAccess(CthResumeSchedulingThreadIdx) =
2116     CmiRegisterHandler((CmiHandler)CthResumeSchedulingThread);
2117   CthSetStrategy(CthSelf(),
2118                  CthEnqueueSchedulingThread,
2119                  CthSuspendSchedulingThread);
2120 }
2121
2122 void CsdInit(argv)
2123   char **argv;
2124 {
2125   CpvInitialize(void *, CsdSchedQueue);
2126   CpvInitialize(int,   CsdStopFlag);
2127   CpvInitialize(int,   CsdLocalCounter);
2128   if(!CmiGetArgIntDesc(argv,"+csdLocalMax",&CsdLocalMax,"Set the max number of local messages to process before forcing a check for remote messages."))
2129     {
2130       CsdLocalMax= CSD_LOCAL_MAX_DEFAULT;
2131     }
2132   CpvAccess(CsdLocalCounter) = CsdLocalMax;
2133   CpvAccess(CsdSchedQueue) = (void *)CqsCreate();
2134    #if CMK_USE_STL_MSGQ
2135    if (CmiMyPe() == 0) CmiPrintf("Charm++> Using STL-based msgQ:\n");
2136    #endif
2137
2138 #if CMK_OBJECT_QUEUE_AVAILABLE
2139   CpvInitialize(void *,CsdObjQueue);
2140   CpvAccess(CsdObjQueue) = CdsFifo_Create();
2141 #endif
2142
2143 #if CMK_NODE_QUEUE_AVAILABLE
2144   CsvInitialize(CmiLock, CsdNodeQueueLock);
2145   CsvInitialize(void *, CsdNodeQueue);
2146   if (CmiMyRank() ==0) {
2147         CsvAccess(CsdNodeQueueLock) = CmiCreateLock();
2148         CsvAccess(CsdNodeQueue) = (void *)CqsCreate();
2149   }
2150   CmiNodeAllBarrier();
2151 #endif
2152
2153 #if CMK_GRID_QUEUE_AVAILABLE
2154   CsvInitialize(void *, CsdGridQueue);
2155   CpvAccess(CsdGridQueue) = (void *)CqsCreate();
2156 #endif
2157
2158   CpvAccess(CsdStopFlag)  = 0;
2159 }
2160
2161
2162
2163 /** 
2164  *  @}
2165  */
2166
2167
2168 /*****************************************************************************
2169  *
2170  * Vector Send
2171  *
2172  * The last parameter "system" is by default at zero, in which case the normal
2173  * messages are sent. If it is set to 1, the CmiChunkHeader prepended to every
2174  * CmiAllocced message will also be sent (except for the first one). Useful for
2175  * AllToAll communication, and other system features. If system is 1, also all
2176  * the messages will be padded to 8 bytes. Thus, the caller must be aware of
2177  * that.
2178  *
2179  ****************************************************************************/
2180
2181 #if CMK_VECTOR_SEND_USES_COMMON_CODE
2182
2183 void CmiSyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2184   int total;
2185   char *mesg;
2186 #if CMK_USE_IBVERBS
2187   VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(infiCmiChunkHeader));
2188 #else
2189   VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(CmiChunkHeader));
2190 #endif  
2191   CmiSyncSendAndFree(destPE, total, mesg);
2192 }
2193
2194 CmiCommHandle CmiASyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2195   CmiSyncVectorSend(destPE, n, sizes, msgs);
2196   return NULL;
2197 }
2198
2199 void CmiSyncVectorSendAndFree(int destPE, int n, int *sizes, char **msgs) {
2200   int i;
2201   CmiSyncVectorSend(destPE, n, sizes, msgs);
2202   for(i=0;i<n;i++) CmiFree(msgs[i]);
2203   CmiFree(sizes);
2204   CmiFree(msgs);
2205 }
2206
2207 #endif
2208
2209 /*****************************************************************************
2210  *
2211  * Reduction management
2212  *
2213  * Only one reduction can be active at a single time in the program.
2214  * Moreover, since every call is supposed to pass in the same arguments,
2215  * having some static variables is not a problem for multithreading.
2216  * 
2217  * Except for "data" and "size", all the other parameters (which are all function
2218  * pointers) MUST be the same in every processor. Having different processors
2219  * pass in different function pointers results in an undefined behaviour.
2220  * 
2221  * The data passed in to CmiReduce and CmiNodeReduce is deleted by the system,
2222  * and MUST be allocated with CmiAlloc. The data passed in to the "Struct"
2223  * functions is deleted with the provided function, or it is left intact if no
2224  * function is specified.
2225  * 
2226  * The destination handler for the the first form MUST be embedded into the
2227  * message's header.
2228  * 
2229  * The pup function is used to pup the input data structure into a message to
2230  * be sent to the parent processor. This pup routine is currently used only
2231  * for sizing and packing, NOT unpacking. It MUST be non-null.
2232  * 
2233  * The merge function receives as first parameter the input "data", being it
2234  * a message or a complex data structure (it is up to the user to interpret it
2235  * correctly), and a list of incoming (packed) messages from the children.
2236  * The merge function is responsible to delete "data" if this is no longer needed.
2237  * The system will be in charge of deleting the messages passed in as the second
2238  * argument, and the return value of the function (using the provided deleteFn in
2239  * the second version, or CmiFree in the first). The merge function can return
2240  * data if the merge can be performed in-place. It MUST be non-null.
2241  * 
2242  * At the destination, on processor zero, the final data returned by the last
2243  * merge call will not be deleted by the system, and the CmiHandler function
2244  * will be in charge of its deletion.
2245  * 
2246  * CmiReduce/CmiReduceStruct MUST be called once by every processor,
2247  * CmiNodeReduce/CmiNodeReduceStruct MUST be called once by every node, and in
2248  * particular by the rank zero in each node.
2249  ****************************************************************************/
2250
2251 CpvStaticDeclare(int, CmiReductionMessageHandler);
2252 CpvStaticDeclare(int, CmiReductionDynamicRequestHandler);
2253
2254 CpvStaticDeclare(CmiReduction**, _reduce_info);
2255 CpvStaticDeclare(int, _reduce_info_size); /* This is the log2 of the size of the array */
2256 CpvStaticDeclare(CmiUInt2, _reduce_seqID_global); /* This is used only by global reductions */
2257 CpvStaticDeclare(CmiUInt2, _reduce_seqID_request);
2258 CpvStaticDeclare(CmiUInt2, _reduce_seqID_dynamic);
2259
2260 enum {
2261   CmiReductionID_globalOffset = 0, /* Reductions that involve the whole set of processors */
2262   CmiReductionID_requestOffset = 1, /* Reductions IDs that are requested by all the processors (i.e during intialization) */
2263   CmiReductionID_dynamicOffset = 2, /* Reductions IDs that are requested by only one processor (typically at runtime) */
2264   CmiReductionID_multiplier = 3
2265 };
2266
2267 CmiReduction* CmiGetReductionCreate(int id, short int numChildren) {
2268   int index = id & ~((~0)<<CpvAccess(_reduce_info_size));
2269   CmiReduction *red = CpvAccess(_reduce_info)[index];
2270   if (red != NULL && red->seqID != id) {
2271     /* The table needs to be expanded */
2272     CmiAbort("Too many simultaneous reductions");
2273   }
2274   if (red == NULL || red->numChildren < numChildren) {
2275     CmiReduction *newred;
2276     if (red != NULL) CmiPrintf("[%d] Reduction structure reallocated\n",CmiMyPe());
2277     CmiAssert(red == NULL || red->localContributed == 0);
2278     if (numChildren == 0) numChildren = 4;
2279     newred = (CmiReduction*)malloc(sizeof(CmiReduction)+numChildren*sizeof(void*));
2280     newred->numRemoteReceived = 0;
2281     newred->localContributed = 0;
2282     newred->seqID = id;
2283     if (red != NULL) {
2284       memcpy(newred, red, sizeof(CmiReduction)+red->numChildren*sizeof(void*));
2285       free(red);
2286     }
2287     red = newred;
2288     red->numChildren = numChildren;
2289     red->remoteData = (char**)(red+1);
2290     CpvAccess(_reduce_info)[index] = red;
2291   }
2292   return red;
2293 }
2294
2295 CmiReduction* CmiGetReduction(int id) {
2296   return CmiGetReductionCreate(id, 0);
2297 }
2298
2299 void CmiClearReduction(int id) {
2300   int index = id & ~((~0)<<CpvAccess(_reduce_info_size));
2301   free(CpvAccess(_reduce_info)[index]);
2302   CpvAccess(_reduce_info)[index] = NULL;
2303 }
2304
2305 CmiReduction* CmiGetNextReduction(short int numChildren) {
2306   int id = CpvAccess(_reduce_seqID_global);
2307   CpvAccess(_reduce_seqID_global) += CmiReductionID_multiplier;
2308   if (id > 0xFFF0) CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2309   return CmiGetReductionCreate(id, numChildren);
2310 }
2311
2312 CmiReductionID CmiGetGlobalReduction() {
2313   return CpvAccess(_reduce_seqID_request)+=CmiReductionID_multiplier;
2314 }
2315
2316 CmiReductionID CmiGetDynamicReduction() {
2317   if (CmiMyPe() != 0) CmiAbort("Cannot call CmiGetDynamicReduction on processors other than zero!\n");
2318   return CpvAccess(_reduce_seqID_dynamic)+=CmiReductionID_multiplier;
2319 }
2320
2321 void CmiReductionHandleDynamicRequest(char *msg) {
2322   int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2323   int pe = values[0];
2324   int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+values[1];
2325   values[0] = CmiGetDynamicReduction();
2326   CmiSetHandler(msg, CmiGetXHandler(msg));
2327   if (pe >= 0) {
2328     CmiSyncSendAndFree(pe, size, msg);
2329   } else {
2330     CmiSyncBroadcastAllAndFree(size, msg);
2331   }
2332 }
2333
2334 void CmiGetDynamicReductionRemote(int handlerIdx, int pe, int dataSize, void *data) {
2335   int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+dataSize;
2336   char *msg = (char*)CmiAlloc(size);
2337   int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2338   values[0] = pe;
2339   values[1] = dataSize;
2340   CmiSetXHandler(msg, handlerIdx);
2341   if (dataSize) memcpy(msg+CmiMsgHeaderSizeBytes+2*sizeof(int), data, dataSize);
2342   if (CmiMyPe() == 0) {
2343     CmiReductionHandleDynamicRequest(msg);
2344   } else {
2345     /* send the request to processor 0 */
2346     CmiSetHandler(msg, CpvAccess(CmiReductionDynamicRequestHandler));
2347     CmiSyncSendAndFree(0, size, msg);
2348   }
2349 }
2350
2351 void CmiSendReduce(CmiReduction *red) {
2352   void *mergedData, *msg;
2353   int msg_size;
2354   if (!red->localContributed || red->numChildren != red->numRemoteReceived) return;
2355   mergedData = red->localData;
2356   msg_size = red->localSize;
2357   if (red->numChildren > 0) {
2358     int i, offset=0;
2359     if (red->ops.pupFn != NULL) {
2360       offset = CmiReservedHeaderSize;
2361       for (i=0; i<red->numChildren; ++i) red->remoteData[i] += offset;
2362     }
2363     mergedData = (red->ops.mergeFn)(&msg_size, red->localData, (void **)red->remoteData, red->numChildren);
2364     for (i=0; i<red->numChildren; ++i) CmiFree(red->remoteData[i] - offset);
2365   }
2366   /*CpvAccess(_reduce_num_children) = 0;*/
2367   /*CpvAccess(_reduce_received) = 0;*/
2368   msg = mergedData;
2369   if (red->parent != -1) {
2370     if (red->ops.pupFn != NULL) {
2371       pup_er p = pup_new_sizer();
2372       (red->ops.pupFn)(p, mergedData);
2373       msg_size = pup_size(p) + CmiReservedHeaderSize;
2374       pup_destroy(p);
2375       msg = CmiAlloc(msg_size);
2376       p = pup_new_toMem((void*)(((char*)msg)+CmiReservedHeaderSize));
2377       (red->ops.pupFn)(p, mergedData);
2378       pup_destroy(p);
2379       if (red->ops.deleteFn != NULL) (red->ops.deleteFn)(red->localData);
2380     }
2381     CmiSetHandler(msg, CpvAccess(CmiReductionMessageHandler));
2382     CmiSetRedID(msg, red->seqID);
2383     /*CmiPrintf("CmiSendReduce(%d): sending %d bytes to %d\n",CmiMyPe(),msg_size,red->parent);*/
2384     CmiSyncSendAndFree(red->parent, msg_size, msg);
2385   } else {
2386     (red->ops.destination)(msg);
2387   }
2388   CmiClearReduction(red->seqID);
2389 }
2390
2391 void *CmiReduceMergeFn_random(int *size, void *data, void** remote, int n) {
2392   return data;
2393 }
2394
2395 static void CmiGlobalReduce(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReduction *red) {
2396   CmiAssert(red->localContributed == 0);
2397   red->localContributed = 1;
2398   red->localData = msg;
2399   red->localSize = size;
2400   red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2401   red->parent = CmiSpanTreeParent(CmiMyPe());
2402   red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2403   red->ops.mergeFn = mergeFn;
2404   red->ops.pupFn = NULL;
2405   /*CmiPrintf("[%d] CmiReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2406   CmiSendReduce(red);
2407 }
2408
2409 static void CmiGlobalReduceStruct(void *data, CmiReducePupFn pupFn,
2410                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2411                      CmiReduceDeleteFn deleteFn, CmiReduction *red) {
2412   CmiAssert(red->localContributed == 0);
2413   red->localContributed = 1;
2414   red->localData = data;
2415   red->localSize = 0;
2416   red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2417   red->parent = CmiSpanTreeParent(CmiMyPe());
2418   red->ops.destination = dest;
2419   red->ops.mergeFn = mergeFn;
2420   red->ops.pupFn = pupFn;
2421   red->ops.deleteFn = deleteFn;
2422   /*CmiPrintf("[%d] CmiReduceStruct::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2423   CmiSendReduce(red);
2424 }
2425
2426 void CmiReduce(void *msg, int size, CmiReduceMergeFn mergeFn) {
2427   CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2428   CmiGlobalReduce(msg, size, mergeFn, red);
2429 }
2430
2431 void CmiReduceStruct(void *data, CmiReducePupFn pupFn,
2432                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2433                      CmiReduceDeleteFn deleteFn) {
2434   CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2435   CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2436 }
2437
2438 void CmiReduceID(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2439   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2440   CmiGlobalReduce(msg, size, mergeFn, red);
2441 }
2442
2443 void CmiReduceStructID(void *data, CmiReducePupFn pupFn,
2444                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2445                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2446   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2447   CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2448 }
2449
2450 void CmiListReduce(int npes, int *pes, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2451   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2452   int myPos;
2453   CmiAssert(red->localContributed == 0);
2454   red->localContributed = 1;
2455   red->localData = msg;
2456   red->localSize = size;
2457   for (myPos=0; myPos<npes; ++myPos) {
2458     if (pes[myPos] == CmiMyPe()) break;
2459   }
2460   CmiAssert(myPos < npes);
2461   red->numChildren = npes - (myPos << 2) - 1;
2462   if (red->numChildren > 4) red->numChildren = 4;
2463   if (red->numChildren < 0) red->numChildren = 0;
2464   if (myPos == 0) red->parent = -1;
2465   else red->parent = pes[(myPos - 1) >> 2];
2466   red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2467   red->ops.mergeFn = mergeFn;
2468   red->ops.pupFn = NULL;
2469   /*CmiPrintf("[%d] CmiListReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2470   CmiSendReduce(red);
2471 }
2472
2473 void CmiListReduceStruct(int npes, int *pes,
2474                      void *data, CmiReducePupFn pupFn,
2475                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2476                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2477   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2478   int myPos;
2479   CmiAssert(red->localContributed == 0);
2480   red->localContributed = 1;
2481   red->localData = data;
2482   red->localSize = 0;
2483   for (myPos=0; myPos<npes; ++myPos) {
2484     if (pes[myPos] == CmiMyPe()) break;
2485   }
2486   CmiAssert(myPos < npes);
2487   red->numChildren = npes - (myPos << 2) - 1;
2488   if (red->numChildren > 4) red->numChildren = 4;
2489   if (red->numChildren < 0) red->numChildren = 0;
2490   red->parent = (myPos - 1) >> 2;
2491   if (myPos == 0) red->parent = -1;
2492   red->ops.destination = dest;
2493   red->ops.mergeFn = mergeFn;
2494   red->ops.pupFn = pupFn;
2495   red->ops.deleteFn = deleteFn;
2496   CmiSendReduce(red);
2497 }
2498
2499 void CmiGroupReduce(CmiGroup grp, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2500   int npes, *pes;
2501   CmiLookupGroup(grp, &npes, &pes);
2502   CmiListReduce(npes, pes, msg, size, mergeFn, id);
2503 }
2504
2505 void CmiGroupReduceStruct(CmiGroup grp, void *data, CmiReducePupFn pupFn,
2506                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2507                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2508   int npes, *pes;
2509   CmiLookupGroup(grp, &npes, &pes);
2510   CmiListReduceStruct(npes, pes, data, pupFn, mergeFn, dest, deleteFn, id);
2511 }
2512
2513 void CmiNodeReduce(void *data, int size, CmiReduceMergeFn mergeFn, int redID, int numChildren, int parent) {
2514   CmiAbort("Feel free to implement CmiNodeReduce...");
2515   /*
2516   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2517   CpvAccess(_reduce_data) = data;
2518   CpvAccess(_reduce_data_size) = size;
2519   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2520   _reduce_destination = (CmiHandler)CmiGetHandlerFunction(data);
2521   _reduce_pupFn = NULL;
2522   _reduce_mergeFn = mergeFn;
2523   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2524   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(size);
2525   */
2526 }
2527 #if 0
2528 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int redID) {
2529   CmiNodeReduce(data, size, mergeFn, redID, CmiNumNodeSpanTreeChildren(CmiMyNode()),
2530       CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2531 }
2532 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int numChildren, int parent) {
2533   CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), numChildren, parent);
2534 }
2535 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int)) {
2536   CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), CmiNumNodeSpanTreeChildren(CmiMyNode()),
2537       CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2538 }
2539 #endif
2540
2541 void CmiNodeReduceStruct(void *data, CmiReducePupFn pupFn,
2542                          CmiReduceMergeFn mergeFn, CmiHandler dest,
2543                          CmiReduceDeleteFn deleteFn) {
2544   CmiAbort("Feel free to implement CmiNodeReduceStruct...");
2545 /*
2546   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2547   CpvAccess(_reduce_data) = data;
2548   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2549   _reduce_destination = dest;
2550   _reduce_pupFn = pupFn;
2551   _reduce_mergeFn = mergeFn;
2552   _reduce_deleteFn = deleteFn;
2553   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2554   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(0);
2555   */
2556 }
2557
2558 void CmiHandleReductionMessage(void *msg) {
2559   CmiReduction *red = CmiGetReduction(CmiGetRedID(msg));
2560   if (red->numRemoteReceived == red->numChildren) red = CmiGetReductionCreate(CmiGetRedID(msg), red->numChildren+4);
2561   red->remoteData[red->numRemoteReceived++] = msg;
2562   /*CmiPrintf("[%d] CmiReduce::remote %hd\n",CmiMyPe(),red->seqID);*/
2563   CmiSendReduce(red);
2564 /*
2565   CpvAccess(_reduce_msg_list)[CpvAccess(_reduce_received)++] = msg;
2566   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce();
2567   / *else CmiPrintf("CmiHandleReductionMessage(%d): %d - %d\n",CmiMyPe(),CpvAccess(_reduce_received),CpvAccess(_reduce_num_children));*/
2568 }
2569
2570 void CmiReductionsInit() {
2571   int i;
2572   CpvInitialize(int, CmiReductionMessageHandler);
2573   CpvAccess(CmiReductionMessageHandler) = CmiRegisterHandler((CmiHandler)CmiHandleReductionMessage);
2574   CpvInitialize(int, CmiReductionDynamicRequestHandler);
2575   CpvAccess(CmiReductionDynamicRequestHandler) = CmiRegisterHandler((CmiHandler)CmiReductionHandleDynamicRequest);
2576   CpvInitialize(CmiUInt2, _reduce_seqID_global);
2577   CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2578   CpvInitialize(CmiUInt2, _reduce_seqID_request);
2579   CpvAccess(_reduce_seqID_request) = CmiReductionID_requestOffset;
2580   CpvInitialize(CmiUInt2, _reduce_seqID_dynamic);
2581   CpvAccess(_reduce_seqID_dynamic) = CmiReductionID_dynamicOffset;
2582   CpvInitialize(int, _reduce_info_size);
2583   CpvAccess(_reduce_info_size) = 4;
2584   CpvInitialize(CmiReduction**, _reduce_info);
2585   CpvAccess(_reduce_info) = malloc(16*sizeof(CmiReduction*));
2586   for (i=0; i<16; ++i) CpvAccess(_reduce_info)[i] = NULL;
2587 }
2588
2589 /*****************************************************************************
2590  *
2591  * Multicast groups
2592  *
2593  ****************************************************************************/
2594
2595 #if CMK_MULTICAST_DEF_USE_COMMON_CODE
2596
2597 typedef struct GroupDef
2598 {
2599   union {
2600     char core[CmiMsgHeaderSizeBytes];
2601     struct GroupDef *next;
2602   } core;
2603   CmiGroup group;
2604   int npes;
2605   int pes[1];
2606 }
2607 *GroupDef;
2608
2609 #define GROUPTAB_SIZE 101
2610
2611 CpvStaticDeclare(int, CmiGroupHandlerIndex);
2612 CpvStaticDeclare(int, CmiGroupCounter);
2613 CpvStaticDeclare(GroupDef *, CmiGroupTable);
2614
2615 void CmiGroupHandler(GroupDef def)
2616 {
2617   /* receive group definition, insert into group table */
2618   GroupDef *table = CpvAccess(CmiGroupTable);
2619   unsigned int hashval, bucket;
2620   hashval = (def->group.id ^ def->group.pe);
2621   bucket = hashval % GROUPTAB_SIZE;
2622   def->core.next = table[bucket];
2623   table[bucket] = def;
2624 }
2625
2626 CmiGroup CmiEstablishGroup(int npes, int *pes)
2627 {
2628   /* build new group definition, broadcast it */
2629   CmiGroup grp; GroupDef def; int len, i;
2630   grp.id = CpvAccess(CmiGroupCounter)++;
2631   grp.pe = CmiMyPe();
2632   len = sizeof(struct GroupDef)+(npes*sizeof(int));
2633   def = (GroupDef)CmiAlloc(len);
2634   def->group = grp;
2635   def->npes = npes;
2636   for (i=0; i<npes; i++)
2637     def->pes[i] = pes[i];
2638   CmiSetHandler(def, CpvAccess(CmiGroupHandlerIndex));
2639   CmiSyncBroadcastAllAndFree(len, def);
2640   return grp;
2641 }
2642
2643 void CmiLookupGroup(CmiGroup grp, int *npes, int **pes)
2644 {
2645   unsigned int hashval, bucket;  GroupDef def;
2646   GroupDef *table = CpvAccess(CmiGroupTable);
2647   hashval = (grp.id ^ grp.pe);
2648   bucket = hashval % GROUPTAB_SIZE;
2649   for (def=table[bucket]; def; def=def->core.next) {
2650     if ((def->group.id == grp.id)&&(def->group.pe == grp.pe)) {
2651       *npes = def->npes;
2652       *pes = def->pes;
2653       return;
2654     }
2655   }
2656   *npes = 0; *pes = 0;
2657 }
2658
2659 void CmiGroupInit()
2660 {
2661   CpvInitialize(int, CmiGroupHandlerIndex);
2662   CpvInitialize(int, CmiGroupCounter);
2663   CpvInitialize(GroupDef *, CmiGroupTable);
2664   CpvAccess(CmiGroupHandlerIndex) = CmiRegisterHandler((CmiHandler)CmiGroupHandler);
2665   CpvAccess(CmiGroupCounter) = 0;
2666   CpvAccess(CmiGroupTable) =
2667     (GroupDef*)calloc(GROUPTAB_SIZE, sizeof(GroupDef));
2668   if (CpvAccess(CmiGroupTable) == 0)
2669     CmiAbort("Memory Allocation Error");
2670 }
2671
2672 #endif
2673
2674 /*****************************************************************************
2675  *
2676  * Common List-Cast and Multicast Code
2677  *
2678  ****************************************************************************/
2679
2680 #if CMK_MULTICAST_LIST_USE_COMMON_CODE
2681
2682 void CmiSyncListSendFn(int npes, int *pes, int len, char *msg)
2683 {
2684   int i;
2685 #if CMK_BROADCAST_USE_CMIREFERENCE
2686   for(i=0;i<npes;i++) {
2687     if (pes[i] == CmiMyPe())
2688       CmiSyncSend(pes[i], len, msg);
2689     else {
2690       CmiReference(msg);
2691       CmiSyncSendAndFree(pes[i], len, msg);
2692     }
2693   }
2694 #else
2695   for(i=0;i<npes;i++) {
2696     CmiSyncSend(pes[i], len, msg);
2697   }
2698 #endif
2699 }
2700
2701 CmiCommHandle CmiAsyncListSendFn(int npes, int *pes, int len, char *msg)
2702 {
2703   /* A better asynchronous implementation may be wanted, but at least it works */
2704   CmiSyncListSendFn(npes, pes, len, msg);
2705   return (CmiCommHandle) 0;
2706 }
2707
2708 void CmiFreeListSendFn(int npes, int *pes, int len, char *msg)
2709 {
2710 #if CMK_BROADCAST_USE_CMIREFERENCE
2711   if (npes == 1) {
2712     CmiSyncSendAndFree(pes[0], len, msg);
2713     return;
2714   }
2715   CmiSyncListSendFn(npes, pes, len, msg);
2716   CmiFree(msg);
2717 #else
2718   int i;
2719   for(i=0;i<npes-1;i++) {
2720     CmiSyncSend(pes[i], len, msg);
2721   }
2722   if (npes>0)
2723     CmiSyncSendAndFree(pes[npes-1], len, msg);
2724   else 
2725     CmiFree(msg);
2726 #endif
2727 }
2728
2729 #endif
2730
2731 #if CMK_MULTICAST_GROUP_USE_COMMON_CODE
2732
2733 typedef struct MultiMsg
2734 {
2735   char core[CmiMsgHeaderSizeBytes];
2736   CmiGroup group;
2737   int pos;
2738   int origlen;
2739 }
2740 *MultiMsg;
2741
2742
2743 CpvDeclare(int, CmiMulticastHandlerIndex);
2744
2745 void CmiMulticastDeliver(MultiMsg msg)
2746 {
2747   int npes, *pes; int olen, nlen, pos, child1, child2;
2748   olen = msg->origlen;
2749   nlen = olen + sizeof(struct MultiMsg);
2750   CmiLookupGroup(msg->group, &npes, &pes);
2751   if (pes==0) {
2752     CmiSyncSendAndFree(CmiMyPe(), nlen, msg);
2753     return;
2754   }
2755   if (npes==0) {
2756     CmiFree(msg);
2757     return;
2758   }
2759   if (msg->pos == -1) {
2760     msg->pos=0;
2761     CmiSyncSendAndFree(pes[0], nlen, msg);
2762     return;
2763   }
2764   pos = msg->pos;
2765   child1 = ((pos+1)<<1);
2766   child2 = child1-1;
2767   if (child1 < npes) {
2768     msg->pos = child1;
2769     CmiSyncSend(pes[child1], nlen, msg);
2770   }
2771   if (child2 < npes) {
2772     msg->pos = child2;
2773     CmiSyncSend(pes[child2], nlen, msg);
2774   }
2775   if(olen < sizeof(struct MultiMsg)) {
2776     memcpy(msg, msg+1, olen);
2777   } else {
2778     memcpy(msg, (((char*)msg)+olen), sizeof(struct MultiMsg));
2779   }
2780   CmiSyncSendAndFree(CmiMyPe(), olen, msg);
2781 }
2782
2783 void CmiMulticastHandler(MultiMsg msg)
2784 {
2785   CmiMulticastDeliver(msg);
2786 }
2787
2788 void CmiSyncMulticastFn(CmiGroup grp, int len, char *msg)
2789 {
2790   int newlen; MultiMsg newmsg;
2791   newlen = len + sizeof(struct MultiMsg);
2792   newmsg = (MultiMsg)CmiAlloc(newlen);
2793   if(len < sizeof(struct MultiMsg)) {
2794     memcpy(newmsg+1, msg, len);
2795   } else {
2796     memcpy(newmsg+1, msg+sizeof(struct MultiMsg), len-sizeof(struct MultiMsg));
2797     memcpy(((char *)newmsg+len), msg, sizeof(struct MultiMsg));
2798   }
2799   newmsg->group = grp;
2800   newmsg->origlen = len;
2801   newmsg->pos = -1;
2802   CmiSetHandler(newmsg, CpvAccess(CmiMulticastHandlerIndex));
2803   CmiMulticastDeliver(newmsg);
2804 }
2805
2806 void CmiFreeMulticastFn(CmiGroup grp, int len, char *msg)
2807 {
2808   CmiSyncMulticastFn(grp, len, msg);
2809   CmiFree(msg);
2810 }
2811
2812 CmiCommHandle CmiAsyncMulticastFn(CmiGroup grp, int len, char *msg)
2813 {
2814   CmiError("Async Multicast not implemented.");
2815   return (CmiCommHandle) 0;
2816 }
2817
2818 void CmiMulticastInit()
2819 {
2820   CpvInitialize(int, CmiMulticastHandlerIndex);
2821   CpvAccess(CmiMulticastHandlerIndex) =
2822     CmiRegisterHandler((CmiHandler)CmiMulticastHandler);
2823 }
2824
2825 #endif
2826
2827 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
2828 extern void *arena_malloc(int size);
2829 extern void arena_free(void *blockPtr);
2830 #endif
2831
2832 /***************************************************************************
2833  *
2834  * Memory Allocation routines 
2835  *
2836  * A block of memory can consist of multiple chunks.  Each chunk has
2837  * a sizefield and a refcount.  The first chunk's refcount is a reference
2838  * count.  That's how many CmiFrees it takes to free the message.
2839  * Subsequent chunks have a refcount which is less than zero.  This is
2840  * the offset back to the start of the first chunk.
2841  *
2842  * Each chunk has a CmiChunkHeader before the user data, with the fields:
2843  *
2844  *  size: The user-allocated size of the chunk, in bytes.
2845  *
2846  *  ref: A magic reference count object. Ordinary blocks start with
2847  *     reference count 1.  When the reference count reaches zero,
2848  *     the block is deleted.  To support nested buffers, the 
2849  *     reference count can also be negative, which means it is 
2850  *     a byte offset to the enclosing buffer's reference count.
2851  *
2852  ***************************************************************************/
2853
2854
2855 void *CmiAlloc(int size)
2856 {
2857
2858   char *res;
2859
2860 #if CONVERSE_VERSION_ELAN
2861   res = (char *) elan_CmiAlloc(size+sizeof(CmiChunkHeader));
2862 #elif CONVERSE_VERSION_VMI
2863   res = (char *) CMI_VMI_CmiAlloc(size+sizeof(CmiChunkHeader));
2864 #elif CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
2865   res = (char*) arena_malloc(size+sizeof(CmiChunkHeader));
2866 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
2867   res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
2868 #elif CMK_CONVERSE_GEMINI_UGNI
2869   res =(char *) LrtsAlloc(size, sizeof(CmiChunkHeader));
2870 #elif CONVERSE_POOL
2871   res =(char *) CmiPoolAlloc(size+sizeof(CmiChunkHeader));
2872 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
2873   MPI_Alloc_mem(size+sizeof(CmiChunkHeader), MPI_INFO_NULL, &res);
2874 #elif CMK_SMP && CMK_BLUEGENEQ && CMK_USE_L2ATOMICS
2875   res = (char *) CmiAlloc_bgq(size+sizeof(CmiChunkHeader));
2876 #else
2877   res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
2878 #endif
2879
2880   _MEMCHECK(res);
2881
2882 #ifdef MEMMONITOR
2883   CpvAccess(MemoryUsage) += size+sizeof(CmiChunkHeader);
2884   CpvAccess(AllocCount)++;
2885   CpvAccess(BlocksAllocated)++;
2886   if (CpvAccess(MemoryUsage) > CpvAccess(HiWaterMark)) {
2887     CpvAccess(HiWaterMark) = CpvAccess(MemoryUsage);
2888   }
2889   if (CpvAccess(MemoryUsage) > 1.1 * CpvAccess(ReportedHiWaterMark)) {
2890     CmiPrintf("HIMEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
2891             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
2892             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
2893     CpvAccess(ReportedHiWaterMark) = CpvAccess(MemoryUsage);
2894   }
2895   if ((CpvAccess(AllocCount) % 1000) == 0) {
2896     CmiPrintf("MEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
2897             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
2898             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
2899   }
2900 #endif
2901
2902   res+=sizeof(CmiChunkHeader);
2903   SIZEFIELD(res)=size;
2904   REFFIELD(res)=1;
2905   return (void *)res;
2906 }
2907
2908 /** Follow the header links out to the most enclosing block */
2909 static void *CmiAllocFindEnclosing(void *blk) {
2910   int refCount = REFFIELD(blk);
2911   while (refCount < 0) {
2912     blk = (void *)((char*)blk+refCount); /* Jump to enclosing block */
2913     refCount = REFFIELD(blk);
2914   }
2915   return blk;
2916 }
2917
2918 int CmiGetReference(void *blk)
2919 {
2920   return REFFIELD(CmiAllocFindEnclosing(blk));
2921 }
2922
2923 /** Increment the reference count for this block's owner.
2924     This call must be matched by an equivalent CmiFree. */
2925 void CmiReference(void *blk)
2926 {
2927   REFFIELD(CmiAllocFindEnclosing(blk))++;
2928 }
2929
2930 /** Return the size of the user portion of this block. */
2931 int CmiSize(void *blk)
2932 {
2933   return SIZEFIELD(blk);
2934 }
2935
2936 /** Decrement the reference count for this block. */
2937 void CmiFree(void *blk)
2938 {
2939   void *parentBlk=CmiAllocFindEnclosing(blk);
2940   int refCount=REFFIELD(parentBlk);
2941 #if CMK_ERROR_CHECKING
2942   if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
2943     CmiAbort("CmiFree reference count was zero-- is this a duplicate free?");
2944 #endif
2945   refCount--;
2946   REFFIELD(parentBlk) = refCount;
2947   if(refCount==0) { /* This was the last reference to the block-- free it */
2948 #ifdef MEMMONITOR
2949     int size=SIZEFIELD(parentBlk);
2950     if (size > 1000000000) /* Absurdly large size field-- warning */
2951       CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
2952     CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader));
2953     CpvAccess(BlocksAllocated)--;
2954 #endif
2955
2956 #if CONVERSE_VERSION_ELAN
2957     elan_CmiFree(BLKSTART(parentBlk));
2958 #elif CONVERSE_VERSION_VMI
2959     CMI_VMI_CmiFree(BLKSTART(parentBlk));
2960 #elif CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
2961     arena_free(BLKSTART(parentBlk));
2962 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
2963     /* is this message the head of a MultipleSend that we received?
2964        Then the parts with INFIMULTIPOOL have metadata which must be 
2965        unregistered and freed.  */
2966 #ifdef CMK_IBVERS_CLEAN_MULTIPLESEND
2967     if(CmiGetHandler(parentBlk)==CpvAccess(CmiMainHandlerIDP))
2968       {
2969         infi_freeMultipleSend(parentBlk);
2970       }
2971 #endif
2972     infi_CmiFree(BLKSTART(parentBlk));
2973 #elif CMK_CONVERSE_GEMINI_UGNI
2974     LrtsFree(BLKSTART(parentBlk));
2975 #elif CONVERSE_POOL
2976     CmiPoolFree(BLKSTART(parentBlk));
2977 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
2978     MPI_Free_mem(parentBlk);
2979 #elif CMK_SMP && CMK_BLUEGENEQ && CMK_USE_L2ATOMICS
2980     CmiFree_bgq(BLKSTART(parentBlk));
2981 #else
2982     free_nomigrate(BLKSTART(parentBlk));
2983 #endif
2984   }
2985 }
2986
2987
2988 /***************************************************************************
2989  *
2990  * Temporary-memory Allocation routines 
2991  *
2992  *  This buffer augments the storage available on the regular machine stack
2993  * for fairly large temporary buffers, which allows us to use smaller machine
2994  * stacks.
2995  *
2996  ***************************************************************************/
2997
2998 #define CMI_TMP_BUF_MAX 128*1024 /* Allow this much temporary storage. */
2999
3000 typedef struct {
3001   char *buf; /* Start of temporary buffer */
3002   int cur; /* First unused location in temporary buffer */
3003   int max; /* Length of temporary buffer */
3004 } CmiTmpBuf_t;
3005 CpvDeclare(CmiTmpBuf_t,CmiTmpBuf); /* One temporary buffer per PE */
3006
3007 static void CmiTmpSetup(CmiTmpBuf_t *b) {
3008   b->buf=malloc(CMI_TMP_BUF_MAX);
3009   b->cur=0;
3010   b->max=CMI_TMP_BUF_MAX;
3011 }
3012
3013 void *CmiTmpAlloc(int size) {
3014   if (!CpvInitialized(CmiTmpBuf)) {
3015     return malloc(size);
3016   }
3017   else { /* regular case */
3018     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3019     void *t;
3020     if (b->cur+size>b->max) {
3021       if (b->max==0) /* We're just uninitialized */
3022         CmiTmpSetup(b);
3023       else /* We're really out of space! */
3024         CmiAbort("CmiTmpAlloc: asked for too much temporary buffer space");
3025     }
3026     t=b->buf+b->cur;
3027     b->cur+=size;
3028     return t;
3029   }
3030 }
3031 void CmiTmpFree(void *t) {
3032   if (!CpvInitialized(CmiTmpBuf)) {
3033     free(t);
3034   }
3035   else { /* regular case */
3036     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3037     /* t should point into our temporary buffer: figure out where */
3038     int cur=((const char *)t)-b->buf;
3039 #if CMK_ERROR_CHECKING
3040     if (cur<0 || cur>b->max)
3041       CmiAbort("CmiTmpFree: called with an invalid pointer");
3042 #endif
3043     b->cur=cur;
3044   }
3045 }
3046
3047 void CmiTmpInit(char **argv) {
3048   CpvInitialize(CmiTmpBuf_t,CmiTmpBuf);
3049   /* Set up this processor's temporary buffer */
3050   CmiTmpSetup(&CpvAccess(CmiTmpBuf));
3051 }
3052
3053 /******************************************************************************
3054
3055   Cross-platform directory creation
3056
3057   ****************************************************************************/
3058 #ifdef _MSC_VER
3059 /* Windows directory creation: */
3060 #include <windows.h>
3061
3062 void CmiMkdir(const char *dirName) {
3063         CreateDirectory(dirName,NULL);
3064 }
3065
3066 #else /* !_MSC_VER */
3067 /* UNIX directory creation */
3068 #include <unistd.h> 
3069 #include <sys/stat.h> /* from "mkdir" man page */
3070 #include <sys/types.h>
3071
3072 void CmiMkdir(const char *dirName) {
3073 #ifndef __MINGW_H
3074         mkdir(dirName,0777);
3075 #else
3076         mkdir(dirName);
3077 #endif
3078 }
3079
3080 #endif
3081
3082
3083 /******************************************************************************
3084
3085   Multiple Send function                               
3086
3087   ****************************************************************************/
3088
3089
3090
3091
3092
3093 /****************************************************************************
3094 * DESCRIPTION : This function call allows the user to send multiple messages
3095 *               from one processor to another, all intended for differnet 
3096 *               handlers.
3097 *
3098 *               Parameters :
3099 *
3100 *               destPE, len, int sizes[0..len-1], char *messages[0..len-1]
3101 *
3102 ****************************************************************************/
3103 /* Round up message size to the message granularity. 
3104    Does this by adding, then truncating.
3105 */
3106 static int roundUpSize(unsigned int s) {
3107   return (int)((s+sizeof(double)-1)&~(sizeof(double)-1));
3108 }
3109 /* Return the amount of message padding required for a message
3110    with this many user bytes. 
3111  */
3112 static int paddingSize(unsigned int s) {
3113   return roundUpSize(s)-s;
3114 }
3115
3116 /* Message header for a bundle of multiple-sent messages */
3117 typedef struct {
3118   char convHeader[CmiMsgHeaderSizeBytes];
3119   int nMessages; /* Number of distinct messages bundled below. */
3120   double pad; /* To align the first message, which follows this header */
3121 } CmiMultipleSendHeader;
3122
3123 #if CMK_USE_IBVERBS | CMK_USE_IBUD
3124 /* given a pointer to a multisend message clean up the metadata */
3125
3126 void infi_freeMultipleSend(void *msgWhole)
3127 {
3128   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3129   double pad=((CmiMultipleSendHeader *)msgWhole)->pad;
3130   int offset=sizeof(CmiMultipleSendHeader);
3131   int m;
3132   void *thisMsg=NULL;
3133   if (pad != 1234567.89) return;
3134   for(m=0;m<len;m++)
3135     {
3136       /*unreg meta, free meta, move the ptr */
3137       /* note these weird little things are not pooled */
3138       /* do NOT free the message here, we are only a part of this buffer*/
3139       infiCmiChunkHeader *ch=(infiCmiChunkHeader *)(msgWhole+offset);
3140       char *msg=(msgWhole+offset+sizeof(infiCmiChunkHeader));
3141       int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3142       infi_unregAndFreeMeta(ch->metaData);
3143       offset+= sizeof(infiCmiChunkHeader) + msgSize;
3144     }
3145 }
3146 #endif
3147
3148
3149 static void _CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[], int immed)
3150 {
3151   CmiMultipleSendHeader header;
3152   int m; /* Outgoing message */
3153
3154 #if CMK_USE_IBVERBS
3155   infiCmiChunkHeader *msgHdr;
3156 #else
3157   CmiChunkHeader *msgHdr; /* Chunk headers for each message */
3158 #endif
3159         
3160   double pad = 0; /* padding required */
3161   int vecLen; /* Number of pieces in outgoing message vector */
3162   int *vecSizes; /* Sizes of each piece we're sending out. */
3163   char **vecPtrs; /* Pointers to each piece we're sending out. */
3164   int vec; /* Entry we're currently filling out in above array */
3165         
3166 #if CMK_USE_IBVERBS
3167   msgHdr = (infiCmiChunkHeader *)CmiTmpAlloc(len * sizeof(infiCmiChunkHeader));
3168 #else
3169   msgHdr = (CmiChunkHeader *)CmiTmpAlloc(len * sizeof(CmiChunkHeader));
3170 #endif
3171         
3172   /* Allocate memory for the outgoing vector*/
3173   vecLen=1+3*len; /* Header and 3 parts per message */
3174   vecSizes = (int *)CmiTmpAlloc(vecLen * sizeof(int));
3175   vecPtrs = (char **)CmiTmpAlloc(vecLen * sizeof(char *));
3176   vec=0;
3177   
3178   /* Build the header */
3179   header.nMessages=len;
3180   CmiSetHandler(&header, CpvAccess(CmiMainHandlerIDP));
3181   header.pad = 1234567.89;
3182 #if CMK_IMMEDIATE_MSG
3183   if (immed) CmiBecomeImmediate(&header);
3184 #endif
3185   vecSizes[vec]=sizeof(header); vecPtrs[vec]=(char *)&header;
3186   vec++;
3187
3188   /* Build an entry for each message: 
3189          | CmiChunkHeader | Message data | Message padding | ...next message entry ...
3190   */
3191   for (m=0;m<len;m++) {
3192 #if CMK_USE_IBVERBS
3193     msgHdr[m].chunkHeader.size=roundUpSize(sizes[m]); /* Size of message and padding */
3194     msgHdr[m].chunkHeader.ref=0; /* Reference count will be filled out on receive side */
3195     msgHdr[m].metaData=NULL;
3196 #else
3197     msgHdr[m].size=roundUpSize(sizes[m]); /* Size of message and padding */
3198     msgHdr[m].ref=0; /* Reference count will be filled out on receive side */
3199 #endif          
3200     
3201     /* First send the message's CmiChunkHeader (for use on receive side) */
3202 #if CMK_USE_IBVERBS
3203     vecSizes[vec]=sizeof(infiCmiChunkHeader);
3204 #else
3205     vecSizes[vec]=sizeof(CmiChunkHeader); 
3206 #endif          
3207                 vecPtrs[vec]=(char *)&msgHdr[m];
3208     vec++;
3209     
3210     /* Now send the actual message data */
3211     vecSizes[vec]=sizes[m]; vecPtrs[vec]=msgComps[m];
3212     vec++;
3213     
3214     /* Now send padding to align the next message on a double-boundary */
3215     vecSizes[vec]=paddingSize(sizes[m]); vecPtrs[vec]=(char *)&pad;
3216     vec++;
3217   }
3218   CmiAssert(vec==vecLen);
3219   
3220   CmiSyncVectorSend(destPE, vecLen, vecSizes, vecPtrs);
3221   
3222   CmiTmpFree(vecPtrs); /* CmiTmp: Be sure to throw away in opposite order of allocation */
3223   CmiTmpFree(vecSizes);
3224   CmiTmpFree(msgHdr);
3225 }
3226
3227 void CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3228 {
3229   _CmiMultipleSend(destPE, len, sizes, msgComps, 0);
3230 }
3231
3232 void CmiMultipleIsend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3233 {
3234   _CmiMultipleSend(destPE, len, sizes, msgComps, 1);
3235 }
3236
3237 /****************************************************************************
3238 * DESCRIPTION : This function initializes the main handler required for the
3239 *               CmiMultipleSend() function to work. 
3240 *               
3241 *               This function should be called once in any Converse program
3242 *               that uses CmiMultipleSend()
3243 *
3244 ****************************************************************************/
3245
3246 static void CmiMultiMsgHandler(char *msgWhole);
3247
3248 void CmiInitMultipleSend(void)
3249 {
3250   CpvInitialize(int,CmiMainHandlerIDP); 
3251   CpvAccess(CmiMainHandlerIDP) =
3252     CmiRegisterHandler((CmiHandler)CmiMultiMsgHandler);
3253 }
3254
3255 /****************************************************************************
3256 * DESCRIPTION : This function is the main handler that splits up the messages
3257 *               CmiMultipleSend() pastes together. 
3258 *
3259 ****************************************************************************/
3260
3261 static void CmiMultiMsgHandler(char *msgWhole)
3262 {
3263   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3264   int offset=sizeof(CmiMultipleSendHeader);
3265   int m;
3266   for (m=0;m<len;m++) {
3267 #if CMK_USE_IBVERBS
3268     infiCmiChunkHeader *ch=(infiCmiChunkHeader *)(msgWhole+offset);
3269     char *msg=(msgWhole+offset+sizeof(infiCmiChunkHeader));
3270     int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3271     ch->chunkHeader.ref=msgWhole-msg; 
3272     ch->metaData =  registerMultiSendMesg(msg,msgSize);
3273 #else
3274     CmiChunkHeader *ch=(CmiChunkHeader *)(msgWhole+offset);
3275     char *msg=(msgWhole+offset+sizeof(CmiChunkHeader));
3276     int msgSize=ch->size; /* Size of user portion of message (plus padding at end) */
3277     ch->ref=msgWhole-msg; 
3278 #endif          
3279     /* Link new message to owner via a negative ref pointer */
3280     CmiReference(msg); /* Follows link & increases reference count of *msgWhole* */
3281     CmiSyncSendAndFree(CmiMyPe(), msgSize, msg);
3282 #if CMK_USE_IBVERBS
3283     offset+= sizeof(infiCmiChunkHeader) + msgSize;
3284 #else
3285     offset+= sizeof(CmiChunkHeader) + msgSize;
3286 #endif          
3287   }
3288   /* Release our reference to the whole message.  The message will
3289      only actually be deleted once all its sub-messages are free'd as well. */
3290   CmiFree(msgWhole);
3291 }
3292
3293 /****************************************************************************
3294 * Hypercube broadcast message passing.
3295 ****************************************************************************/
3296
3297 int HypercubeGetBcastDestinations(int mype, int total_pes, int k, int *dest_pes) {
3298   int num_pes = 0;
3299   for ( ; k>=0; --k) {
3300     /* add the processor destination at level k if it exist */
3301     dest_pes[num_pes] = mype ^ (1<<k);
3302     if (dest_pes[num_pes] >= total_pes) {
3303       /* find the first proc in the other part of the current dimention */
3304       dest_pes[num_pes] &= (-1)<<k;
3305       /* if the first proc there is over CmiNumPes() then there is no other
3306          dimension, otherwise if it is valid compute my correspondent in such
3307          a way to minimize the load for every processor */
3308       if (total_pes>dest_pes[num_pes]) dest_pes[num_pes] += (mype - (mype & ((-1)<<k))) % (total_pes - dest_pes[num_pes]);
3309       }
3310     if (dest_pes[num_pes] < total_pes) {
3311       /* if the destination is in the acceptable range increment num_pes */
3312       ++num_pes;
3313     }
3314   }
3315   return num_pes;
3316 }
3317
3318
3319 /****************************************************************************
3320 * DESCRIPTION : This function initializes the main handler required for the
3321 *               Immediate message
3322 *               
3323 *               This function should be called once in any Converse program
3324 *
3325 ****************************************************************************/
3326
3327 int _immediateLock = 0; /* if locked, all immediate message handling will be delayed. */
3328 int _immediateFlag = 0; /* if set, there is delayed immediate message. */
3329
3330 CpvDeclare(int, CmiImmediateMsgHandlerIdx); /* Main handler that is run on every node */
3331
3332 /* xdl is the real handler */
3333 static void CmiImmediateMsgHandler(char *msg)
3334 {
3335   CmiSetHandler(msg, CmiGetXHandler(msg));
3336   CmiHandleMessage(msg);
3337 }
3338
3339 void CmiInitImmediateMsg(void)
3340 {
3341   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
3342   CpvAccess(CmiImmediateMsgHandlerIdx) =
3343     CmiRegisterHandler((CmiHandler)CmiImmediateMsgHandler);
3344 }
3345
3346 /*#if !CMK_IMMEDIATE_MSG
3347 #if !CMK_MACHINE_PROGRESS_DEFINED
3348 void CmiProbeImmediateMsg()
3349 {
3350 }
3351 #endif
3352 #endif*/
3353
3354 /******** Idle timeout module (+idletimeout=30) *********/
3355
3356 typedef struct {
3357   int idle_timeout;/*Milliseconds to wait idle before aborting*/
3358   int is_idle;/*Boolean currently-idle flag*/
3359   int call_count;/*Number of timeout calls currently in flight*/
3360 } cmi_cpu_idlerec;
3361
3362 static void on_timeout(cmi_cpu_idlerec *rec,double curWallTime)
3363 {
3364   rec->call_count--;
3365   if(rec->call_count==0 && rec->is_idle==1) {
3366     CmiError("Idle time on PE %d exceeded specified timeout.\n", CmiMyPe());
3367     CmiAbort("Exiting.\n");
3368   }
3369 }
3370 static void on_idle(cmi_cpu_idlerec *rec,double curWallTime)
3371 {
3372   CcdCallFnAfter((CcdVoidFn)on_timeout, rec, rec->idle_timeout);
3373   rec->call_count++; /*Keeps track of overlapping timeout calls.*/  
3374   rec->is_idle = 1;
3375 }
3376 static void on_busy(cmi_cpu_idlerec *rec,double curWallTime)
3377 {
3378   rec->is_idle = 0;
3379 }
3380 static void CIdleTimeoutInit(char **argv)
3381 {
3382   int idle_timeout=0; /*Seconds to wait*/
3383   CmiGetArgIntDesc(argv,"+idle-timeout",&idle_timeout,"Abort if idle for this many seconds");
3384   if(idle_timeout != 0) {
3385     cmi_cpu_idlerec *rec=(cmi_cpu_idlerec *)malloc(sizeof(cmi_cpu_idlerec));
3386     _MEMCHECK(rec);
3387     rec->idle_timeout=idle_timeout*1000;
3388     rec->is_idle=0;
3389     rec->call_count=0;
3390     CcdCallOnCondition(CcdPROCESSOR_BEGIN_IDLE, (CcdVoidFn)on_idle, rec);
3391     CcdCallOnCondition(CcdPROCESSOR_BEGIN_BUSY, (CcdVoidFn)on_busy, rec);
3392   }
3393 }
3394
3395 /*****************************************************************************
3396  *
3397  * Converse Initialization
3398  *
3399  *****************************************************************************/
3400
3401 extern void CrnInit(void);
3402 extern void CmiIsomallocInit(char **argv);
3403 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3404 void CmiIOInit(char **argv);
3405 #endif
3406
3407 /* defined in cpuaffinity.c */
3408 extern void CmiInitCPUAffinityUtil();
3409
3410 static void CmiProcessPriority(char **argv)
3411 {
3412   int dummy, nicelevel=-100;      /* process priority */
3413   CmiGetArgIntDesc(argv,"+nice",&nicelevel,"Set the process priority level");
3414   /* ignore others */
3415   while (CmiGetArgIntDesc(argv,"+nice",&dummy,"Set the process priority level"));
3416   /* call setpriority once on each process to set process's priority */
3417   if (CmiMyRank() == 0 && nicelevel != -100)  {
3418 #ifndef _WIN32
3419     if (0!=setpriority(PRIO_PROCESS, 0, nicelevel))  {
3420       CmiPrintf("[%d] setpriority failed with value %d. \n", CmiMyPe(), nicelevel);
3421       perror("setpriority");
3422       CmiAbort("setpriority failed.");
3423     }
3424     else
3425       CmiPrintf("[%d] Charm++: setpriority %d\n", CmiMyPe(), nicelevel);
3426 #else
3427     HANDLE hProcess = GetCurrentProcess();
3428     DWORD dwPriorityClass = NORMAL_PRIORITY_CLASS;
3429     char *prio_str = "NORMAL_PRIORITY_CLASS";
3430     BOOL status;
3431     /*
3432        <-20:      real time
3433        -20--10:   high 
3434        -10-0:     above normal
3435        0:         normal
3436        0-10:      below normal
3437        10-:       idle
3438     */
3439     if (0) ;
3440 #ifdef BELOW_NORMAL_PRIORITY_CLASS
3441     else if (nicelevel<10 && nicelevel>0) {
3442       dwPriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
3443       prio_str = "BELOW_NORMAL_PRIORITY_CLASS";
3444     }
3445 #endif
3446     else if (nicelevel>0) {
3447       dwPriorityClass = IDLE_PRIORITY_CLASS;
3448       prio_str = "IDLE_PRIORITY_CLASS";
3449     }
3450     else if (nicelevel<=-20) {
3451       dwPriorityClass = REALTIME_PRIORITY_CLASS;
3452       prio_str = "REALTIME_PRIORITY_CLASS";
3453     }
3454 #ifdef ABOVE_NORMAL_PRIORITY_CLASS
3455     else if (nicelevel>-10 && nicelevel<0) {
3456       dwPriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
3457       prio_str = "ABOVE_NORMAL_PRIORITY_CLASS";
3458     }
3459 #endif
3460     else if (nicelevel<0) {
3461       dwPriorityClass = HIGH_PRIORITY_CLASS;
3462       prio_str = "HIGH_PRIORITY_CLASS";
3463     }
3464     status = SetPriorityClass(hProcess, dwPriorityClass);
3465     if (!status)  {
3466         int err=GetLastError();
3467         CmiPrintf("SetPriorityClass failed errno=%d, WSAerr=%d\n",errno, err);
3468         CmiAbort("SetPriorityClass failed.");
3469     }
3470     else
3471       CmiPrintf("[%d] Charm++: setpriority %s\n", CmiMyPe(), prio_str);
3472 #endif
3473   }
3474 }
3475
3476 void CommunicationServerInit()
3477 {
3478 #if CMK_IMMEDIATE_MSG
3479   CQdCpvInit();
3480   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
3481 #endif
3482 }
3483
3484
3485 static int testEndian(void)
3486 {
3487         int test=0x1c;
3488         unsigned char *c=(unsigned char *)&test;
3489         if (c[sizeof(int)-1]==0x1c)
3490                 /* Macintosh and most workstations are big-endian */
3491                 return 1;   /* Big-endian machine */
3492         if (c[0]==0x1c)
3493                 /* Intel x86 PC's, and DEC VAX are little-endian */
3494                 return 0;  /* Little-endian machine */
3495         return -2;  /*Unknown integer type */
3496 }
3497
3498 int CmiEndianness()
3499 {
3500   static int _cmi_endianness = -1;
3501   if (_cmi_endianness == -1) _cmi_endianness = testEndian();
3502   CmiAssert(_cmi_endianness != -2);
3503   return  _cmi_endianness;
3504 }
3505
3506 /**
3507   Main Converse initialization routine.  This routine is 
3508   called by the machine file (machine.c) to set up Converse.
3509   It's "Common" because it's shared by all the machine.c files. 
3510   
3511   The main task of this routine is to set up all the Cpv's
3512   (message queues, handler tables, etc.) used during main execution.
3513   
3514   On SMP versions, this initialization routine is called by 
3515   *all* processors of a node simultaniously.  It's *also* called
3516   by the communication thread, which is rather strange but needed
3517   for immediate messages.  Each call to this routine expects a 
3518   different copy of the argv arguments, so use CmiCopyArgs(argv).
3519   
3520   Requires:
3521     - A working network layer.
3522     - Working Cpv's and CmiNodeBarrier.
3523     - CthInit to already have been called.  CthInit is called
3524       from the machine layer directly, because some machine layers
3525       (like uth) use Converse threads internally.
3526
3527   Initialization is somewhat subtle, in that various modules
3528   won't work properly until they're initialized.  For example,
3529   nobody can register handlers before calling CmiHandlerInit.
3530 */
3531 void ConverseCommonInit(char **argv)
3532 {
3533
3534 /**
3535  * The reason to initialize this variable here:
3536  * cmiArgDebugFlag is possibly accessed in CmiPrintf/CmiError etc.,
3537  * therefore, we have to initialize this variable before any calls
3538  * to those functions (such as CmiPrintf). Otherwise, we may encounter
3539  * a memory segmentation fault (bad memory access). Note, even
3540  * testing CpvInitialized(cmiArgDebugFlag) doesn't help to solve
3541  * this problem because the variable indicating whether cmiArgDebugFlag is 
3542  * initialized or not is not initialized, thus possibly causing another
3543  * bad memory access. --Chao Mei
3544  */
3545   CpvInitialize(int, _urgentSend);
3546   CpvAccess(_urgentSend) = 0;
3547 #if CMK_CCS_AVAILABLE
3548   CpvInitialize(int, cmiArgDebugFlag);
3549   CpvAccess(cmiArgDebugFlag) = 0;
3550 #endif
3551   CpvInitialize(int,charmLibExitFlag);
3552   CpvAccess(charmLibExitFlag) = 0;
3553
3554   CpvInitialize(int,_curRestartPhase);
3555   CpvAccess(_curRestartPhase)=1;
3556   CmiArgInit(argv);
3557   CmiMemoryInit(argv);
3558 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3559   CmiIOInit(argv);
3560 #endif
3561   if (CmiMyPe() == 0)
3562       CmiPrintf("Converse/Charm++ Commit ID: %s\n", CmiCommitID);
3563
3564   CpvInitialize(int, cmiMyPeIdle);
3565   CpvAccess(cmiMyPeIdle) = 0;
3566
3567 /* #if CONVERSE_POOL */
3568   CmiPoolAllocInit(30);  
3569 /* #endif */
3570   CmiTmpInit(argv);
3571   CmiTimerInit(argv);
3572   CstatsInit(argv);
3573   CmiInitCPUAffinityUtil();
3574
3575   CcdModuleInit(argv);
3576   CmiHandlerInit();
3577   CmiReductionsInit();
3578   CIdleTimeoutInit(argv);
3579   
3580 #if CMK_SHARED_VARS_POSIX_THREADS_SMP /*Used by the net-*-smp versions*/
3581   if(CmiGetArgFlagDesc(argv,"+CmiNoProcForComThread","Is there an extra processor for the communication thread on each node(only for net-smp-*) ?")){
3582     if(CmiMyRank() == 0) _Cmi_noprocforcommthread=1;
3583    }
3584 #endif
3585         
3586 #if CMK_TRACE_ENABLED
3587   traceInit(argv);
3588 /*initTraceCore(argv);*/ /* projector */
3589 #endif
3590   CmiProcessPriority(argv);
3591
3592   CmiPersistentInit();
3593   CmiIsomallocInit(argv);
3594   CmiDeliversInit();
3595   CsdInit(argv);
3596 #if CMK_CCS_AVAILABLE
3597   CcsInit(argv);
3598 #endif
3599   CpdInit();
3600   CthSchedInit();
3601   CmiGroupInit();
3602   CmiMulticastInit();
3603   CmiInitMultipleSend();
3604   CQdInit();
3605
3606   CrnInit();
3607   CmiInitImmediateMsg();
3608   CldModuleInit(argv);
3609   
3610 #if CMK_CELL
3611   void CmiInitCell();
3612   CmiInitCell();
3613 #endif
3614
3615 #ifdef CMK_CUDA
3616   initHybridAPI(CmiMyPe()); 
3617 #endif
3618
3619   /* main thread is suspendable */
3620 /*
3621   CthSetSuspendable(CthSelf(), 0);
3622 */
3623
3624 #if CMK_BIGSIM_CHARM
3625    /* have to initialize QD here instead of _initCharm */
3626   extern void initQd(char **argv);
3627   initQd(argv);
3628 #endif
3629 }
3630
3631 void ConverseCommonExit(void)
3632 {
3633   CcsImpl_kill();
3634
3635 #if CMK_TRACE_ENABLED
3636   traceClose();
3637 /*closeTraceCore();*/ /* projector */
3638 #endif
3639
3640 #if CMI_IO_BUFFER_EXPLICIT
3641   CmiFlush(stdout);  /* end of program, always flush */
3642 #endif
3643   CmiFlush(stdout);  /* end of program, always flush */
3644
3645 #if CMK_CELL
3646   CloseOffloadAPI();
3647 #endif
3648
3649 #if CMK_CUDA
3650   exitHybridAPI(); 
3651 #endif
3652   seedBalancerExit();
3653   EmergencyExit();
3654 }
3655
3656
3657 #if CMK_CELL != 0
3658
3659 extern void register_accel_spe_funcs(void);
3660
3661 void CmiInitCell()
3662 {
3663   // Create a unique string for each PPE to use for the timing
3664   //   data file's name
3665   char fileNameBuf[64];
3666   sprintf(fileNameBuf, "speTiming.%d", CmiMyPe());
3667
3668   InitOffloadAPI(offloadCallback, NULL, NULL, fileNameBuf);
3669   //CcdCallOnConditionKeep(CcdPERIODIC, 
3670   //      (CcdVoidFn) OffloadAPIProgress, NULL);
3671   CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,
3672       (CcdVoidFn) OffloadAPIProgress, NULL);
3673
3674   // Register accelerated entry methods on the PPE
3675   register_accel_spe_funcs();
3676 }
3677
3678 #include "cell-api.c"
3679
3680 #endif
3681
3682 /****
3683  * CW Lee - 9/14/2005
3684  * Added a mechanism to allow some control over machines with extremely
3685  * inefficient terminal IO mechanisms. Case in point: the XT3 has a
3686  * 20ms flush overhead along with about 25MB/s bandwidth for IO. This,
3687  * coupled with a default setup using unbuffered stdout introduced
3688  * severe overheads (and hence limiting scaling) for applications like 
3689  * NAMD.
3690  */
3691 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3692 void CmiIOInit(char **argv) {
3693   CpvInitialize(int, expIOFlushFlag);
3694 #if CMI_IO_BUFFER_EXPLICIT
3695   /* 
3696      Support for an explicit buffer only makes sense if the machine
3697      layer does not wish to make its own implementation.
3698
3699      Placing this after CmiMemoryInit() means that CmiMemoryInit()
3700      MUST NOT make use of stdout if an explicit buffer is requested.
3701
3702      The setvbuf function may only be used after opening a stream and
3703      before any other operations have been performed on it
3704   */
3705   CpvInitialize(char*, explicitIOBuffer);
3706   CpvInitialize(int, expIOBufferSize);
3707   if (!CmiGetArgIntDesc(argv,"+io_buffer_size", &CpvAccess(expIOBufferSize),
3708                         "Explicit IO Buffer Size")) {
3709     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3710   }
3711   if (CpvAccess(expIOBufferSize) <= 0) {
3712     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3713   }
3714   CpvAccess(explicitIOBuffer) = (char*)CmiAlloc(CpvAccess(expIOBufferSize)*
3715                                                 sizeof(char));
3716   if (setvbuf(stdout, CpvAccess(explicitIOBuffer), _IOFBF, 
3717               CpvAccess(expIOBufferSize))) {
3718     CmiAbort("Explicit IO Buffering failed\n");
3719   }
3720 #endif
3721 #if CMI_IO_FLUSH_USER
3722   /* system default to have user control flushing of IO */
3723   /* Now look for user override */
3724   CpvAccess(expIOFlushFlag) = !CmiGetArgFlagDesc(argv,"+io_flush_system",
3725                                                  "System Controls IO Flush");
3726 #else
3727   /* system default to have system handle IO flushing */
3728   /* Now look for user override */
3729   CpvAccess(expIOFlushFlag) = CmiGetArgFlagDesc(argv,"+io_flush_user",
3730                                                 "User Controls IO Flush");
3731 #endif
3732 }
3733 #endif
3734
3735 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3736
3737 void CmiPrintf(const char *format, ...)
3738 {
3739   CpdSystemEnter();
3740   {
3741   va_list args;
3742   va_start(args,format);
3743   vfprintf(stdout,format, args);
3744   if (CpvInitialized(expIOFlushFlag) && !CpvAccess(expIOFlushFlag)) {
3745     CmiFlush(stdout);
3746   }
3747   va_end(args);
3748 #if CMK_CCS_AVAILABLE
3749   if (CpvAccess(cmiArgDebugFlag)) {
3750     va_start(args,format);
3751     print_node0(format, args);
3752     va_end(args);
3753   }
3754 #endif
3755   }
3756   CpdSystemExit();
3757 }
3758
3759 void CmiError(const char *format, ...)
3760 {
3761   CpdSystemEnter();
3762   {
3763   va_list args;
3764   va_start(args,format);
3765   vfprintf(stderr,format, args);
3766   CmiFlush(stderr);  /* stderr is always flushed */
3767   va_end(args);
3768 #if CMK_CCS_AVAILABLE
3769   if (CpvAccess(cmiArgDebugFlag)) {
3770     va_start(args,format);
3771     print_node0(format, args);
3772     va_end(args);
3773   }
3774 #endif
3775   }
3776   CpdSystemExit();
3777 }
3778
3779 #endif
3780
3781 void __cmi_assert(const char *expr, const char *file, int line)
3782 {
3783   CmiError("[%d] Assertion \"%s\" failed in file %s line %d.\n",
3784       CmiMyPe(), expr, file, line);
3785   CmiAbort("");
3786 }
3787
3788 char *CmiCopyMsg(char *msg, int len)
3789 {
3790   char *copy = (char *)CmiAlloc(len);
3791   _MEMCHECK(copy);
3792   memcpy(copy, msg, len);
3793   return copy;
3794 }
3795
3796 unsigned char computeCheckSum(unsigned char *data, int len)
3797 {
3798   int i;
3799   unsigned char ret = 0;
3800   for (i=0; i<len; i++) ret ^= (unsigned char)data[i];
3801   return ret;
3802 }
3803
3804 /* Flag for bigsim's out-of-core emulation */
3805 int _BgOutOfCoreFlag=0; /*indicate the type of memory operation (in or out) */
3806 int _BgInOutOfCoreMode=0; /*indicate whether the emulation is in the out-of-core emulation mode */
3807
3808 #if !CMK_HAS_LOG2
3809 unsigned int CmiILog2(unsigned int val) {
3810   unsigned int log = 0u;
3811   if ( val != 0u ) {
3812       while ( val > (1u<<log) ) { log++; }
3813   }
3814   return log;
3815 }
3816 double CmiLog2(double x) {
3817   return log(x)/log(2);
3818 }
3819 #endif
3820
3821 /* for bigsim */
3822 int CmiMyRank_()
3823 {
3824   return CmiMyRank();
3825 }
3826
3827 double CmiReadSize(const char *str)
3828 {
3829     double val;
3830     if (strpbrk(str,"Gg")) {
3831         //sscanf(str, "%llf", &val);
3832         //val = strtod(str, &p);
3833         val = atof(str);
3834         val *= 1024ll*1024*1024;
3835     }
3836     else if (strpbrk(str,"Mm")) {
3837         val = atof(str);
3838         val *= 1024*1024;
3839     }
3840     else if (strpbrk(str,"Kk")) {
3841         val = atof(str);
3842         val *= 1024;
3843     }
3844     else {
3845         val = atof(str);
3846     }
3847     return val;
3848 }
3849
3850 int CmiIsMyNodeIdle(){
3851     int i;
3852     for(i=0; i<CmiMyNodeSize(); i++){
3853         if(CpvAccessOther(cmiMyPeIdle, i)) return 1;
3854     }
3855     return 0;
3856 }
3857
3858 /*@}*/