Route ampif77 and ampif90 through ampiCC, factoring out duplicated code
[charm.git] / src / conv-core / convcore.C
blobb86d1fcf5fe0d9c5df0ad6b97b4fe90ce6833478
1 /** 
2   @defgroup Converse
3   \brief Converse--a parallel portability layer.
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.
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.
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.
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).
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).
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.
39   Incoming messages that are destined for Charm++ will be passed to the 
40   \ref CharmScheduler "charm scheduling routines".
42   @file
43   converse main core
44   @ingroup Converse
45   @ingroup ConverseScheduler
47   @addtogroup Converse
48   @{
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include "hrctimer.h"
56 #ifndef __STDC_FORMAT_MACROS
57 # define __STDC_FORMAT_MACROS
58 #endif
59 #ifndef __STDC_LIMIT_MACROS
60 # define __STDC_LIMIT_MACROS
61 #endif
62 #include <inttypes.h>
63 #include <errno.h>
64 #ifndef _WIN32
65 #include <sys/time.h>
66 #include <sys/resource.h>
67 #else
68 #define snprintf _snprintf
69 #endif
71 #include "converse.h"
72 #include "conv-trace.h"
73 #include "sockRoutines.h"
74 #include "queueing.h"
75 #if CMK_SMP && CMK_TASKQUEUE
76 #include "taskqueue.h"
77 #include "conv-taskQ.h"
78 #endif
79 #include "conv-ccs.h"
80 #include "ccs-server.h"
81 #include "memory-isomalloc.h"
82 #if CMK_PROJECTOR
83 #include "converseEvents.h"             /* projector */
84 #include "traceCoreCommon.h"    /* projector */
85 #include "machineEvents.h"     /* projector */
86 #endif
88 CMI_EXTERNC_VARIABLE const char * const CmiCommitID;
90 #if CMI_QD
91 CMI_EXTERNC void initQd(char **argv);
92 #endif
94 #if CMK_OUT_OF_CORE
95 #include "conv-ooc.h"
96 #endif
98 #if CONVERSE_POOL
99 #include "cmipool.h"
100 #else
101 void CmiPoolAllocInit(int numBins);
102 #endif
104 #if CMK_CONDS_USE_SPECIAL_CODE
105 CmiSwitchToPEFnPtr CmiSwitchToPE;
106 #endif
108 CpvExtern(int, _traceCoreOn);   /* projector */
109 CMI_EXTERNC void CcdModuleInit(char **);
110 CMI_EXTERNC
111 void CmiMemoryInit(char **);
112 CMI_EXTERNC void CldModuleInit(char **);
114 #if CMK_WHEN_PROCESSOR_IDLE_USLEEP
115 #include <sys/types.h>
116 #include <sys/time.h>
117 #endif
119 #if CMK_TIMER_USE_TIMES
120 #include <sys/times.h>
121 #include <limits.h>
122 #include <unistd.h>
123 #endif
125 #if CMK_TIMER_USE_GETRUSAGE
126 #include <sys/time.h>
127 #include <sys/resource.h>
128 #endif
130 #if CMK_TIMER_USE_RDTSC
131 #include <string.h>
132 #include <unistd.h>
133 #include <time.h>
134 #include <stdio.h>
135 #include <sys/time.h>
136 #include <sys/resource.h>
137 #endif
139 #ifdef CMK_TIMER_USE_WIN32API
140 #include <stdlib.h>
141 #include <time.h>
142 #include <sys/types.h>
143 #include <sys/timeb.h>
144 #endif
146 #ifdef CMK_HAS_ASCTIME
147 #include <time.h>
148 #endif
150 #include "quiescence.h"
152 #if USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
153 #include <mpi.h>
154 #endif
156 #if CMK_TRACE_ENABLED
157 struct envelope;
158 void traceAddThreadListeners(CthThread tid, struct envelope *env);
159 #endif
161 CMI_EXTERNC void seedBalancerExit(void);
162 CMI_EXTERNC
163 void EmergencyExit(void);
165 //int cur_restart_phase = 1;      /* checkpointing/restarting phase counter */
166 CpvDeclare(int,_curRestartPhase);
167 static int CsdLocalMax = CSD_LOCAL_MAX_DEFAULT;
169 int CharmLibInterOperate = 0;
170 CpvCExtern(int,interopExitFlag);
171 CpvDeclare(int,interopExitFlag);
173 CpvStaticDeclare(int, CmiMainHandlerIDP); /* Main handler for _CmiMultipleSend that is run on every node */
175 #if CMK_MEM_CHECKPOINT
176 void (*notify_crash_fn)(int) = NULL;
177 #endif
179 CpvDeclare(char *, _validProcessors);
181 #if CMK_CUDA
182 CpvExtern(int, n_hapi_events);
183 CMI_EXTERNC
184 void hapiPollEvents();
185 CMI_EXTERNC
186 void exitHybridAPI();
187 #endif
189 /*****************************************************************************
191  * Unix Stub Functions
193  ****************************************************************************/
195 #ifdef MEMMONITOR
196 typedef unsigned long mmulong;
197 CpvDeclare(mmulong,MemoryUsage);
198 CpvDeclare(mmulong,HiWaterMark);
199 CpvDeclare(mmulong,ReportedHiWaterMark);
200 CpvDeclare(int,AllocCount);
201 CpvDeclare(int,BlocksAllocated);
202 #endif
204 #define MAX_HANDLERS 512
206 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
207 CpvDeclare(int,expIOFlushFlag);
208 #if CMI_IO_BUFFER_EXPLICIT
209 /* 250k not too large depending on how slow terminal IO is */
210 #define DEFAULT_IO_BUFFER_SIZE 250000
211 CpvDeclare(char*,explicitIOBuffer);
212 CpvDeclare(int,expIOBufferSize);
213 #endif
214 #endif
216 #if CMK_NODE_QUEUE_AVAILABLE
217 CMI_EXTERNC
218 void  *CmiGetNonLocalNodeQ();
219 #endif
221 CpvDeclare(Queue, CsdSchedQueue);
223 #if CMK_OUT_OF_CORE
224 /* The Queue where the Prefetch Thread puts the messages from CsdSchedQueue  */
225 CpvDeclare(Queue, CsdPrefetchQueue);
226 pthread_mutex_t prefetchLock;
227 #endif
229 #if CMK_NODE_QUEUE_AVAILABLE
230 CsvDeclare(Queue, CsdNodeQueue);
231 CsvDeclare(CmiNodeLock, CsdNodeQueueLock);
232 #endif
233 CpvDeclare(int,   CsdStopFlag);
234 CpvDeclare(int,   CsdLocalCounter);
236 CpvDeclare(int,   _urgentSend);
238 CmiNodeLock _smp_mutex;               /* for smp */
240 #if CMK_USE_IBVERBS | CMK_USE_IBUD
241 CMI_EXTERNC
242 void *infi_CmiAlloc(int size);
243 CMI_EXTERNC
244 void infi_CmiFree(void *ptr);
245 void infi_freeMultipleSend(void *ptr);
246 CMI_EXTERNC
247 void infi_unregAndFreeMeta(void *ch);
248 #endif
250 #if CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
251 CMI_EXTERNC void * CmiAlloc_bgq (int     size);
252 CMI_EXTERNC void   CmiFree_bgq  (void  * buf);
253 #endif
255 #if CMK_SMP && CMK_PPC_ATOMIC_QUEUE
256 CMI_EXTERNC void * CmiAlloc_ppcq (int     size);
257 CMI_EXTERNC void   CmiFree_ppcq  (void  * buf);
258 #endif
260 #if CMK_GRID_QUEUE_AVAILABLE
261 CpvDeclare(void *, CkGridObject);
262 CpvDeclare(Queue, CsdGridQueue);
263 #endif
265 #if CMK_CRAYXE || CMK_CRAYXC || CMK_OFI
266 CMI_EXTERNC void* LrtsAlloc(int, int);
267 CMI_EXTERNC void* LrtsRdmaAlloc(int, int);
268 CMI_EXTERNC void  LrtsFree(void*);
269 CMI_EXTERNC void  LrtsRdmaFree(void*);
270 #endif
272 CpvStaticDeclare(int, cmiMyPeIdle);
273 #if CMK_SMP && CMK_TASKQUEUE
274 CsvDeclare(unsigned int, idleThreadsCnt);
275 CpvDeclare(Queue, CsdTaskQueue);
276 CpvDeclare(void *, CmiSuspendedTaskQueue);
277 #endif
279 CpvDeclare(int, isHelperOn);
281 CMI_EXTERNC_VARIABLE int CmiMyLocalRank;
283 int    CmiMyLocalRank;        /* local rank only for scalable startup */
285 #if CMK_LOCKLESS_QUEUE
286 /*****************************************************************************
288  * MPSCQueue and MPMCQueue variables
290  *****************************************************************************/
291 int DataNodeSize;
292 int MaxDataNodes;
293 int QueueUpperBound;
294 int DataNodeWrap;
295 int QueueWrap;
296 int messageQueueOverflow;
297 #endif
299 /*****************************************************************************
301  * Command-Line Argument (CLA) parsing routines.
303  *****************************************************************************/
305 static int usageChecked=0; /* set when argv has been searched for a usage request */
306 static int printUsage=0; /* if set, print command-line usage information */
307 static const char *CLAformatString="%20s %10s %s\n";
309 /** This little list of CLA's holds the argument descriptions until it's
310    safe to print them--it's needed because the netlrts- versions don't have 
311    printf until they're pretty well started.
312  */
313 typedef struct {
314         const char *arg; /* Flag name, like "-foo"*/
315         const char *param; /* Argument's parameter type, like "integer" or "none"*/
316         const char *desc; /* Human-readable description of what it does */
317 } CLA;
318 static int CLAlistLen=0;
319 static int CLAlistMax=0;
320 static CLA *CLAlist=NULL;
322 /** Add this CLA */
323 static void CmiAddCLA(const char *arg,const char *param,const char *desc) {
324         int i;
325         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
326         if (desc==NULL) return; /*It's an internal argument*/
327         if (usageChecked) { /* Printf should work now */
328                 if (printUsage)
329                         CmiPrintf(CLAformatString,arg,param,desc);
330         }
331         else { /* Printf doesn't work yet-- just add to the list.
332                 This assumes the const char *'s are static references,
333                 which is probably reasonable. */
334                 CLA *temp;
335                 i=CLAlistLen++;
336                 if (CLAlistLen>CLAlistMax) { /*Grow the CLA list */
337                         CLAlistMax=16+2*CLAlistLen;
338                         temp = (CLA *)realloc(CLAlist,sizeof(CLA)*CLAlistMax);
339                         if(temp != NULL) {
340                           CLAlist=temp;
341                         } else {
342                           free(CLAlist);
343                           CmiAbort("Reallocation failed for CLAlist\n");
344                         }
345                 }
346                 CLAlist[i].arg=arg;
347                 CLAlist[i].param=param;
348                 CLAlist[i].desc=desc;
349         }
352 /** Print out the stored list of CLA's */
353 static void CmiPrintCLAs(void) {
354         int i;
355         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
356         CmiPrintf("Converse Machine Command-line Parameters:\n ");
357         CmiPrintf(CLAformatString,"Option:","Parameter:","Description:");
358         for (i=0;i<CLAlistLen;i++) {
359                 CLA *c=&CLAlist[i];
360                 CmiPrintf(CLAformatString,c->arg,c->param,c->desc);
361         }
365  * Determines if command-line usage information should be printed--
366  * that is, if a "-?", "-h", or "--help" flag is present.
367  * Must be called after printf is setup.
368  */
369 void CmiArgInit(char **argv) {
370         int i;
371         CmiLock(_smp_mutex);
372         for (i=0;argv[i]!=NULL;i++)
373         {
374                 if (0==strcmp(argv[i],"-?") ||
375                     0==strcmp(argv[i],"-h") ||
376                     0==strcmp(argv[i],"--help")) 
377                 {
378                         printUsage=1;
379                         /* Don't delete arg:  CmiDeleteArgs(&argv[i],1);
380                           Leave it there for user program to see... */
381                         CmiPrintCLAs();
382                 }
383         }
384         if (CmiMyPe()==0) { /* Throw away list of stored CLA's */
385                 CLAlistLen=CLAlistMax=0;
386                 free(CLAlist); CLAlist=NULL;
387         }
388         usageChecked=1;
389         CmiUnlock(_smp_mutex);
392 /** Return 1 if we're currently printing command-line usage information. */
393 int CmiArgGivingUsage(void) {
394         return (CmiMyPe()==0) && printUsage;
397 /** Identifies the module that accepts the following command-line parameters */
398 void CmiArgGroup(const char *parentName,const char *groupName) {
399         if (CmiArgGivingUsage()) {
400                 if (groupName==NULL) groupName=parentName; /* Start of a new group */
401                 CmiPrintf("\n%s Command-line Parameters:\n",groupName);
402         }
405 /** Count the number of non-NULL arguments in list*/
406 int CmiGetArgc(char **argv)
408         int i=0,argc=0;
409         if (argv)
410         while (argv[i++]!=NULL)
411                 argc++;
412         return argc;
415 /** Return a new, heap-allocated copy of the argv array*/
416 char **CmiCopyArgs(char **argv)
418         int argc=CmiGetArgc(argv);
419         char **ret=(char **)malloc(sizeof(char *)*(argc+1));
420         int i;
421         for (i=0;i<=argc;i++)
422                 ret[i]=argv[i];
423         return ret;
426 /** Delete the first k argument from the given list, shifting
427 all other arguments down by k spaces.
428 e.g., argv=={"a","b","c","d",NULL}, k==3 modifies
429 argv={"d",NULL,"c","d",NULL}
431 void CmiDeleteArgs(char **argv,int k)
433         int i=0;
434         while ((argv[i]=argv[i+k])!=NULL)
435                 i++;
438 /** Find the given argment and string option in argv.
439 If the argument is present, set the string option and
440 delete both from argv.  If not present, return NULL.
441 e.g., arg=="-name" returns "bob" from
442 argv=={"a.out","foo","-name","bob","bar"},
443 and sets argv={"a.out","foo","bar"};
445 int CmiGetArgStringDesc(char **argv,const char *arg,char **optDest,const char *desc)
447         int i;
448         CmiAddCLA(arg,"string",desc);
449         for (i=0;argv[i]!=NULL;i++)
450                 if (0==strcmp(argv[i],arg))
451                 {/*We found the argument*/
452                         if (argv[i+1]==NULL) CmiAbort("Argument not complete!");
453                         *optDest=argv[i+1];
454                         CmiDeleteArgs(&argv[i],2);
455                         return 1;
456                 }
457         return 0;/*Didn't find the argument*/
459 int CmiGetArgString(char **argv,const char *arg,char **optDest) {
460         return CmiGetArgStringDesc(argv,arg,optDest,"");
463 /** Find the given argument and floating-point option in argv.
464 Remove it and return 1; or return 0.
466 int CmiGetArgDoubleDesc(char **argv,const char *arg,double *optDest,const char *desc) {
467         char *number=NULL;
468         CmiAddCLA(arg,"number",desc);
469         if (!CmiGetArgStringDesc(argv,arg,&number,NULL)) return 0;
470         if (1!=sscanf(number,"%lg",optDest)) return 0;
471         return 1;
473 int CmiGetArgDouble(char **argv,const char *arg,double *optDest) {
474         return CmiGetArgDoubleDesc(argv,arg,optDest,"");
477 /** Find the given argument and integer option in argv.
478 If the argument is present, parse and set the numeric option,
479 delete both from argv, and return 1. If not present, return 0.
480 e.g., arg=="-pack" matches argv=={...,"-pack","27",...},
481 argv=={...,"-pack0xf8",...}, and argv=={...,"-pack=0777",...};
482 but not argv=={...,"-packsize",...}.
484 int CmiGetArgIntDesc(char **argv,const char *arg,int *optDest,const char *desc)
486         int i;
487         int argLen=strlen(arg);
488         CmiAddCLA(arg,"integer",desc);
489         for (i=0;argv[i]!=NULL;i++)
490                 if (0==strncmp(argv[i],arg,argLen))
491                 {/*We *may* have found the argument*/
492                         const char *opt=NULL;
493                         int nDel=0;
494                         switch(argv[i][argLen]) {
495                         case 0: /* like "-p","27" */
496                                 opt=argv[i+1]; nDel=2; break;
497                         case '=': /* like "-p=27" */
498                                 opt=&argv[i][argLen+1]; nDel=1; break;
499                         case '-':case '+':
500                         case '0':case '1':case '2':case '3':case '4':
501                         case '5':case '6':case '7':case '8':case '9':
502                                 /* like "-p27" */
503                                 opt=&argv[i][argLen]; nDel=1; break;
504                         default:
505                                 continue; /*False alarm-- skip it*/
506                         }
507                         if (opt==NULL) {
508                                 fprintf(stderr, "Command-line flag '%s' expects a numerical argument, "
509                                                 "but none was provided\n", arg);
510                                 CmiAbort("Bad command-line argument\n");
511                         }
512                         if (sscanf(opt,"%i",optDest)<1) {
513                         /*Bad command line argument-- die*/
514                                 fprintf(stderr,"Cannot parse %s option '%s' "
515                                         "as an integer.\n",arg,opt);
516                                 CmiAbort("Bad command-line argument\n");
517                         }
518                         CmiDeleteArgs(&argv[i],nDel);
519                         return 1;
520                 }
521         return 0;/*Didn't find the argument-- dest is unchanged*/
523 int CmiGetArgInt(char **argv,const char *arg,int *optDest) {
524         return CmiGetArgIntDesc(argv,arg,optDest,"");
527 int CmiGetArgLongDesc(char **argv,const char *arg,CmiInt8 *optDest,const char *desc)
529         int i;
530         int argLen=strlen(arg);
531         CmiAddCLA(arg,"integer",desc);
532         for (i=0;argv[i]!=NULL;i++)
533                 if (0==strncmp(argv[i],arg,argLen))
534                 {/*We *may* have found the argument*/
535                         const char *opt=NULL;
536                         int nDel=0;
537                         switch(argv[i][argLen]) {
538                         case 0: /* like "-p","27" */
539                                 opt=argv[i+1]; nDel=2; break;
540                         case '=': /* like "-p=27" */
541                                 opt=&argv[i][argLen+1]; nDel=1; break;
542                         case '-':case '+':
543                         case '0':case '1':case '2':case '3':case '4':
544                         case '5':case '6':case '7':case '8':case '9':
545                                 /* like "-p27" */
546                                 opt=&argv[i][argLen]; nDel=1; break;
547                         default:
548                                 continue; /*False alarm-- skip it*/
549                         }
550                         if (opt==NULL) {
551                                 fprintf(stderr, "Command-line flag '%s' expects a numerical argument, "
552                                                 "but none was provided\n", arg);
553                                 CmiAbort("Bad command-line argument\n");
554                         }
555                         if (sscanf(opt,"%" SCNd64,optDest)<1) {
556                         /*Bad command line argument-- die*/
557                                 fprintf(stderr,"Cannot parse %s option '%s' "
558                                         "as a long integer.\n",arg,opt);
559                                 CmiAbort("Bad command-line argument\n");
560                         }
561                         CmiDeleteArgs(&argv[i],nDel);
562                         return 1;
563                 }
564         return 0;/*Didn't find the argument-- dest is unchanged*/
566 int CmiGetArgLong(char **argv,const char *arg,CmiInt8 *optDest) {
567         return CmiGetArgLongDesc(argv,arg,optDest,"");
570 /** Find the given argument in argv.  If present, delete
571 it and return 1; if not present, return 0.
572 e.g., arg=="-foo" matches argv=={...,"-foo",...} but not
573 argv={...,"-foobar",...}.
575 int CmiGetArgFlagDesc(char **argv,const char *arg,const char *desc)
577         int i;
578         CmiAddCLA(arg,"",desc);
579         for (i=0;argv[i]!=NULL;i++)
580                 if (0==strcmp(argv[i],arg))
581                 {/*We found the argument*/
582                         CmiDeleteArgs(&argv[i],1);
583                         return 1;
584                 }
585         return 0;/*Didn't find the argument*/
587 int CmiGetArgFlag(char **argv,const char *arg) {
588         return CmiGetArgFlagDesc(argv,arg,"");
591 void CmiDeprecateArgInt(char **argv,const char *arg,const char *desc,const char *warning)
593   int dummy = 0, found = CmiGetArgIntDesc(argv, arg, &dummy, desc);
595   if (found)
596     CmiPrintf(warning);
599 /*****************************************************************************
601  * Stack tracing routines.
603  *****************************************************************************/
604 #include "cmibacktrace.c"
607 Convert "X(Y) Z" to "Y Z"-- remove text prior to first '(', and supress
608 the next parenthesis.  Operates in-place on the character data.
609 or Convert X(Y) to "Y" only, when trimname=1
611 static char *_implTrimParenthesis(char *str, int trimname) {
612   char *lParen=str, *ret=NULL, *rParen=NULL;
613   while (*lParen!='(') {
614     if (*lParen==0) return str; /* No left parenthesis at all. */
615     lParen++;
616   }
617   /* now *lParen=='(', so trim it*/
618   ret=lParen+1;
619   rParen=ret;
620   while (*rParen!=')') {
621     if (*rParen==0) return ret; /* No right parenthesis at all. */
622     rParen++;
623   }
624   /* now *rParen==')', so trim it*/
625   *rParen=trimname?0:' ';
626   return ret;  
630 Return the text description of this trimmed routine name, if 
631 it's a system-generated routine where we should stop printing. 
632 This is probably overkill, but improves the appearance of callbacks.
634 static const char* _implGetBacktraceSys(const char *name) {
635   if (0==strncmp(name,"_call",5)) 
636   { /*it might be something we're interested in*/
637     if (0==strncmp(name,"_call_",6)) return "Call Entry Method";
638     if (0==strncmp(name,"_callthr_",9)) return "Call Threaded Entry Method";
639   }
640   if (0==strncmp(name,"CthResume",9)) return "Resumed thread";
641   if (0==strncmp(name,"qt_args",7)) return "Converse thread";
642   
643   return 0; /*ordinary user routine-- just print normally*/
646 /** Print out the names of these function pointers. */
647 void CmiBacktracePrint(void **retPtrs,int nLevels) {
648   if (nLevels>0) {
649     int i;
650     char **names=CmiBacktraceLookup(retPtrs,nLevels);
651     if (names==NULL) return;
652     CmiPrintf("[%d] Stack Traceback:\n", CmiMyPe());
653     for (i=0;i<nLevels;i++) {
654       if (names[i] == NULL) continue;
655       {
656       const char *trimmed=_implTrimParenthesis(names[i], 0);
657       const char *print=trimmed;
658       const char *sys=_implGetBacktraceSys(print);
659       if (sys) {
660           CmiPrintf("  [%d] Charm++ Runtime: %s (%s)\n",i,sys,print);
661           break; /*Stop when we hit Charm++ runtime.*/
662       } else {
663           CmiPrintf("  [%d:%d] %s\n",CmiMyPe(),i,print);
664       }
665      }
666     }
667     free(names);
668   }
671 /* Print (to stdout) the names of the functions that have been 
672    called up to this point. nSkip is the number of routines on the
673    top of the stack to *not* print out. */
674 void CmiPrintStackTrace(int nSkip) {
675 #if CMK_USE_BACKTRACE
676         int nLevels=max_stack;
677         void *stackPtrs[max_stack];
678         CmiBacktraceRecord(stackPtrs,1+nSkip,&nLevels);
679         CmiBacktracePrint(stackPtrs,nLevels);
680 #endif
683 int CmiIsFortranLibraryCall(void) {
684 #if CMK_USE_BACKTRACE
685   int ret = 0;
686   int nLevels=9;
687   void *stackPtrs[18];
688   CmiBacktraceRecord(stackPtrs,1,&nLevels);
689   if (nLevels>0) {
690     int i;
691     char **names=CmiBacktraceLookup(stackPtrs,nLevels);
692     const char *trimmed;
693     if (names==NULL) return 0;
694     for (i=0;i<nLevels;i++) {
695       if (names[i] == NULL) continue;
696       trimmed=_implTrimParenthesis(names[i], 1);
697       if (strncmp(trimmed, "for__", 5) == 0                /* ifort */
698           || strncmp(trimmed, "_xlf", 4) == 0               /* xlf90 */
699           || strncmp(trimmed, "_xlfBeginIO", 11) == 0 
700           || strncmp(trimmed, "_gfortran_", 10) == 0 
701          )
702           {  /* CmiPrintf("[%d] NAME:%s\n", CmiMyPe(), trimmed); */
703              ret = 1; break; }
704     }
705     free(names);
706   }
707   return ret;
708 #else
709   return 0;
710 #endif
713 /*****************************************************************************
715  * Statistics: currently, the following statistics are not updated by converse.
717  *****************************************************************************/
719 CpvDeclare(int, CstatsMaxChareQueueLength);
720 CpvDeclare(int, CstatsMaxForChareQueueLength);
721 CpvDeclare(int, CstatsMaxFixedChareQueueLength);
722 CpvStaticDeclare(int, CstatPrintQueueStatsFlag);
723 CpvStaticDeclare(int, CstatPrintMemStatsFlag);
725 void CstatsInit(char ** argv)
728 #ifdef MEMMONITOR
729   CpvInitialize(mmulong,MemoryUsage);
730   CpvAccess(MemoryUsage) = 0;
731   CpvInitialize(mmulong,HiWaterMark);
732   CpvAccess(HiWaterMark) = 0;
733   CpvInitialize(mmulong,ReportedHiWaterMark);
734   CpvAccess(ReportedHiWaterMark) = 0;
735   CpvInitialize(int,AllocCount);
736   CpvAccess(AllocCount) = 0;
737   CpvInitialize(int,BlocksAllocated);
738   CpvAccess(BlocksAllocated) = 0;
739 #endif
741   CpvInitialize(int, CstatsMaxChareQueueLength);
742   CpvInitialize(int, CstatsMaxForChareQueueLength);
743   CpvInitialize(int, CstatsMaxFixedChareQueueLength);
744   CpvInitialize(int, CstatPrintQueueStatsFlag);
745   CpvInitialize(int, CstatPrintMemStatsFlag);
747   CpvAccess(CstatsMaxChareQueueLength) = 0;
748   CpvAccess(CstatsMaxForChareQueueLength) = 0;
749   CpvAccess(CstatsMaxFixedChareQueueLength) = 0;
750   CpvAccess(CstatPrintQueueStatsFlag) = 0;
751   CpvAccess(CstatPrintMemStatsFlag) = 0;
753 #if 0
754   if (CmiGetArgFlagDesc(argv,"+mems", "Print memory statistics at shutdown"))
755     CpvAccess(CstatPrintMemStatsFlag)=1;
756   if (CmiGetArgFlagDesc(argv,"+qs", "Print queue statistics at shutdown"))
757     CpvAccess(CstatPrintQueueStatsFlag)=1;
758 #endif
761 int CstatMemory(int i)
763   return 0;
766 int CstatPrintQueueStats(void)
768   return CpvAccess(CstatPrintQueueStatsFlag);
771 int CstatPrintMemStats(void)
773   return CpvAccess(CstatPrintMemStatsFlag);
776 /*****************************************************************************
778  * Cmi handler registration
780  *****************************************************************************/
782 CpvDeclare(CmiHandlerInfo*, CmiHandlerTable);
783 CpvStaticDeclare(int  , CmiHandlerCount);
784 CpvStaticDeclare(int  , CmiHandlerLocal);
785 CpvStaticDeclare(int  , CmiHandlerGlobal);
786 CpvDeclare(int,         CmiHandlerMax);
788 static void CmiExtendHandlerTable(int atLeastLen) {
789     int max = CpvAccess(CmiHandlerMax);
790     int newmax = (atLeastLen+(atLeastLen>>2)+32);
791     int bytes = max*sizeof(CmiHandlerInfo);
792     int newbytes = newmax*sizeof(CmiHandlerInfo);
793     CmiHandlerInfo *nu = (CmiHandlerInfo*)malloc(newbytes);
794     CmiHandlerInfo *tab = CpvAccess(CmiHandlerTable);
795     _MEMCHECK(nu);
796     if (tab) {
797       memcpy(nu, tab, bytes);
798     }
799     memset(((char *)nu)+bytes, 0, (newbytes-bytes));
800     free(tab); tab=nu;
801     CpvAccess(CmiHandlerTable) = tab;
802     CpvAccess(CmiHandlerMax) = newmax;
805 void CmiAssignOnce(int* variable, int value) {
806   if (CmiMyRank() == 0) { *variable = value; }
807   CmiNodeAllBarrier();
810 void CmiNumberHandler(int n, CmiHandler h)
812   CmiHandlerInfo *tab;
813   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
814   tab = CpvAccess(CmiHandlerTable);
815   tab[n].hdlr = (CmiHandlerEx)h; /* LIE!  This assumes extra pointer will be ignored!*/
816   tab[n].userPtr = 0;
818 void CmiNumberHandlerEx(int n, CmiHandlerEx h,void *userPtr) {
819   CmiHandlerInfo *tab;
820   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
821   tab = CpvAccess(CmiHandlerTable);
822   tab[n].hdlr = h;
823   tab[n].userPtr=userPtr;
826 #if CMI_LOCAL_GLOBAL_AVAILABLE /*Leave room for local and global handlers*/
827 #  define DIST_BETWEEN_HANDLERS 3
828 #else /*No local or global handlers; ordinary handlers are back-to-back*/
829 #  define DIST_BETWEEN_HANDLERS 1
830 #endif
832 int CmiRegisterHandler(CmiHandler h)
834   int Count = CpvAccess(CmiHandlerCount);
835   CmiNumberHandler(Count, h);
836   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
837   return Count;
840 void CmiRegisterHandlerAssignOnce(CmiHandler h, int *index)
842   if (CmiMyRank() == 0) { *index = CmiRegisterHandler(h); }
843   else { CmiRegisterHandler(h); }
844   CmiBarrier();
847 int CmiRegisterHandlerEx(CmiHandlerEx h,void *userPtr)
849   int Count = CpvAccess(CmiHandlerCount);
850   CmiNumberHandlerEx(Count, h, userPtr);
851   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
852   return Count;
855 void CmiRegisterHandlerExAssignOnce(CmiHandlerEx h, void *userPtr, int *index)
857   if (CmiMyRank() == 0) { *index = CmiRegisterHandlerEx(h, userPtr); }
858   else { CmiRegisterHandlerEx(h, userPtr); }
859   CmiBarrier();
862 #if CMI_LOCAL_GLOBAL_AVAILABLE
863 int CmiRegisterHandlerLocal(CmiHandler h)
865   int Local = CpvAccess(CmiHandlerLocal);
866   CmiNumberHandler(Local, h);
867   CpvAccess(CmiHandlerLocal) = Local+3;
868   return Local;
871 int CmiRegisterHandlerGlobal(CmiHandler h)
873   int Global = CpvAccess(CmiHandlerGlobal);
874   if (CmiMyPe()!=0) 
875     CmiError("CmiRegisterHandlerGlobal must only be called on PE 0.\n");
876   CmiNumberHandler(Global, h);
877   CpvAccess(CmiHandlerGlobal) = Global+3;
878   return Global;
880 #endif
882 static void _cmiZeroHandler(void *msg) {
883         CmiAbort("Converse zero handler executed-- was a message corrupted?\n");
886 static void CmiHandlerInit(void)
888   CpvInitialize(CmiHandlerInfo *, CmiHandlerTable);
889   CpvInitialize(int         , CmiHandlerCount);
890   CpvInitialize(int         , CmiHandlerLocal);
891   CpvInitialize(int         , CmiHandlerGlobal);
892   CpvInitialize(int         , CmiHandlerMax);
893   CpvAccess(CmiHandlerCount)  = 0;
894   CpvAccess(CmiHandlerLocal)  = 1;
895   CpvAccess(CmiHandlerGlobal) = 2;
896   CpvAccess(CmiHandlerMax) = 0; /* Table will be extended on the first registration*/
897   CpvAccess(CmiHandlerTable) = NULL;
898   CmiRegisterHandler((CmiHandler)_cmiZeroHandler);
902 /******************************************************************************
904  * CmiTimer
906  * Here are two possible implementations of CmiTimer.  Some machines don't
907  * select either, and define the timer in machine.C instead.
909  *****************************************************************************/
911 #if CMK_HAS_ASCTIME
913 char *CmiPrintDate(void)
915   struct tm *local;
916   time_t t;
918   t = time(NULL);
919   local = localtime(&t);
920   return asctime(local);
923 #else
925 char *CmiPrintDate(void)
927   return "N/A";
930 #endif
932 static int _absoluteTime = 0;
934 #if CMK_TIMER_USE_TIMES
936 CpvStaticDeclare(double, clocktick);
937 CpvStaticDeclare(int,inittime_wallclock);
938 CpvStaticDeclare(int,inittime_virtual);
940 int CmiTimerIsSynchronized(void)
942   return 0;
945 int CmiTimerAbsolute(void)
947   return 0;
950 double CmiStartTimer(void)
952   return 0.0;
955 double CmiInitTime(void)
957   return CpvAccess(inittime_wallclock);
960 void CmiTimerInit(char **argv)
962   struct tms temp;
963   CpvInitialize(double, clocktick);
964   CpvInitialize(int, inittime_wallclock);
965   CpvInitialize(int, inittime_virtual);
966   CpvAccess(inittime_wallclock) = times(&temp);
967   CpvAccess(inittime_virtual) = temp.tms_utime + temp.tms_stime;
968   CpvAccess(clocktick) = 1.0 / (sysconf(_SC_CLK_TCK));
971 double CmiWallTimer(void)
973   struct tms temp;
974   double currenttime;
975   int now;
977   now = times(&temp);
978   currenttime = (now - CpvAccess(inittime_wallclock)) * CpvAccess(clocktick);
979   return (currenttime);
982 double CmiCpuTimer(void)
984   struct tms temp;
985   double currenttime;
986   int now;
988   times(&temp);
989   now = temp.tms_stime + temp.tms_utime;
990   currenttime = (now - CpvAccess(inittime_virtual)) * CpvAccess(clocktick);
991   return (currenttime);
994 double CmiTimer(void)
996   return CmiCpuTimer();
999 #endif
1001 #if CMK_TIMER_USE_GETRUSAGE
1003 #if CMK_SMP
1004 # if CMK_HAS_RUSAGE_THREAD
1005 #define RUSAGE_WHO        1   /* RUSAGE_THREAD, only in latest Linux kernels */
1006 #else
1007 #undef RUSAGE_WHO
1008 #endif
1009 #else
1010 #define RUSAGE_WHO        0
1011 #endif
1013 static double inittime_wallclock;
1014 CpvStaticDeclare(double, inittime_virtual);
1016 int CmiTimerIsSynchronized(void)
1018   return 0;
1021 int CmiTimerAbsolute(void)
1023   return _absoluteTime;
1026 double CmiStartTimer(void)
1028   return 0.0;
1031 double CmiInitTime(void)
1033   return inittime_wallclock;
1036 void CmiTimerInit(char **argv)
1038   struct rusage ru;
1039   CpvInitialize(double, inittime_virtual);
1041   int tmptime = CmiGetArgFlagDesc(argv,"+useAbsoluteTime", "Use system's absolute time as wallclock time.");
1042   if(CmiMyRank() == 0) _absoluteTime = tmptime;   /* initialize only  once */
1043 #if !(__FAULT__)
1044   /* try to synchronize calling barrier */
1045   CmiBarrier();
1046   CmiBarrier();
1047   CmiBarrier();
1048 #endif
1049 if(CmiMyRank() == 0) /* initialize only  once */
1050   {
1051     inittime_wallclock = inithrc();
1052 #ifndef RUSAGE_WHO
1053     CpvAccess(inittime_virtual) = inittime_wallclock;
1054 #else
1055     getrusage(RUSAGE_WHO, &ru); 
1056     CpvAccess(inittime_virtual) =
1057       (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1058       (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1059 #endif
1060   }
1062 #if !(__FAULT__)
1063   CmiBarrier();
1064 /*  CmiBarrierZero(); */
1065 #endif
1068 double CmiCpuTimer(void)
1070 #ifndef RUSAGE_WHO
1071   return CmiWallTimer();
1072 #else
1073   struct rusage ru;
1074   double currenttime;
1076   getrusage(RUSAGE_WHO, &ru);
1077   currenttime =
1078     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1079     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1080   
1081   return currenttime - CpvAccess(inittime_virtual);
1082 #endif
1085 static double lastT = -1.0;
1087 double CmiWallTimer(void)
1089   double currenttime;
1090   currenttime = gethrctime();
1091   return _absoluteTime?currenttime+inittime_wallclock:currenttime;
1094 double CmiTimer(void)
1096   return CmiCpuTimer();
1099 #endif
1101 #if CMK_TIMER_USE_RDTSC
1103 static double readMHz(void)
1105   double x;
1106   char str[1000];
1107   char buf[100];
1108   FILE *fp;
1109   CmiLock(_smp_mutex);
1110   fp = fopen("/proc/cpuinfo", "r");
1111   if (fp != NULL)
1112   while(fgets(str, 1000, fp)!=0) {
1113     if(sscanf(str, "cpu MHz%[^:]",buf)==1)
1114     {
1115       char *s = strchr(str, ':'); s=s+1;
1116       sscanf(s, "%lf", &x);
1117       fclose(fp);
1118       CmiUnlock(_smp_mutex);
1119       return x;
1120     }
1121   }
1122   CmiUnlock(_smp_mutex);
1123   CmiAbort("Cannot read CPU MHz from /proc/cpuinfo file.");
1124   return 0.0;
1127 double _cpu_speed_factor;
1128 CpvStaticDeclare(double, inittime_virtual);
1129 CpvStaticDeclare(double, inittime_walltime);
1131 double  CmiStartTimer(void)
1133   return CpvAccess(inittime_walltime);
1136 double CmiInitTime(void)
1138   return CpvAccess(inittime_walltime);
1141 void CmiTimerInit(char **argv)
1143   struct rusage ru;
1145   CmiBarrier();
1146   CmiBarrier();
1148   _cpu_speed_factor = 1.0/(readMHz()*1.0e6); 
1149   rdtsc(); rdtsc(); rdtsc(); rdtsc(); rdtsc();
1150   CpvInitialize(double, inittime_walltime);
1151   CpvAccess(inittime_walltime) = CmiWallTimer();
1152   CpvInitialize(double, inittime_virtual);
1153   getrusage(0, &ru); 
1154   CpvAccess(inittime_virtual) =
1155     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1156     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1158   CmiBarrierZero();
1161 double CmiCpuTimer(void)
1163   struct rusage ru;
1164   double currenttime;
1166   getrusage(0, &ru);
1167   currenttime =
1168     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1169     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1170   return currenttime - CpvAccess(inittime_virtual);
1173 #endif
1175 #if CMK_TIMER_USE_BLUEGENEQ  /* This module just compiles with GCC charm. */
1177 CpvStaticDeclare(unsigned long, inittime);
1178 CpvStaticDeclare(double, clocktick);
1180 int CmiTimerIsSynchronized(void)
1182   return 1;
1185 int CmiTimerAbsolute(void)
1187   return 0;
1190 #include "hwi/include/bqc/A2_inlines.h"
1191 #include "spi/include/kernel/process.h"
1193 double CmiStartTimer(void)
1195   return 0.0;
1198 double CmiInitTime(void)
1200   return CpvAccess(inittime);
1203 void CmiTimerInit(char **argv)
1205   CpvInitialize(double, clocktick);
1206   CpvInitialize(unsigned long, inittime);
1208   Personality_t  pers;
1209   Kernel_GetPersonality(&pers, sizeof(pers));
1210   uint32_t clockMhz = pers.Kernel_Config.FreqMHz;
1211   CpvAccess(clocktick) = 1.0 / (clockMhz * 1e6); 
1213   /*fprintf(stderr, "Blue Gene/Q running at clock speed of %d Mhz\n", clockMhz);*/
1215   /* try to synchronize calling barrier */
1216 #if !(__FAULT__)
1217   CmiBarrier();
1218   CmiBarrier();
1219   CmiBarrier();
1220 #endif
1221   CpvAccess(inittime) = GetTimeBase (); 
1224 double CmiWallTimer(void)
1226   unsigned long long currenttime;
1227   currenttime = GetTimeBase();
1228   return CpvAccess(clocktick)*(currenttime-CpvAccess(inittime));
1231 double CmiCpuTimer(void)
1233   return CmiWallTimer();
1236 double CmiTimer(void)
1238   return CmiWallTimer();
1241 #endif
1244 #if CMK_TIMER_USE_PPC64
1246 #include <sys/time.h>
1247 #include <sys/time.h>
1248 #include <sys/platform/ppc.h>
1250 CpvStaticDeclare(uint64_t, inittime);
1251 CpvStaticDeclare(double, clocktick);
1253 int CmiTimerIsSynchronized(void)
1255   return 1;
1258 int CmiTimerAbsolute(void)
1260   return 0;
1263 double CmiStartTimer(void)
1265   return 0.0;
1268 double CmiInitTime(void)
1270   return CpvAccess(inittime);
1273 static inline uint64_t PPC64_TimeBase(void)
1275   register volatile uint64_t result;
1277   /* For 64-bit only */
1278   asm volatile (
1279             "   isync    \n\t"
1280             "   mftb  %0 \n\t"
1281             "   isync    \n\t"
1282             : "=r"(result));
1284   return result;
1287 uint64_t __micro_timer (void)
1289   return gethrctime_micro();
1292 void CmiTimerInit(char **argv)
1294   CpvInitialize(double, clocktick);
1295   CpvInitialize(unsigned long, inittime);
1296   CpvAccess(clocktick) =  1.0 / ((double) __ppc_get_timebase_freq());
1298   /* try to synchronize calling barrier */
1299 #if !(__FAULT__)
1300   CmiBarrier();
1301   CmiBarrier();
1302   CmiBarrier();
1303 #endif
1304   CpvAccess(inittime) = PPC64_TimeBase ();
1307 double CmiWallTimer(void)
1309   uint64_t currenttime;
1310   currenttime = PPC64_TimeBase();
1311   return CpvAccess(clocktick)*(currenttime-CpvAccess(inittime));
1314 double CmiCpuTimer(void)
1316   return CmiWallTimer();
1319 double CmiTimer(void)
1321   return CmiWallTimer();
1324 #endif
1327 #if CMK_TIMER_USE_WIN32API
1329 CpvStaticDeclare(double, inittime_wallclock);
1330 CpvStaticDeclare(double, inittime_virtual);
1332 double CmiStartTimer(void)
1334   return 0.0;
1337 int CmiTimerAbsolute(void)
1339   return 0;
1342 double CmiInitTime(void)
1344   return CpvAccess(inittime_wallclock);
1347 void CmiTimerInit(char **argv)
1349         struct timeb tv;
1350         clock_t       ru;
1352         CpvInitialize(double, inittime_wallclock);
1353         CpvInitialize(double, inittime_virtual);
1354         ftime(&tv);
1355         CpvAccess(inittime_wallclock) = tv.time*1.0 + tv.millitm*0.001;
1356         ru = clock();
1357         CpvAccess(inittime_virtual) = ((double) ru)/CLOCKS_PER_SEC;
1360 double CmiCpuTimer(void)
1362         clock_t ru;
1363         double currenttime;
1365         ru = clock();
1366         currenttime = (double) ru/CLOCKS_PER_SEC;
1368         return currenttime - CpvAccess(inittime_virtual);
1371 double CmiWallTimer(void)
1373         struct timeb tv;
1374         double currenttime;
1376         ftime(&tv);
1377         currenttime = tv.time*1.0 + tv.millitm*0.001;
1379         return currenttime - CpvAccess(inittime_wallclock);
1381         
1383 double CmiTimer(void)
1385         return CmiCpuTimer();
1388 #endif
1390 #if CMK_TIMER_USE_RTC
1392 static double clocktick;
1393 CpvStaticDeclare(long long, inittime_wallclock);
1395 double CmiStartTimer(void)
1397   return 0.0;
1400 double CmiInitTime(void)
1402   return CpvAccess(inittime_wallclock);
1405 void CmiTimerInit(char **argv)
1407   CpvInitialize(long long, inittime_wallclock);
1408   CpvAccess(inittime_wallclock) = _rtc();
1409   clocktick = 1.0 / (double)(sysconf(_SC_SV2_USER_TIME_RATE));
1412 int CmiTimerAbsolute(void)
1414   return 0;
1417 double CmiWallTimer(void)
1419   long long now;
1421   now = _rtc();
1422   return (clocktick * (now - CpvAccess(inittime_wallclock)));
1425 double CmiCpuTimer(void)
1427   return CmiWallTimer();
1430 double CmiTimer(void)
1432   return CmiCpuTimer();
1435 #endif
1437 #if CMK_TIMER_USE_AIX_READ_TIME
1439 #include <sys/time.h>
1441 static timebasestruct_t inittime_wallclock;
1442 static double clocktick;
1443 CpvStaticDeclare(double, inittime_virtual);
1445 double CmiStartTimer(void)
1447   return 0.0;
1450 double CmiInitTime(void)
1452   return inittime_wallclock;
1455 void CmiTimerInit(char **argv)
1457   struct rusage ru;
1459   if (CmiMyRank() == 0) {
1460     read_wall_time(&inittime_wallclock, TIMEBASE_SZ);
1461     time_base_to_time(&inittime_wallclock, TIMEBASE_SZ);
1462   }
1464   CpvInitialize(double, inittime_virtual);
1465   getrusage(0, &ru);
1466   CpvAccess(inittime_virtual) =
1467     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1468     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1471 int CmiTimerAbsolute(void)
1473   return 0;
1476 double CmiWallTimer(void)
1478   int secs, n_secs;
1479   double curt;
1480   timebasestruct_t now;
1481   read_wall_time(&now, TIMEBASE_SZ);
1482   time_base_to_time(&now, TIMEBASE_SZ);
1484   secs = now.tb_high - inittime_wallclock.tb_high;
1485   n_secs = now.tb_low - inittime_wallclock.tb_low;
1486   if (n_secs < 0)  {
1487     secs--;
1488     n_secs += 1000000000;
1489   }
1490   curt = secs*1.0 + n_secs*1e-9;
1491   return curt;
1494 double CmiCpuTimer(void)
1496   struct rusage ru;
1497   double currenttime;
1499   getrusage(0, &ru);
1500   currenttime =
1501     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1502     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1503   return currenttime - CpvAccess(inittime_virtual);
1506 double CmiTimer(void)
1508   return CmiWallTimer();
1511 #endif
1513 #ifndef CMK_USE_SPECIAL_MESSAGE_QUEUE_CHECK
1514 /** Return 1 if our outgoing message queue 
1515    for this node is longer than this many bytes. */
1516 int CmiLongSendQueue(int forNode,int longerThanBytes) {
1517   return 0;
1519 #endif
1521 #if CMK_SIGNAL_USE_SIGACTION
1522 #include <signal.h>
1523 CMI_EXTERNC
1524 void CmiSignal(int sig1, int sig2, int sig3, void (*handler)(int))
1526   struct sigaction in, out ;
1527   in.sa_handler = handler;
1528   sigemptyset(&in.sa_mask);
1529   if (sig1) sigaddset(&in.sa_mask, sig1);
1530   if (sig2) sigaddset(&in.sa_mask, sig2);
1531   if (sig3) sigaddset(&in.sa_mask, sig3);
1532   in.sa_flags = 0;
1533   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1534   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1535   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1537 #endif
1539 #if CMK_SIGNAL_USE_SIGACTION_WITH_RESTART
1540 #include <signal.h>
1541 CMI_EXTERNC
1542 void CmiSignal(int sig1, int sig2, int sig3, void (*handler)(int))
1544   struct sigaction in, out ;
1545   in.sa_handler = handler;
1546   sigemptyset(&in.sa_mask);
1547   if (sig1) sigaddset(&in.sa_mask, sig1);
1548   if (sig2) sigaddset(&in.sa_mask, sig2);
1549   if (sig3) sigaddset(&in.sa_mask, sig3);
1550   in.sa_flags = SA_RESTART;
1551   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1552   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1553   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1555 #endif
1557 /** 
1558  *  @addtogroup ConverseScheduler
1559  *  @{
1560  */
1562 /*****************************************************************************
1563  * 
1564  * The following is the CsdScheduler function.  A common
1565  * implementation is provided below.  The machine layer can provide an
1566  * alternate implementation if it so desires.
1568  * void CmiDeliversInit()
1570  *      - CmiInit promises to call this before calling CmiDeliverMsgs
1571  *        or any of the other functions in this section.
1573  * int CmiDeliverMsgs(int maxmsgs)
1575  *      - CmiDeliverMsgs will retrieve up to maxmsgs that were transmitted
1576  *        with the Cmi, and will invoke their handlers.  It does not wait
1577  *        if no message is unavailable.  Instead, it returns the quantity
1578  *        (maxmsgs-delivered), where delivered is the number of messages it
1579  *        delivered.
1581  * void CmiDeliverSpecificMsg(int handlerno)
1583  *      - Waits for a message with the specified handler to show up, then
1584  *        invokes the message's handler.  Note that unlike CmiDeliverMsgs,
1585  *        This function _does_ wait.
1587  * For this common implementation to work, the machine layer must provide the
1588  * following:
1590  * void *CmiGetNonLocal()
1592  *      - returns a message just retrieved from some other PE, not from
1593  *        local.  If no such message exists, returns 0.
1595  * CpvExtern(CdsFifo, CmiLocalQueue);
1597  *      - a FIFO queue containing all messages from the local processor.
1599  *****************************************************************************/
1601 void CsdBeginIdle(void)
1603   CcdCallBacks();
1604 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1605   _LOG_E_PROC_IDLE();   /* projector */
1606 #endif
1607 #if CMK_SMP && CMK_TASKQUEUE
1608   if (CpvAccess(cmiMyPeIdle) !=1) {
1609     CpvAccess(cmiMyPeIdle) = 1;
1610     CmiMemoryAtomicIncrement(CsvAccess(idleThreadsCnt), memory_order_relaxed);
1611   }
1612 #else
1613   CpvAccess(cmiMyPeIdle) = 1;
1614 #endif // CMK_SMP
1615   CcdRaiseCondition(CcdPROCESSOR_BEGIN_IDLE) ;
1618 void CsdStillIdle(void)
1620   CcdRaiseCondition(CcdPROCESSOR_STILL_IDLE);
1623 void CsdEndIdle(void)
1625 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1626   _LOG_E_PROC_BUSY();   /* projector */
1627 #endif
1628 #if CMK_SMP && CMK_TASKQUEUE
1629   if (CpvAccess(cmiMyPeIdle) != 0){
1630     CpvAccess(cmiMyPeIdle) = 0;
1631     CmiMemoryAtomicDecrement(CsvAccess(idleThreadsCnt), memory_order_relaxed);
1632   }
1633 #else
1634   CpvAccess(cmiMyPeIdle) = 0;
1635 #endif // CMK_SMP
1636   CcdRaiseCondition(CcdPROCESSOR_BEGIN_BUSY) ;
1639 extern int _exitHandlerIdx;
1641 /** Takes a message and calls its corresponding handler. */
1642 void CmiHandleMessage(void *msg)
1644 /* this is wrong because it counts the Charm++ messages in sched queue
1645         CpvAccess(cQdState)->mProcessed++;
1647         CmiHandlerInfo *h;
1648         CmiUInt2 handlerIdx=CmiGetHandler(msg); /* Save handler for use after msg is gone */
1649 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1650         _LOG_E_HANDLER_BEGIN(handlerIdx); /* projector */
1651         /* setMemoryStatus(1) */ /* charmdebug */
1652 #endif
1655         CMK_FAULT_EVAC
1657 /*      if((!CpvAccess(_validProcessors)[CmiMyPe()]) && handler != _exitHandlerIdx){
1658                 return;
1659         }*/
1660         
1661         MESSAGE_PHASE_CHECK(msg)
1662 #if CMK_ERROR_CHECKING
1663         if (handlerIdx >= CpvAccess(CmiHandlerCount)) {
1664           CmiAbort("Msg handler does not exist, possible race condition during init\n");
1665         }
1666 #endif
1667         h=&CmiHandlerToInfo(handlerIdx);
1668 #if CMK_ERROR_CHECKING
1669         if (h->hdlr == NULL) {
1670           CmiAbort("Msg handler does not exist, possible race condition during init\n");
1671         }
1672 #endif
1673         (h->hdlr)(msg,h->userPtr);
1674 #if CMK_TRACE_ENABLED
1675         /* setMemoryStatus(0) */ /* charmdebug */
1676         //_LOG_E_HANDLER_END(handlerIdx);       /* projector */
1677 #endif
1680 #if CMK_CMIDELIVERS_USE_COMMON_CODE
1682 void CmiDeliversInit(void)
1686 int CmiDeliverMsgs(int maxmsgs)
1688   return CsdScheduler(maxmsgs);
1691 #if CMK_OBJECT_QUEUE_AVAILABLE
1692 CpvDeclare(void *, CsdObjQueue);
1693 #endif
1695 void CsdSchedulerState_new(CsdSchedulerState_t *s)
1697 #if CMK_OBJECT_QUEUE_AVAILABLE
1698         s->objQ=CpvAccess(CsdObjQueue);
1699 #endif
1700         s->localQ=CpvAccess(CmiLocalQueue);
1701         s->schedQ=CpvAccess(CsdSchedQueue);
1702         s->localCounter=&(CpvAccess(CsdLocalCounter));
1703 #if CMK_NODE_QUEUE_AVAILABLE
1704         s->nodeQ=CsvAccess(CsdNodeQueue);
1705         s->nodeLock=CsvAccess(CsdNodeQueueLock);
1706 #endif
1707 #if CMK_GRID_QUEUE_AVAILABLE
1708         s->gridQ=CpvAccess(CsdGridQueue);
1709 #endif
1710 #if CMK_SMP && CMK_TASKQUEUE
1711         s->taskQ = CpvAccess(CsdTaskQueue);
1712         s->suspendedTaskQ = CpvAccess(CmiSuspendedTaskQueue);
1713 #endif
1717 /** Dequeue and return the next message from the unprocessed message queues.
1719  * This function encapsulates the multiple queues that exist for holding unprocessed
1720  * messages and the rules for the order in which to check them. There are five (5)
1721  * different Qs that converse uses to store and retrieve unprocessed messages. These
1722  * are:
1723  *     Q Purpose                  Type      internal DeQ logic
1724  * -----------------------------------------------------------
1725  * - PE offnode                   pcQ             FIFO
1726  * - PE onnode                    CkQ             FIFO
1727  * - Node offnode                 pcQ             FIFO
1728  * - Node onnode                  prioQ           prio-based
1729  * - Scheduler                    prioQ           prio-based
1731  * The PE queues hold messages that are destined for a specific PE. There is one such
1732  * queue for every PE within a charm node. The node queues hold messages that are
1733  * destined to that node. There is only one of each node queue within a charm node.
1734  * Finally there is also a charm++ message queue for each PE.
1736  * The offnode queues are meant for holding messages that arrive from outside the
1737  * node. The onnode queues hold messages that are generated within the same charm
1738  * node.
1740  * The PE and node level offnode queues are accessed via functions CmiGetNonLocal()
1741  * and CmiGetNonLocalNodeQ(). These are implemented separately by each machine layer
1742  * and hide the implementation specifics for each layer.
1744  * The PE onnode queue is implemented as a FIFO CkQ and is initialized via a call to
1745  * CdsFifo_Create(). The node local queue and the scheduler queue are both priority
1746  * queues. They are initialized via calls to CqsCreate() which gives each of them
1747  * three separate internal queues for different priority ranges (-ve, 0 and +ve).
1748  * Access to these queues is via pointers stored in the struct CsdSchedulerState that
1749  * is passed into this function.
1751  * The order in which these queues are checked is described below. The function
1752  * proceeds to the next queue in the list only if it does not find any messages in
1753  * the current queue. The first message that is found is returned, terminating the
1754  * call.
1755  * (1) offnode queue for this PE
1756  * (2) onnode queue for this PE
1757  * (3) offnode queue for this node
1758  * (4) highest priority msg from onnode queue or scheduler queue
1760  * @note: Across most (all?) machine layers, the two GetNonLocal functions simply
1761  * access (after observing adequate locking rigor) structs representing the scheduler
1762  * state, to dequeue from the queues stored within them. The structs (CmiStateStruct
1763  * and CmiNodeStateStruct) implement these queues as \ref Machine "pc (producer-consumer)
1764  * queues". The functions also perform other necessary actions like PumpMsgs() etc.
1766  */
1767 void *CsdNextMessage(CsdSchedulerState_t *s) {
1768         void *msg;
1769         if((*(s->localCounter))-- >0)
1770           {
1771               /* This avoids a race condition with migration detected by megatest*/
1772               msg=CdsFifo_Dequeue(s->localQ);
1773               if (msg!=NULL)
1774                 {
1775 #if CMI_QD
1776                   CpvAccess(cQdState)->mProcessed++;
1777 #endif
1778                   return msg;       
1779                 }
1780               CqsDequeue(s->schedQ,(void **)&msg);
1781               if (msg!=NULL) return msg;
1782           }
1783         
1784         *(s->localCounter)=CsdLocalMax;
1785         if ( NULL!=(msg=CmiGetNonLocal()) || 
1786              NULL!=(msg=CdsFifo_Dequeue(s->localQ)) ) {
1787 #if CMI_QD
1788             CpvAccess(cQdState)->mProcessed++;
1789 #endif
1790             return msg;
1791         }
1792 #if CMK_GRID_QUEUE_AVAILABLE
1793         /*#warning "CsdNextMessage: CMK_GRID_QUEUE_AVAILABLE" */
1794         CqsDequeue (s->gridQ, (void **) &msg);
1795         if (msg != NULL) {
1796           return (msg);
1797         }
1798 #endif
1799 #if CMK_SMP && CMK_TASKQUEUE
1800 #if CMK_OMP
1801         msg = CmiSuspendedTaskPop();
1802         if (msg != NULL) {
1803           return (msg);
1804         }
1805 #endif
1806         msg = TaskQueuePop((TaskQueue)s->taskQ);
1807         if (msg != NULL) {
1808           return (msg);
1809         }
1810 #endif
1811 #if CMK_NODE_QUEUE_AVAILABLE
1812         /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1813         if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;
1814 #if !CMK_NO_MSG_PRIOS
1815         if (!CqsEmpty(s->nodeQ)
1816          && CqsPrioGT(CqsGetPriority(s->schedQ),
1817                        CqsGetPriority(s->nodeQ))) {
1818           if(CmiTryLock(s->nodeLock) == 0) {
1819             CqsDequeue(s->nodeQ,(void **)&msg);
1820             CmiUnlock(s->nodeLock);
1821             if (msg!=NULL) return msg;
1822           }
1823         }
1824 #endif
1825 #endif
1826 #if CMK_OBJECT_QUEUE_AVAILABLE
1827         /*#warning "CsdNextMessage: CMK_OBJECT_QUEUE_AVAILABLE"   */
1828         if (NULL!=(msg=CdsFifo_Dequeue(s->objQ))) {
1829           return msg;
1830         }
1831 #endif
1832         if(!CsdLocalMax) {
1833           CqsDequeue(s->schedQ,(void **)&msg);
1834           if (msg!=NULL) return msg;        
1835         }
1836         return NULL;
1840 void *CsdNextLocalNodeMessage(CsdSchedulerState_t *s) {
1841         void *msg;
1842 #if CMK_NODE_QUEUE_AVAILABLE
1843         /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1844         /*if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;*/
1845         if (!CqsEmpty(s->nodeQ))
1846         {
1847           CmiLock(s->nodeLock);
1848           CqsDequeue(s->nodeQ,(void **)&msg);
1849           CmiUnlock(s->nodeLock);
1850           if (msg!=NULL) return msg;
1851         }
1852 #endif
1853         return NULL;
1857 int CsdScheduler(int maxmsgs)
1859         if (maxmsgs<0) CsdScheduleForever();    
1860         else if (maxmsgs==0)
1861                 CsdSchedulePoll();
1862         else /*(maxmsgs>0)*/ 
1863                 return CsdScheduleCount(maxmsgs);
1864         return 0;
1867 /*Declare the standard scheduler housekeeping*/
1868 #define SCHEDULE_TOP \
1869       void *msg;\
1870       int *CsdStopFlag_ptr = &CpvAccess(CsdStopFlag); \
1871       int cycle = CpvAccess(CsdStopFlag); \
1872       CsdSchedulerState_t state;\
1873       CsdSchedulerState_new(&state);
1875 /*A message is available-- process it*/
1876 #define SCHEDULE_MESSAGE \
1877       CmiHandleMessage(msg);\
1878       if (*CsdStopFlag_ptr != cycle) break;
1880 /*No message available-- go (or remain) idle*/
1881 #if CSD_NO_IDLE_TRACING
1882 #define SCHEDULE_IDLE /* do nothing */
1883 #else
1884 #define SCHEDULE_IDLE \
1885       if (!isIdle) {isIdle=1;CsdBeginIdle();}\
1886       else CsdStillIdle();\
1887       if (*CsdStopFlag_ptr != cycle) {\
1888         CsdEndIdle();\
1889         break;\
1890       }
1891 #endif
1894         EVAC
1896 extern void CkClearAllArrayElements(void);
1899 extern void machine_OffloadAPIProgress(void);
1901 /** The main scheduler loop that repeatedly executes messages from a queue, forever. */
1902 void CsdScheduleForever(void)
1904   #if CMK_CELL
1905     #define CMK_CELL_PROGRESS_FREQ  96  /* (MSG-Q Entries x1.5) */
1906     int progressCount = CMK_CELL_PROGRESS_FREQ;
1907   #endif
1909   int isIdle=0;
1910   SCHEDULE_TOP
1911   while (1) {
1912 #if !CMK_NO_INTEROP
1913     /* The interoperation will cost this little overhead in scheduling */
1914     if(CharmLibInterOperate) {
1915       if(CpvAccess(interopExitFlag)) {
1916         CpvAccess(interopExitFlag) = 0;
1917         break;
1918       }
1919     }
1920 #endif
1921     #if CMK_CUDA
1922     // check if any GPU work needs to be processed
1923     if (CpvAccess(n_hapi_events) > 0) {
1924       hapiPollEvents();
1925     }
1926     #endif
1927     msg = CsdNextMessage(&state);
1928     if (msg!=NULL) { /*A message is available-- process it*/
1929 #if !CSD_NO_IDLE_TRACING
1930       if (isIdle) {isIdle=0;CsdEndIdle();}
1931 #endif
1932       SCHEDULE_MESSAGE
1934       #if CMK_CELL
1935         if (progressCount <= 0) {
1936           /*OffloadAPIProgress();*/
1937           machine_OffloadAPIProgress();
1938           progressCount = CMK_CELL_PROGRESS_FREQ;
1939         }
1940         progressCount--;
1941       #endif
1942     } else { /*No message available-- go (or remain) idle*/
1943       SCHEDULE_IDLE
1945       #if CMK_CELL
1946         /*OffloadAPIProgress();*/
1947         machine_OffloadAPIProgress();
1948         progressCount = CMK_CELL_PROGRESS_FREQ;
1949       #endif
1950     }
1951 #if !CSD_NO_PERIODIC
1952     CsdPeriodic();
1953 #endif
1954   }
1956 int CsdScheduleCount(int maxmsgs)
1958   int isIdle=0;
1959   SCHEDULE_TOP
1960   while (1) {
1961     msg = CsdNextMessage(&state);
1962     if (msg!=NULL) { /*A message is available-- process it*/
1963 #if !CSD_NO_IDLE_TRACING
1964       if (isIdle) {isIdle=0;CsdEndIdle();}
1965 #endif
1966       maxmsgs--; 
1967       SCHEDULE_MESSAGE
1968       if (maxmsgs==0) break;
1969     } else { /*No message available-- go (or remain) idle*/
1970       SCHEDULE_IDLE
1971     }
1972 #if !CSD_NO_PERIODIC
1973     CsdPeriodic();
1974 #endif
1975   }
1976   return maxmsgs;
1979 void CsdSchedulePoll(void)
1981   SCHEDULE_TOP
1982   while (1)
1983   {
1984 #if !CSD_NO_PERIODIC
1985         CsdPeriodic();
1986 #endif
1987         /*CmiMachineProgressImpl(); ??? */
1988         if (NULL!=(msg = CsdNextMessage(&state)))
1989         {
1990              SCHEDULE_MESSAGE 
1991         }
1992         else break;
1993   }
1996 void CsdScheduleNodePoll(void)
1998   SCHEDULE_TOP
1999   while (1)
2000   {
2001         /*CsdPeriodic();*/
2002         /*CmiMachineProgressImpl(); ??? */
2003         if (NULL!=(msg = CsdNextLocalNodeMessage(&state)))
2004         {
2005              SCHEDULE_MESSAGE 
2006         }
2007         else break;
2008   }
2011 void CmiDeliverSpecificMsg(int handler)
2013   int *msg; int side;
2014   void *localqueue = CpvAccess(CmiLocalQueue);
2016   side = 0;
2017   while (1) {
2018 #if !CSD_NO_PERIODIC
2019     CsdPeriodic();
2020 #endif
2021     side ^= 1;
2022     if (side) msg = (int *)CmiGetNonLocal();
2023     else      msg = (int *)CdsFifo_Dequeue(localqueue);
2024     if (msg) {
2025       if (CmiGetHandler(msg)==handler) {
2026 #if CMI_QD
2027         CpvAccess(cQdState)->mProcessed++;
2028 #endif
2029         CmiHandleMessage(msg);
2030         return;
2031       } else {
2032         CdsFifo_Enqueue(localqueue, msg);
2033       }
2034     }
2035   }
2038 #endif /* CMK_CMIDELIVERS_USE_COMMON_CODE */
2040 /***************************************************************************
2042  * Standin Schedulers.
2044  * We use the following strategy to make sure somebody's always running
2045  * the scheduler (CsdScheduler).  Initially, we assume the main thread
2046  * is responsible for this.  If the main thread blocks, we create a
2047  * "standin scheduler" thread to replace it.  If the standin scheduler
2048  * blocks, we create another standin scheduler to replace that one,
2049  * ad infinitum.  Collectively, the main thread and all the standin
2050  * schedulers are called "scheduling threads".
2052  * Suppose the main thread is blocked waiting for data, and a standin
2053  * scheduler is running instead.  Suppose, then, that the data shows
2054  * up and the main thread is CthAwakened.  This causes a token to be
2055  * pushed into the queue.  When the standin pulls the token from the
2056  * queue and handles it, the standin goes to sleep, and control shifts
2057  * back to the main thread.  In this way, unnecessary standins are put
2058  * back to sleep.  These sleeping standins are stored on the
2059  * CthSleepingStandins list.
2061  ***************************************************************************/
2063 CpvStaticDeclare(CthThread, CthMainThread);
2064 CpvStaticDeclare(CthThread, CthSchedulingThread);
2065 CpvStaticDeclare(CthThread, CthSleepingStandins);
2066 CpvDeclare(int      , CthResumeNormalThreadIdx);
2067 CpvStaticDeclare(int      , CthResumeSchedulingThreadIdx);
2069 #if CMK_OMP
2070 CpvDeclare (int, CthResumeStealableThreadIdx);
2071 CpvDeclare (int, CthResumeSuspendedStealableThreadIdx);
2072 #endif
2074 void CthStandinCode(void *arg)
2076   CsdScheduler(-1);
2079 /* this fix the function pointer for thread migration and pup */
2080 static CthThread CthSuspendNormalThread(void)
2082   return CpvAccess(CthSchedulingThread);
2085 void CthEnqueueSchedulingThread(CthThreadToken *token, int, int, unsigned int*);
2086 CthThread CthSuspendSchedulingThread(void);
2088 CthThread CthSuspendSchedulingThread(void)
2090   CthThread succ = CpvAccess(CthSleepingStandins);
2092   if (succ) {
2093     CpvAccess(CthSleepingStandins) = CthGetNext(succ);
2094   } else {
2095     succ = CthCreate(CthStandinCode, 0, 256000);
2096     CthSetStrategy(succ,
2097                    CthEnqueueSchedulingThread,
2098                    CthSuspendSchedulingThread);
2099   }
2100   
2101   CpvAccess(CthSchedulingThread) = succ;
2102   return succ;
2105 /* Notice: For changes to the following function, make sure the function CthResumeNormalThreadDebug is also kept updated. */
2106 CMI_EXTERNC
2107 void CthResumeNormalThread(CthThreadToken* token)
2109   CthThread t = token->thread;
2111   /* BIGSIM_OOC DEBUGGING
2112   CmiPrintf("Resume normal thread with token[%p] ==> thread[%p]\n", token, t);
2113   */
2115   if(t == NULL){
2116     free(token);
2117     return;
2118   }
2119 #if CMK_TRACE_ENABLED
2120 #if ! CMK_TRACE_IN_CHARM
2121   if(CpvAccess(traceOn))
2122     CthTraceResume(t);
2123 /*    if(CpvAccess(_traceCoreOn)) 
2124                 resumeTraceCore();*/
2125 #endif
2126 #endif
2127   
2128   /* BIGSIM_OOC DEBUGGING
2129   CmiPrintf("In CthResumeNormalThread:   ");
2130   CthPrintThdMagic(t);
2131   */
2132 #if CMK_OMP
2133   CthSetPrev(t, CthSelf());
2134 #endif
2135   CthResume(t);
2136 #if CMK_OMP
2137   CthScheduledDecrement();
2138   CthSetPrev(CthSelf(), 0);
2139 #endif
2142 void CthResumeSchedulingThread(CthThreadToken  *token)
2144   CthThread t = token->thread;
2145   CthThread me = CthSelf();
2146   if (me == CpvAccess(CthMainThread)) {
2147     CthEnqueueSchedulingThread(CthGetToken(me),CQS_QUEUEING_FIFO, 0, 0);
2148   } else {
2149     CthSetNext(me, CpvAccess(CthSleepingStandins));
2150     CpvAccess(CthSleepingStandins) = me;
2151   }
2152   CpvAccess(CthSchedulingThread) = t;
2153 #if CMK_TRACE_ENABLED
2154 #if ! CMK_TRACE_IN_CHARM
2155   if(CpvAccess(traceOn))
2156     CthTraceResume(t);
2157 /*    if(CpvAccess(_traceCoreOn)) 
2158                 resumeTraceCore();*/
2159 #endif
2160 #endif
2161 #if CMK_OMP
2162   CthSetPrev(t, CthSelf());
2163 #endif
2164   CthResume(t);
2165 #if CMK_OMP
2166   CthScheduledDecrement();
2167   CthSetPrev(CthSelf(), 0);
2168 #endif
2171 void CthEnqueueNormalThread(CthThreadToken* token, int s, 
2172                                    int pb,unsigned int *prio)
2174   CmiSetHandler(token, CpvAccess(CthResumeNormalThreadIdx));
2175   CsdEnqueueGeneral(token, s, pb, prio);
2178 void CthEnqueueSchedulingThread(CthThreadToken* token, int s, 
2179                                        int pb,unsigned int *prio)
2181   CmiSetHandler(token, CpvAccess(CthResumeSchedulingThreadIdx));
2182   CsdEnqueueGeneral(token, s, pb, prio);
2185 void CthSetStrategyDefault(CthThread t)
2187   CthSetStrategy(t,
2188                  CthEnqueueNormalThread,
2189                  CthSuspendNormalThread);
2191 #if CMK_OMP
2192 /* Use work-stealing queue for scheduling threads
2193   We use the previous scheduling handlers while we push the message into the work-stealing queue
2195 void CthResumeStealableThread(CthThreadToken *token)
2197   CthThread t = token->thread;
2198   CthSetNext(t, CthSelf());
2199 #if CMK_TRACE_ENABLED
2200 #if ! CMK_TRACE_IN_CHARM
2201   if(CpvAccess(traceOn))
2202     CthTraceResume(t);
2203 #endif
2204 #endif
2205   CthSetPrev(t, CthSelf());
2206   CthResume(t);
2207   CthScheduledDecrement();
2208   CthSetPrev(CthSelf(), 0);
2211 void CthEnqueueStealableThread(CthThreadToken * token, int s, int pb, unsigned int *prio) {
2212   CmiSetHandler(token, CpvAccess(CthResumeStealableThreadIdx));
2213   CsdTaskEnqueue((void*)token);
2217 void CthEnqueueSuspendedStealableThread(CthThreadToken * token, int s, int pb, unsigned int *prio)
2219   CthThread t = token->thread;
2220   int targetRank = CthGetThreadID(t)->id[2];
2221   CthSetStrategyWorkStealing(t);
2222   if (targetRank == CmiMyRank()) {
2223     CthEnqueueStealableThread(token,s,pb,prio);
2224   }
2225   else {
2226     CmiSetHandler(token, CpvAccess(CthResumeSuspendedStealableThreadIdx));
2227     CmiSuspendedTaskEnqueue(targetRank ,(void*)token);
2228   }
2231 void CthResumeSuspendedStealableThread(CthThreadToken *token) {
2232   CthEnqueueStealableThread(token, 0, 0, NULL);
2235 CthThread CthSuspendStealableThread()
2237   CthThread succ = CthGetNext(CthSelf());
2238 #if CMK_ERROR_CHECKING
2239   if (!succ)
2240     CmiAbort("successor is invalid\n");
2241 #endif
2242   return succ;
2245 void CthSetStrategyWorkStealing(CthThread t)
2247   CthSetStrategy(t, CthEnqueueStealableThread, CthSuspendStealableThread);
2250 void CthSetStrategySuspendedWorkStealing(CthThread t)
2252   CthSetStrategy(t, CthEnqueueSuspendedStealableThread, CthSuspendStealableThread);
2255 #endif
2256 void CthSchedInit()
2258   CpvInitialize(CthThread, CthMainThread);
2259   CpvInitialize(CthThread, CthSchedulingThread);
2260   CpvInitialize(CthThread, CthSleepingStandins);
2261   CpvInitialize(int      , CthResumeNormalThreadIdx);
2262   CpvInitialize(int      , CthResumeSchedulingThreadIdx);
2263 #if CMK_OMP
2264   CpvInitialize(int      , CthResumeStealableThreadIdx);
2265   CpvInitialize(int      , CthResumeSuspendedStealableThreadIdx);
2266 #endif
2267   CpvAccess(CthMainThread) = CthSelf();
2268   CpvAccess(CthSchedulingThread) = CthSelf();
2269   CpvAccess(CthSleepingStandins) = 0;
2270   CpvAccess(CthResumeNormalThreadIdx) =
2271     CmiRegisterHandler((CmiHandler)CthResumeNormalThread);
2272   CpvAccess(CthResumeSchedulingThreadIdx) =
2273     CmiRegisterHandler((CmiHandler)CthResumeSchedulingThread);
2274   CthSetStrategy(CthSelf(),
2275                  CthEnqueueSchedulingThread,
2276                  CthSuspendSchedulingThread);
2278 #if CMK_OMP
2279   CpvAccess(CthResumeStealableThreadIdx) = CmiRegisterHandler((CmiHandler)CthResumeStealableThread);
2280   CpvAccess(CthResumeSuspendedStealableThreadIdx) = CmiRegisterHandler((CmiHandler)CthResumeSuspendedStealableThread);
2281 #endif
2284 void CsdInit(char **argv)
2286   CpvInitialize(Queue, CsdSchedQueue);
2287   CpvInitialize(int,   CsdStopFlag);
2288   CpvInitialize(int,   CsdLocalCounter);
2289   int argCsdLocalMax=CSD_LOCAL_MAX_DEFAULT;
2290   int argmaxset = CmiGetArgIntDesc(argv,"+csdLocalMax",&argCsdLocalMax,"Set the max number of local messages to process before forcing a check for remote messages.");
2291   if (CmiMyRank() == 0 ) CsdLocalMax = argCsdLocalMax;
2292   CpvAccess(CsdLocalCounter) = argCsdLocalMax;
2293   CpvAccess(CsdSchedQueue) = CqsCreate();
2294 #if CMK_SMP && CMK_TASKQUEUE
2295   CsvInitialize(unsigned int, idleThreadsCnt);
2296   CsvAccess(idleThreadsCnt) = 0;
2297 #endif
2298    #if CMK_USE_STL_MSGQ
2299    if (CmiMyPe() == 0) CmiPrintf("Charm++> Using STL-based msgQ:\n");
2300    #endif
2301    #if CMK_RANDOMIZED_MSGQ
2302    if (CmiMyPe() == 0) CmiPrintf("Charm++> Using randomized msgQ. Priorities will not be respected!\n");
2303    #elif CMK_NO_MSG_PRIOS
2304    if (CmiMyPe() == 0) CmiPrintf("Charm++> Message priorities have been turned off and will not be respected.\n");
2305    #endif
2307 #if CMK_OBJECT_QUEUE_AVAILABLE
2308   CpvInitialize(Queue, CsdObjQueue);
2309   CpvAccess(CsdObjQueue) = CdsFifo_Create();
2310 #endif
2312 #if CMK_NODE_QUEUE_AVAILABLE
2313   CsvInitialize(CmiLock, CsdNodeQueueLock);
2314   CsvInitialize(Queue, CsdNodeQueue);
2315   if (CmiMyRank() ==0) {
2316         CsvAccess(CsdNodeQueueLock) = CmiCreateLock();
2317         CsvAccess(CsdNodeQueue) = CqsCreate();
2318   }
2319   CmiNodeAllBarrier();
2320 #endif
2322 #if CMK_GRID_QUEUE_AVAILABLE
2323   CsvInitialize(Queue, CsdGridQueue);
2324   CpvAccess(CsdGridQueue) = CqsCreate();
2325 #endif
2327 #if CMK_SMP && CMK_TASKQUEUE
2328   CpvInitialize(Queue, CsdTaskQueue);
2329   CpvInitialize(void *, CmiSuspendedTaskQueue);
2330   CpvAccess(CsdTaskQueue) = (Queue)TaskQueueCreate();
2331 #endif
2332   CpvAccess(CsdStopFlag)  = 0;
2333   CpvInitialize(int, isHelperOn);
2334   CpvAccess(isHelperOn) = 1; // Turn on this bit by default for threads to be used for CkLoop and OpenMP integration
2335   CmiMemoryWriteFence();
2336 #if CMK_SMP && CMK_TASKQUEUE
2337   CmiTaskQueueInit();
2338 #endif
2343 /** 
2344  *  @}
2345  */
2348 /*****************************************************************************
2350  * Vector Send
2352  * The last parameter "system" is by default at zero, in which case the normal
2353  * messages are sent. If it is set to 1, the CmiChunkHeader prepended to every
2354  * CmiAllocced message will also be sent (except for the first one). Useful for
2355  * AllToAll communication, and other system features. If system is 1, also all
2356  * the messages will be padded to 8 bytes. Thus, the caller must be aware of
2357  * that.
2359  ****************************************************************************/
2361 #if CMK_VECTOR_SEND_USES_COMMON_CODE
2363 void CmiSyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2364   int total;
2365   char *mesg;
2366 #if CMK_USE_IBVERBS
2367   VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(infiCmiChunkHeader));
2368 #else
2369   VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(CmiChunkHeader));
2370 #endif  
2371   CmiSyncSendAndFree(destPE, total, mesg);
2374 CmiCommHandle CmiASyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2375   CmiSyncVectorSend(destPE, n, sizes, msgs);
2376   return NULL;
2379 void CmiSyncVectorSendAndFree(int destPE, int n, int *sizes, char **msgs) {
2380   int i;
2381   CmiSyncVectorSend(destPE, n, sizes, msgs);
2382   for(i=0;i<n;i++) CmiFree(msgs[i]);
2383   CmiFree(sizes);
2384   CmiFree(msgs);
2387 #endif
2389 /*****************************************************************************
2391  * Reduction management
2393  * Only one reduction can be active at a single time in the program.
2394  * Moreover, since every call is supposed to pass in the same arguments,
2395  * having some static variables is not a problem for multithreading.
2396  * 
2397  * Except for "data" and "size", all the other parameters (which are all function
2398  * pointers) MUST be the same in every processor. Having different processors
2399  * pass in different function pointers results in an undefined behaviour.
2400  * 
2401  * The data passed in to CmiReduce and CmiNodeReduce is deleted by the system,
2402  * and MUST be allocated with CmiAlloc. The data passed in to the "Struct"
2403  * functions is deleted with the provided function, or it is left intact if no
2404  * function is specified.
2405  * 
2406  * The destination handler for the the first form MUST be embedded into the
2407  * message's header.
2408  * 
2409  * The pup function is used to pup the input data structure into a message to
2410  * be sent to the parent processor. This pup routine is currently used only
2411  * for sizing and packing, NOT unpacking. It MUST be non-null.
2412  * 
2413  * The merge function receives as first parameter the input "data", being it
2414  * a message or a complex data structure (it is up to the user to interpret it
2415  * correctly), and a list of incoming (packed) messages from the children.
2416  * The merge function is responsible to delete "data" if this is no longer needed.
2417  * The system will be in charge of deleting the messages passed in as the second
2418  * argument, and the return value of the function (using the provided deleteFn in
2419  * the second version, or CmiFree in the first). The merge function can return
2420  * data if the merge can be performed in-place. It MUST be non-null.
2421  * 
2422  * At the destination, on processor zero, the final data returned by the last
2423  * merge call will not be deleted by the system, and the CmiHandler function
2424  * will be in charge of its deletion.
2425  * 
2426  * CmiReduce/CmiReduceStruct MUST be called once by every processor,
2427  * CmiNodeReduce/CmiNodeReduceStruct MUST be called once by every node, and in
2428  * particular by the rank zero in each node.
2429  ****************************************************************************/
2431 CpvStaticDeclare(int, CmiReductionMessageHandler);
2432 CpvStaticDeclare(int, CmiReductionDynamicRequestHandler);
2434 CpvStaticDeclare(CmiReduction**, _reduce_info);
2435 CpvStaticDeclare(int, _reduce_info_size); /* This is the log2 of the size of the array */
2436 CpvStaticDeclare(CmiUInt2, _reduce_seqID_global); /* This is used only by global reductions */
2437 CpvStaticDeclare(CmiUInt2, _reduce_seqID_request);
2438 CpvStaticDeclare(CmiUInt2, _reduce_seqID_dynamic);
2440 enum {
2441   CmiReductionID_globalOffset = 0, /* Reductions that involve the whole set of processors */
2442   CmiReductionID_requestOffset = 1, /* Reductions IDs that are requested by all the processors (i.e during intialization) */
2443   CmiReductionID_dynamicOffset = 2, /* Reductions IDs that are requested by only one processor (typically at runtime) */
2444   CmiReductionID_multiplier = 3
2447 CmiReduction* CmiGetReductionCreate(int id, short int numChildren) {
2448   int index = id & ~((~0u)<<CpvAccess(_reduce_info_size));
2449   CmiReduction *red = CpvAccess(_reduce_info)[index];
2450   if (red != NULL && red->seqID != id) {
2451     /* The table needs to be expanded */
2452     CmiAbort("Too many simultaneous reductions");
2453   }
2454   if (red == NULL || red->numChildren < numChildren) {
2455     CmiReduction *newred;
2456     CmiAssert(red == NULL || red->localContributed == 0);
2457     if (numChildren == 0) numChildren = 4;
2458     newred = (CmiReduction*)malloc(sizeof(CmiReduction)+numChildren*sizeof(void*));
2459     newred->numRemoteReceived = 0;
2460     newred->localContributed = 0;
2461     newred->seqID = id;
2462     if (red != NULL) {
2463       memcpy(newred, red, sizeof(CmiReduction)+red->numChildren*sizeof(void*));
2464       free(red);
2465     }
2466     red = newred;
2467     red->numChildren = numChildren;
2468     red->remoteData = (char**)(red+1);
2469     CpvAccess(_reduce_info)[index] = red;
2470   }
2471   return red;
2474 CmiReduction* CmiGetReduction(int id) {
2475   return CmiGetReductionCreate(id, 0);
2478 void CmiClearReduction(int id) {
2479   int index = id & ~((~0u)<<CpvAccess(_reduce_info_size));
2480   free(CpvAccess(_reduce_info)[index]);
2481   CpvAccess(_reduce_info)[index] = NULL;
2484 CmiReduction* CmiGetNextReduction(short int numChildren) {
2485   int id = CpvAccess(_reduce_seqID_global);
2486   CpvAccess(_reduce_seqID_global) += CmiReductionID_multiplier;
2487   if (id > 0xFFF0) CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2488   return CmiGetReductionCreate(id, numChildren);
2491 CmiReductionID CmiGetGlobalReduction(void) {
2492   return CpvAccess(_reduce_seqID_request)+=CmiReductionID_multiplier;
2495 CmiReductionID CmiGetDynamicReduction(void) {
2496   if (CmiMyPe() != 0) CmiAbort("Cannot call CmiGetDynamicReduction on processors other than zero!\n");
2497   return CpvAccess(_reduce_seqID_dynamic)+=CmiReductionID_multiplier;
2500 void CmiReductionHandleDynamicRequest(char *msg) {
2501   int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2502   int pe = values[0];
2503   int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+values[1];
2504   values[0] = CmiGetDynamicReduction();
2505   CmiSetHandler(msg, CmiGetXHandler(msg));
2506   if (pe >= 0) {
2507     CmiSyncSendAndFree(pe, size, msg);
2508   } else {
2509     CmiSyncBroadcastAllAndFree(size, msg);
2510   }
2513 void CmiGetDynamicReductionRemote(int handlerIdx, int pe, int dataSize, void *data) {
2514   int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+dataSize;
2515   char *msg = (char*)CmiAlloc(size);
2516   int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2517   values[0] = pe;
2518   values[1] = dataSize;
2519   CmiSetXHandler(msg, handlerIdx);
2520   if (dataSize) memcpy(msg+CmiMsgHeaderSizeBytes+2*sizeof(int), data, dataSize);
2521   if (CmiMyPe() == 0) {
2522     CmiReductionHandleDynamicRequest(msg);
2523   } else {
2524     /* send the request to processor 0 */
2525     CmiSetHandler(msg, CpvAccess(CmiReductionDynamicRequestHandler));
2526     CmiSyncSendAndFree(0, size, msg);
2527   }
2530 void CmiSendReduce(CmiReduction *red) {
2531   void *mergedData, *msg;
2532   int msg_size;
2533   if (!red->localContributed || red->numChildren != red->numRemoteReceived) return;
2534   mergedData = red->localData;
2535   msg_size = red->localSize;
2536   if (red->numChildren > 0) {
2537     int i, offset=0;
2538     if (red->ops.pupFn != NULL) {
2539       offset = CmiReservedHeaderSize;
2540       for (i=0; i<red->numChildren; ++i) red->remoteData[i] += offset;
2541     }
2542     mergedData = (red->ops.mergeFn)(&msg_size, red->localData, (void **)red->remoteData, red->numChildren);
2543     for (i=0; i<red->numChildren; ++i) CmiFree(red->remoteData[i] - offset);
2544   }
2545   /*CpvAccess(_reduce_num_children) = 0;*/
2546   /*CpvAccess(_reduce_received) = 0;*/
2547   msg = mergedData;
2548   if (red->parent != -1) {
2549     if (red->ops.pupFn != NULL) {
2550       pup_er p = pup_new_sizer();
2551       (red->ops.pupFn)(p, mergedData);
2552       msg_size = pup_size(p) + CmiReservedHeaderSize;
2553       pup_destroy(p);
2554       msg = CmiAlloc(msg_size);
2555       p = pup_new_toMem((void*)(((char*)msg)+CmiReservedHeaderSize));
2556       (red->ops.pupFn)(p, mergedData);
2557       pup_destroy(p);
2558       if (red->ops.deleteFn != NULL) (red->ops.deleteFn)(red->localData);
2559     }
2560     CmiSetHandler(msg, CpvAccess(CmiReductionMessageHandler));
2561     CmiSetRedID(msg, red->seqID);
2562     /*CmiPrintf("CmiSendReduce(%d): sending %d bytes to %d\n",CmiMyPe(),msg_size,red->parent);*/
2563     CmiSyncSendAndFree(red->parent, msg_size, msg);
2564   } else {
2565     (red->ops.destination)(msg);
2566   }
2567   CmiClearReduction(red->seqID);
2570 void *CmiReduceMergeFn_random(int *size, void *data, void** remote, int n) {
2571   return data;
2574 void CmiResetGlobalReduceSeqID(void) {
2575         CpvAccess(_reduce_seqID_global) = 0;
2578 static void CmiGlobalReduce(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReduction *red) {
2579   CmiAssert(red->localContributed == 0);
2580   red->localContributed = 1;
2581   red->localData = msg;
2582   red->localSize = size;
2583   red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2584   red->parent = CmiSpanTreeParent(CmiMyPe());
2585   red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2586   red->ops.mergeFn = mergeFn;
2587   red->ops.pupFn = NULL;
2588   /*CmiPrintf("[%d] CmiReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2589   CmiSendReduce(red);
2592 static void CmiGlobalReduceStruct(void *data, CmiReducePupFn pupFn,
2593                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2594                      CmiReduceDeleteFn deleteFn, CmiReduction *red) {
2595   CmiAssert(red->localContributed == 0);
2596   red->localContributed = 1;
2597   red->localData = data;
2598   red->localSize = 0;
2599   red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2600   red->parent = CmiSpanTreeParent(CmiMyPe());
2601   red->ops.destination = dest;
2602   red->ops.mergeFn = mergeFn;
2603   red->ops.pupFn = pupFn;
2604   red->ops.deleteFn = deleteFn;
2605   /*CmiPrintf("[%d] CmiReduceStruct::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2606   CmiSendReduce(red);
2609 void CmiReduce(void *msg, int size, CmiReduceMergeFn mergeFn) {
2610   CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2611   CmiGlobalReduce(msg, size, mergeFn, red);
2614 void CmiReduceStruct(void *data, CmiReducePupFn pupFn,
2615                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2616                      CmiReduceDeleteFn deleteFn) {
2617   CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2618   CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2621 void CmiReduceID(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2622   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2623   CmiGlobalReduce(msg, size, mergeFn, red);
2626 void CmiReduceStructID(void *data, CmiReducePupFn pupFn,
2627                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2628                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2629   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2630   CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2633 void CmiListReduce(int npes, int *pes, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2634   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2635   int myPos;
2636   CmiAssert(red->localContributed == 0);
2637   red->localContributed = 1;
2638   red->localData = msg;
2639   red->localSize = size;
2640   for (myPos=0; myPos<npes; ++myPos) {
2641     if (pes[myPos] == CmiMyPe()) break;
2642   }
2643   CmiAssert(myPos < npes);
2644   red->numChildren = npes - (myPos << 2) - 1;
2645   if (red->numChildren > 4) red->numChildren = 4;
2646   if (red->numChildren < 0) red->numChildren = 0;
2647   if (myPos == 0) red->parent = -1;
2648   else red->parent = pes[(myPos - 1) >> 2];
2649   red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2650   red->ops.mergeFn = mergeFn;
2651   red->ops.pupFn = NULL;
2652   /*CmiPrintf("[%d] CmiListReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2653   CmiSendReduce(red);
2656 void CmiListReduceStruct(int npes, int *pes,
2657                      void *data, CmiReducePupFn pupFn,
2658                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2659                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2660   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2661   int myPos;
2662   CmiAssert(red->localContributed == 0);
2663   red->localContributed = 1;
2664   red->localData = data;
2665   red->localSize = 0;
2666   for (myPos=0; myPos<npes; ++myPos) {
2667     if (pes[myPos] == CmiMyPe()) break;
2668   }
2669   CmiAssert(myPos < npes);
2670   red->numChildren = npes - (myPos << 2) - 1;
2671   if (red->numChildren > 4) red->numChildren = 4;
2672   if (red->numChildren < 0) red->numChildren = 0;
2673   red->parent = (myPos - 1) >> 2;
2674   if (myPos == 0) red->parent = -1;
2675   red->ops.destination = dest;
2676   red->ops.mergeFn = mergeFn;
2677   red->ops.pupFn = pupFn;
2678   red->ops.deleteFn = deleteFn;
2679   CmiSendReduce(red);
2682 void CmiGroupReduce(CmiGroup grp, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2683   int npes, *pes;
2684   CmiLookupGroup(grp, &npes, &pes);
2685   CmiListReduce(npes, pes, msg, size, mergeFn, id);
2688 void CmiGroupReduceStruct(CmiGroup grp, void *data, CmiReducePupFn pupFn,
2689                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2690                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2691   int npes, *pes;
2692   CmiLookupGroup(grp, &npes, &pes);
2693   CmiListReduceStruct(npes, pes, data, pupFn, mergeFn, dest, deleteFn, id);
2696 void CmiNodeReduce(void *data, int size, CmiReduceMergeFn mergeFn, int redID, int numChildren, int parent) {
2697   CmiAbort("Feel free to implement CmiNodeReduce...");
2698   /*
2699   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2700   CpvAccess(_reduce_data) = data;
2701   CpvAccess(_reduce_data_size) = size;
2702   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2703   _reduce_destination = (CmiHandler)CmiGetHandlerFunction(data);
2704   _reduce_pupFn = NULL;
2705   _reduce_mergeFn = mergeFn;
2706   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2707   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(size);
2708   */
2710 #if 0
2711 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int redID) {
2712   CmiNodeReduce(data, size, mergeFn, redID, CmiNumNodeSpanTreeChildren(CmiMyNode()),
2713       CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2715 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int numChildren, int parent) {
2716   CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), numChildren, parent);
2718 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int)) {
2719   CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), CmiNumNodeSpanTreeChildren(CmiMyNode()),
2720       CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2722 #endif
2724 void CmiNodeReduceStruct(void *data, CmiReducePupFn pupFn,
2725                          CmiReduceMergeFn mergeFn, CmiHandler dest,
2726                          CmiReduceDeleteFn deleteFn) {
2727   CmiAbort("Feel free to implement CmiNodeReduceStruct...");
2729   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2730   CpvAccess(_reduce_data) = data;
2731   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2732   _reduce_destination = dest;
2733   _reduce_pupFn = pupFn;
2734   _reduce_mergeFn = mergeFn;
2735   _reduce_deleteFn = deleteFn;
2736   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2737   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(0);
2738   */
2741 void CmiHandleReductionMessage(void *msg) {
2742   CmiReduction *red = CmiGetReduction(CmiGetRedID(msg));
2743   if (red->numRemoteReceived == red->numChildren) red = CmiGetReductionCreate(CmiGetRedID(msg), red->numChildren+4);
2744   red->remoteData[red->numRemoteReceived++] = (char *)msg;
2745   /*CmiPrintf("[%d] CmiReduce::remote %hd\n",CmiMyPe(),red->seqID);*/
2746   CmiSendReduce(red);
2748   CpvAccess(_reduce_msg_list)[CpvAccess(_reduce_received)++] = msg;
2749   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce();
2750   / *else CmiPrintf("CmiHandleReductionMessage(%d): %d - %d\n",CmiMyPe(),CpvAccess(_reduce_received),CpvAccess(_reduce_num_children));*/
2753 void CmiReductionsInit(void) {
2754   int i;
2755   CpvInitialize(int, CmiReductionMessageHandler);
2756   CpvAccess(CmiReductionMessageHandler) = CmiRegisterHandler((CmiHandler)CmiHandleReductionMessage);
2757   CpvInitialize(int, CmiReductionDynamicRequestHandler);
2758   CpvAccess(CmiReductionDynamicRequestHandler) = CmiRegisterHandler((CmiHandler)CmiReductionHandleDynamicRequest);
2759   CpvInitialize(CmiUInt2, _reduce_seqID_global);
2760   CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2761   CpvInitialize(CmiUInt2, _reduce_seqID_request);
2762   CpvAccess(_reduce_seqID_request) = CmiReductionID_requestOffset;
2763   CpvInitialize(CmiUInt2, _reduce_seqID_dynamic);
2764   CpvAccess(_reduce_seqID_dynamic) = CmiReductionID_dynamicOffset;
2765   CpvInitialize(int, _reduce_info_size);
2766   CpvAccess(_reduce_info_size) = 4;
2767   CpvInitialize(CmiReduction**, _reduce_info);
2768   CpvAccess(_reduce_info) = (CmiReduction **)malloc(16*sizeof(CmiReduction*));
2769   for (i=0; i<16; ++i) CpvAccess(_reduce_info)[i] = NULL;
2772 /*****************************************************************************
2774  * Multicast groups
2776  ****************************************************************************/
2778 #if CMK_MULTICAST_DEF_USE_COMMON_CODE
2780 typedef struct GroupDef_s
2782   union {
2783     char core[CmiMsgHeaderSizeBytes];
2784     struct GroupDef_s *next;
2785   } core;
2786   CmiGroup group;
2787   int npes;
2788   int pes[1];
2790 *GroupDef;
2792 #define GROUPTAB_SIZE 101
2794 CpvStaticDeclare(int, CmiGroupHandlerIndex);
2795 CpvStaticDeclare(int, CmiGroupCounter);
2796 CpvStaticDeclare(GroupDef *, CmiGroupTable);
2798 void CmiGroupHandler(GroupDef def)
2800   /* receive group definition, insert into group table */
2801   GroupDef *table = CpvAccess(CmiGroupTable);
2802   unsigned int hashval, bucket;
2803   hashval = (def->group.id ^ def->group.pe);
2804   bucket = hashval % GROUPTAB_SIZE;
2805   def->core.next = table[bucket];
2806   table[bucket] = def;
2809 CmiGroup CmiEstablishGroup(int npes, int *pes)
2811   /* build new group definition, broadcast it */
2812   CmiGroup grp; GroupDef def; int len, i;
2813   grp.id = CpvAccess(CmiGroupCounter)++;
2814   grp.pe = CmiMyPe();
2815   len = sizeof(struct GroupDef_s)+(npes*sizeof(int));
2816   def = (GroupDef)CmiAlloc(len);
2817   def->group = grp;
2818   def->npes = npes;
2819   for (i=0; i<npes; i++)
2820     def->pes[i] = pes[i];
2821   CmiSetHandler(def, CpvAccess(CmiGroupHandlerIndex));
2822   CmiSyncBroadcastAllAndFree(len, def);
2823   return grp;
2826 void CmiLookupGroup(CmiGroup grp, int *npes, int **pes)
2828   unsigned int hashval, bucket;  GroupDef def;
2829   GroupDef *table = CpvAccess(CmiGroupTable);
2830   hashval = (grp.id ^ grp.pe);
2831   bucket = hashval % GROUPTAB_SIZE;
2832   for (def=table[bucket]; def; def=def->core.next) {
2833     if ((def->group.id == grp.id)&&(def->group.pe == grp.pe)) {
2834       *npes = def->npes;
2835       *pes = def->pes;
2836       return;
2837     }
2838   }
2839   *npes = 0; *pes = 0;
2842 void CmiGroupInit(void)
2844   CpvInitialize(int, CmiGroupHandlerIndex);
2845   CpvInitialize(int, CmiGroupCounter);
2846   CpvInitialize(GroupDef *, CmiGroupTable);
2847   CpvAccess(CmiGroupHandlerIndex) = CmiRegisterHandler((CmiHandler)CmiGroupHandler);
2848   CpvAccess(CmiGroupCounter) = 0;
2849   CpvAccess(CmiGroupTable) =
2850     (GroupDef*)calloc(GROUPTAB_SIZE, sizeof(GroupDef));
2851   if (CpvAccess(CmiGroupTable) == 0)
2852     CmiAbort("Memory Allocation Error");
2855 #endif
2857 /*****************************************************************************
2859  * Common List-Cast and Multicast Code
2861  ****************************************************************************/
2863 #if CMK_MULTICAST_LIST_USE_COMMON_CODE
2865 void CmiSyncListSendFn(int npes, int *pes, int len, char *msg)
2867   int i;
2868 #if CMK_BROADCAST_USE_CMIREFERENCE
2869   for(i=0;i<npes;i++) {
2870     if (pes[i] == CmiMyPe())
2871       CmiSyncSend(pes[i], len, msg);
2872     else {
2873       CmiReference(msg);
2874       CmiSyncSendAndFree(pes[i], len, msg);
2875     }
2876   }
2877 #else
2878   for(i=0;i<npes;i++) {
2879     CmiSyncSend(pes[i], len, msg);
2880   }
2881 #endif
2884 CmiCommHandle CmiAsyncListSendFn(int npes, int *pes, int len, char *msg)
2886   /* A better asynchronous implementation may be wanted, but at least it works */
2887   CmiSyncListSendFn(npes, pes, len, msg);
2888   return (CmiCommHandle) 0;
2891 void CmiFreeListSendFn(int npes, int *pes, int len, char *msg)
2893 #if CMK_BROADCAST_USE_CMIREFERENCE
2894   if (npes == 1) {
2895     CmiSyncSendAndFree(pes[0], len, msg);
2896     return;
2897   }
2898   CmiSyncListSendFn(npes, pes, len, msg);
2899   CmiFree(msg);
2900 #else
2901   int i;
2902   for(i=0;i<npes-1;i++) {
2903     CmiSyncSend(pes[i], len, msg);
2904   }
2905   if (npes>0)
2906     CmiSyncSendAndFree(pes[npes-1], len, msg);
2907   else 
2908     CmiFree(msg);
2909 #endif
2912 #endif
2914 #if CMK_MULTICAST_GROUP_USE_COMMON_CODE
2916 typedef struct MultiMsg_s
2918   char core[CmiMsgHeaderSizeBytes];
2919   CmiGroup group;
2920   int pos;
2921   int origlen;
2923 *MultiMsg;
2926 CpvDeclare(int, CmiMulticastHandlerIndex);
2928 void CmiMulticastDeliver(MultiMsg msg)
2930   int npes, *pes; int olen, nlen, pos, child1, child2;
2931   olen = msg->origlen;
2932   nlen = olen + sizeof(struct MultiMsg_s);
2933   CmiLookupGroup(msg->group, &npes, &pes);
2934   if (pes==0) {
2935     CmiSyncSendAndFree(CmiMyPe(), nlen, msg);
2936     return;
2937   }
2938   if (npes==0) {
2939     CmiFree(msg);
2940     return;
2941   }
2942   if (msg->pos == -1) {
2943     msg->pos=0;
2944     CmiSyncSendAndFree(pes[0], nlen, msg);
2945     return;
2946   }
2947   pos = msg->pos;
2948   child1 = ((pos+1)<<1);
2949   child2 = child1-1;
2950   if (child1 < npes) {
2951     msg->pos = child1;
2952     CmiSyncSend(pes[child1], nlen, msg);
2953   }
2954   if (child2 < npes) {
2955     msg->pos = child2;
2956     CmiSyncSend(pes[child2], nlen, msg);
2957   }
2958   if(olen < sizeof(struct MultiMsg_s)) {
2959     memcpy(msg, msg+1, olen);
2960   } else {
2961     memcpy(msg, (((char*)msg)+olen), sizeof(struct MultiMsg_s));
2962   }
2963   CmiSyncSendAndFree(CmiMyPe(), olen, msg);
2966 void CmiMulticastHandler(MultiMsg msg)
2968   CmiMulticastDeliver(msg);
2971 void CmiSyncMulticastFn(CmiGroup grp, int len, char *msg)
2973   int newlen; MultiMsg newmsg;
2974   newlen = len + sizeof(struct MultiMsg_s);
2975   newmsg = (MultiMsg)CmiAlloc(newlen);
2976   if(len < sizeof(struct MultiMsg_s)) {
2977     memcpy(newmsg+1, msg, len);
2978   } else {
2979     memcpy(newmsg+1, msg+sizeof(struct MultiMsg_s), len-sizeof(struct MultiMsg_s));
2980     memcpy(((char *)newmsg+len), msg, sizeof(struct MultiMsg_s));
2981   }
2982   newmsg->group = grp;
2983   newmsg->origlen = len;
2984   newmsg->pos = -1;
2985   CmiSetHandler(newmsg, CpvAccess(CmiMulticastHandlerIndex));
2986   CmiMulticastDeliver(newmsg);
2989 void CmiFreeMulticastFn(CmiGroup grp, int len, char *msg)
2991   CmiSyncMulticastFn(grp, len, msg);
2992   CmiFree(msg);
2995 CmiCommHandle CmiAsyncMulticastFn(CmiGroup grp, int len, char *msg)
2997   CmiError("Async Multicast not implemented.");
2998   return (CmiCommHandle) 0;
3001 void CmiMulticastInit(void)
3003   CpvInitialize(int, CmiMulticastHandlerIndex);
3004   CpvAccess(CmiMulticastHandlerIndex) =
3005     CmiRegisterHandler((CmiHandler)CmiMulticastHandler);
3008 #else
3009 extern void CmiMulticastInit(void);
3010 #endif
3012 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
3013 extern void *arena_malloc(int size);
3014 extern void arena_free(void *blockPtr);
3015 #endif
3017 /***************************************************************************
3019  * Memory Allocation routines 
3021  * A block of memory can consist of multiple chunks.  Each chunk has
3022  * a sizefield and a refcount.  The first chunk's refcount is a reference
3023  * count.  That's how many CmiFrees it takes to free the message.
3024  * Subsequent chunks have a refcount which is less than zero.  This is
3025  * the offset back to the start of the first chunk.
3027  * Each chunk has a CmiChunkHeader before the user data, with the fields:
3029  *  size: The user-allocated size of the chunk, in bytes.
3031  *  ref: A magic reference count object. Ordinary blocks start with
3032  *     reference count 1.  When the reference count reaches zero,
3033  *     the block is deleted.  To support nested buffers, the 
3034  *     reference count can also be negative, which means it is 
3035  *     a byte offset to the enclosing buffer's reference count.
3037  ***************************************************************************/
3040 void *CmiAlloc(int size)
3043   char *res;
3045 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
3046   res = (char*) arena_malloc(size+sizeof(CmiChunkHeader));
3047 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
3048   res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
3049 #elif CMK_CONVERSE_UGNI || CMK_OFI
3050   res =(char *) LrtsAlloc(size, sizeof(CmiChunkHeader));
3051 #elif CONVERSE_POOL
3052   res =(char *) CmiPoolAlloc(size+sizeof(CmiChunkHeader));
3053 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
3054   MPI_Alloc_mem(size+sizeof(CmiChunkHeader), MPI_INFO_NULL, &res);
3055 #elif CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
3056   res = (char *) CmiAlloc_bgq(size+sizeof(CmiChunkHeader));
3057 #elif CMK_SMP && CMK_PPC_ATOMIC_QUEUE
3058   res = (char *) CmiAlloc_ppcq(size+sizeof(CmiChunkHeader));
3059 #else
3060   res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
3061 #endif
3063   _MEMCHECK(res);
3065 #ifdef MEMMONITOR
3066   CpvAccess(MemoryUsage) += size+sizeof(CmiChunkHeader);
3067   CpvAccess(AllocCount)++;
3068   CpvAccess(BlocksAllocated)++;
3069   if (CpvAccess(MemoryUsage) > CpvAccess(HiWaterMark)) {
3070     CpvAccess(HiWaterMark) = CpvAccess(MemoryUsage);
3071   }
3072   if (CpvAccess(MemoryUsage) > 1.1 * CpvAccess(ReportedHiWaterMark)) {
3073     CmiPrintf("HIMEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
3074             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
3075             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
3076     CpvAccess(ReportedHiWaterMark) = CpvAccess(MemoryUsage);
3077   }
3078   if ((CpvAccess(AllocCount) % 1000) == 0) {
3079     CmiPrintf("MEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
3080             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
3081             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
3082   }
3083 #endif
3085   res+=sizeof(CmiChunkHeader);
3086   CmiAssert((intptr_t)res % ALIGN_BYTES == 0);
3088   SIZEFIELD(res)=size;
3089   REFFIELDSET(res, 1);
3090   return (void *)res;
3093 void *CmiRdmaAlloc(int size) {
3094   char *res;
3096 #if CMK_CONVERSE_UGNI
3097   res = (char *)LrtsRdmaAlloc(size, sizeof(CmiChunkHeader));
3098 #elif CMK_USE_IBVERBS || CMK_USE_IBUD
3099   res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
3100 #elif CMK_OFI
3101   res = (char *)LrtsAlloc(size, sizeof(CmiChunkHeader));
3102 #else
3103   res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
3104 #endif
3106   _MEMCHECK(res);
3107   res+=sizeof(CmiChunkHeader);
3108   CmiAssert((intptr_t)res % ALIGN_BYTES == 0);
3110   SIZEFIELD(res)=size;
3111   REFFIELDSET(res, 1);
3112   return (void *)res;
3116 /** Follow the header links out to the most enclosing block */
3117 static void *CmiAllocFindEnclosing(void *blk) {
3118   int refCount = REFFIELD(blk);
3119   while (refCount < 0) {
3120     blk = (void *)((char*)blk+refCount); /* Jump to enclosing block */
3121     refCount = REFFIELD(blk);
3122   }
3123   return blk;
3126 int CmiGetReference(void *blk)
3128   return REFFIELD(CmiAllocFindEnclosing(blk));
3131 /** Increment the reference count for this block's owner.
3132     This call must be matched by an equivalent CmiFree. */
3133 void CmiReference(void *blk)
3135   REFFIELDINC(CmiAllocFindEnclosing(blk));
3138 /** Return the size of the user portion of this block. */
3139 int CmiSize(void *blk)
3141   return SIZEFIELD(blk);
3144 /** Decrement the reference count for this block. */
3145 void CmiFree(void *blk)
3147   void *parentBlk=CmiAllocFindEnclosing(blk);
3148   int refCount=REFFIELDDEC(parentBlk);
3149 #if CMK_ERROR_CHECKING
3150   if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
3151     CmiAbort("CmiFree reference count was zero-- is this a duplicate free?");
3152 #endif
3153   if(refCount==1) { /* This was the last reference to the block-- free it */
3154 #ifdef MEMMONITOR
3155     int size=SIZEFIELD(parentBlk);
3156     if (size > 1000000000) /* Absurdly large size field-- warning */
3157       CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
3158     CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader));
3159     CpvAccess(BlocksAllocated)--;
3160 #endif
3162 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
3163     arena_free(BLKSTART(parentBlk));
3164 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
3165     /* is this message the head of a MultipleSend that we received?
3166        Then the parts with INFIMULTIPOOL have metadata which must be 
3167        unregistered and freed.  */
3168 #ifdef CMK_IBVERS_CLEAN_MULTIPLESEND
3169     if(CmiGetHandler(parentBlk)==CpvAccess(CmiMainHandlerIDP))
3170       {
3171         infi_freeMultipleSend(parentBlk);
3172       }
3173 #endif
3174     infi_CmiFree(BLKSTART(parentBlk));
3175 #elif CMK_CONVERSE_UGNI || CMK_OFI
3176     LrtsFree(BLKSTART(parentBlk));
3177 #elif CONVERSE_POOL
3178     CmiPoolFree(BLKSTART(parentBlk));
3179 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
3180     MPI_Free_mem(parentBlk);
3181 #elif CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
3182     CmiFree_bgq(BLKSTART(parentBlk));
3183 #elif CMK_SMP && CMK_PPC_ATOMIC_QUEUE
3184     CmiFree_ppcq(BLKSTART(parentBlk));
3185 #else
3186     free_nomigrate(BLKSTART(parentBlk));
3187 #endif
3188   }
3191 void CmiRdmaFree(void *blk)
3193   void *parentBlk=CmiAllocFindEnclosing(blk);
3194   int refCount=REFFIELDDEC(parentBlk);
3195 #if CMK_ERROR_CHECKING
3196   if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
3197     CmiAbort("CmiRdmaFree reference count was zero-- is this a duplicate free?");
3198 #endif
3199   if(refCount==1) { /* This was the last reference to the block-- free it */
3200 #ifdef MEMMONITOR
3201     int size=SIZEFIELD(parentBlk);
3202     if (size > 1000000000) /* Absurdly large size field-- warning */
3203       CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
3204     CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader));
3205     CpvAccess(BlocksAllocated)--;
3206 #endif
3208 #if CMK_CONVERSE_UGNI
3209     LrtsRdmaFree(BLKSTART(parentBlk));
3210 #elif CMK_USE_IBVERBS || CMK_USE_IBUD
3211     infi_CmiFree(BLKSTART(parentBlk));
3212 #elif CMK_OFI
3213     LrtsFree(BLKSTART(parentBlk));
3214 #else
3215     free_nomigrate(BLKSTART(parentBlk));
3216 #endif
3217   }
3221 /***************************************************************************
3223  * Temporary-memory Allocation routines 
3225  *  This buffer augments the storage available on the regular machine stack
3226  * for fairly large temporary buffers, which allows us to use smaller machine
3227  * stacks.
3229  ***************************************************************************/
3231 #define CMI_TMP_BUF_MAX 16*1024 /* Allow this much temporary storage. */
3233 typedef struct {
3234   char *buf; /* Start of temporary buffer */
3235   int cur; /* First unused location in temporary buffer */
3236   int max; /* Length of temporary buffer */
3237 } CmiTmpBuf_t;
3238 CpvDeclare(CmiTmpBuf_t,CmiTmpBuf); /* One temporary buffer per PE */
3240 static void CmiTmpSetup(CmiTmpBuf_t *b) {
3241   b->buf=(char *)malloc(CMI_TMP_BUF_MAX);
3242   b->cur=0;
3243   b->max=CMI_TMP_BUF_MAX;
3246 void *CmiTmpAlloc(int size) {
3247   if (!CpvInitialized(CmiTmpBuf)) {
3248     return malloc(size);
3249   }
3250   else { /* regular case */
3251     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3252     void *t;
3253     if (b->cur+size>b->max) {
3254       if (b->max==0) /* We're just uninitialized */
3255         CmiTmpSetup(b);
3256       else /* We're really out of space! */
3257         return malloc(size);
3258     }
3259     t=b->buf+b->cur;
3260     b->cur+=size;
3261     return t;
3262   }
3264 void CmiTmpFree(void *t) {
3265   if (!CpvInitialized(CmiTmpBuf)) {
3266     free(t);
3267   }
3268   else { /* regular case */
3269     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3270     /* t should point into our temporary buffer: figure out where */
3271     int cur=((const char *)t)-b->buf;
3272     if (cur<0 || cur>b->max) {
3273       free(t);
3274     } else {
3275       b->cur=cur;
3276     }
3277   }
3280 void CmiTmpInit(char **argv) {
3281   CpvInitialize(CmiTmpBuf_t,CmiTmpBuf);
3282   /* Set up this processor's temporary buffer */
3283   CmiTmpSetup(&CpvAccess(CmiTmpBuf));
3286 /******************************************************************************
3288   Cross-platform directory creation
3290   ****************************************************************************/
3291 #ifdef _WIN32
3292 /* Windows directory creation: */
3293 #include <windows.h>
3295 void CmiMkdir(const char *dirName) {
3296         CreateDirectory(dirName,NULL);
3299 int CmiGetPageSize(void)
3301   SYSTEM_INFO system_info;
3302   GetSystemInfo(&system_info);
3303   return system_info.dwPageSize;
3305 #else
3306 /* UNIX directory creation */
3307 #include <unistd.h> 
3308 #include <sys/stat.h> /* from "mkdir" man page */
3309 #include <sys/types.h>
3311 void CmiMkdir(const char *dirName) {
3312         mkdir(dirName,0777);
3315 int CmiGetPageSize(void)
3317 #if CMK_HAS_GETPAGESIZE
3318   return getpagesize();
3319 #else
3320   return CMK_MEMORY_PAGESIZE;
3321 #endif
3324 #endif
3327 /******************************************************************************
3329   Multiple Send function                               
3331   ****************************************************************************/
3337 /****************************************************************************
3338 * DESCRIPTION : This function call allows the user to send multiple messages
3339 *               from one processor to another, all intended for differnet 
3340 *               handlers.
3342 *               Parameters :
3344 *               destPE, len, int sizes[0..len-1], char *messages[0..len-1]
3346 ****************************************************************************/
3347 /* Round up message size to the message granularity. 
3348    Does this by adding, then truncating.
3350 static int roundUpSize(unsigned int s) {
3351   return (int)((s+sizeof(double)-1)&~(sizeof(double)-1));
3353 /* Return the amount of message padding required for a message
3354    with this many user bytes. 
3355  */
3356 static int paddingSize(unsigned int s) {
3357   return roundUpSize(s)-s;
3360 /* Message header for a bundle of multiple-sent messages */
3361 typedef struct {
3362   char convHeader[CmiMsgHeaderSizeBytes];
3363   int nMessages; /* Number of distinct messages bundled below. */
3364   double pad; /* To align the first message, which follows this header */
3365 } CmiMultipleSendHeader;
3367 #if CMK_USE_IBVERBS | CMK_USE_IBUD
3368 /* given a pointer to a multisend message clean up the metadata */
3370 void infi_freeMultipleSend(void *msgWhole)
3372   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3373   double pad=((CmiMultipleSendHeader *)msgWhole)->pad;
3374   int offset=sizeof(CmiMultipleSendHeader);
3375   int m;
3376   void *thisMsg=NULL;
3377   if (pad != 1234567.89) return;
3378   for(m=0;m<len;m++)
3379     {
3380       /*unreg meta, free meta, move the ptr */
3381       /* note these weird little things are not pooled */
3382       /* do NOT free the message here, we are only a part of this buffer*/
3383       infiCmiChunkHeader *ch = (infiCmiChunkHeader *)((char *)msgWhole + offset);
3384       char *msg = (char *)msgWhole + offset + sizeof(infiCmiChunkHeader);
3385       int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3386       infi_unregAndFreeMeta(ch->metaData);
3387       offset+= sizeof(infiCmiChunkHeader) + msgSize;
3388     }
3390 #endif
3393 static void _CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[], int immed)
3395   CmiMultipleSendHeader header;
3396   int m; /* Outgoing message */
3398 #if CMK_USE_IBVERBS
3399   infiCmiChunkHeader *msgHdr;
3400 #else
3401   CmiChunkHeader *msgHdr; /* Chunk headers for each message */
3402 #endif
3403         
3404   double pad = 0; /* padding required */
3405   int vecLen; /* Number of pieces in outgoing message vector */
3406   int *vecSizes; /* Sizes of each piece we're sending out. */
3407   char **vecPtrs; /* Pointers to each piece we're sending out. */
3408   int vec; /* Entry we're currently filling out in above array */
3409         
3410 #if CMK_USE_IBVERBS
3411   msgHdr = (infiCmiChunkHeader *)CmiTmpAlloc(len * sizeof(infiCmiChunkHeader));
3412 #else
3413   msgHdr = (CmiChunkHeader *)CmiTmpAlloc(len * sizeof(CmiChunkHeader));
3414 #endif
3415         
3416   /* Allocate memory for the outgoing vector*/
3417   vecLen=1+3*len; /* Header and 3 parts per message */
3418   vecSizes = (int *)CmiTmpAlloc(vecLen * sizeof(int));
3419   vecPtrs = (char **)CmiTmpAlloc(vecLen * sizeof(char *));
3420   vec=0;
3421   
3422   /* Build the header */
3423   header.nMessages=len;
3424   CmiSetHandler(&header, CpvAccess(CmiMainHandlerIDP));
3425   header.pad = 1234567.89;
3426 #if CMK_IMMEDIATE_MSG
3427   if (immed) CmiBecomeImmediate(&header);
3428 #endif
3429   vecSizes[vec]=sizeof(header); vecPtrs[vec]=(char *)&header;
3430   vec++;
3432   /* Build an entry for each message: 
3433          | CmiChunkHeader | Message data | Message padding | ...next message entry ...
3434   */
3435   for (m=0;m<len;m++) {
3436 #if CMK_USE_IBVERBS
3437     msgHdr[m].chunkHeader.size=roundUpSize(sizes[m]); /* Size of message and padding */
3438     msgHdr[m].chunkHeader.setRef(0); /* Reference count will be filled out on receive side */
3439     msgHdr[m].metaData=NULL;
3440 #else
3441     msgHdr[m].size=roundUpSize(sizes[m]); /* Size of message and padding */
3442     msgHdr[m].setRef(0); /* Reference count will be filled out on receive side */
3443 #endif          
3444     
3445     /* First send the message's CmiChunkHeader (for use on receive side) */
3446 #if CMK_USE_IBVERBS
3447     vecSizes[vec]=sizeof(infiCmiChunkHeader);
3448 #else
3449     vecSizes[vec]=sizeof(CmiChunkHeader); 
3450 #endif          
3451                 vecPtrs[vec]=(char *)&msgHdr[m];
3452     vec++;
3453     
3454     /* Now send the actual message data */
3455     vecSizes[vec]=sizes[m]; vecPtrs[vec]=msgComps[m];
3456     vec++;
3457     
3458     /* Now send padding to align the next message on a double-boundary */
3459     vecSizes[vec]=paddingSize(sizes[m]); vecPtrs[vec]=(char *)&pad;
3460     vec++;
3461   }
3462   CmiAssert(vec==vecLen);
3463   
3464   CmiSyncVectorSend(destPE, vecLen, vecSizes, vecPtrs);
3465   
3466   CmiTmpFree(vecPtrs); /* CmiTmp: Be sure to throw away in opposite order of allocation */
3467   CmiTmpFree(vecSizes);
3468   CmiTmpFree(msgHdr);
3471 void CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3473   _CmiMultipleSend(destPE, len, sizes, msgComps, 0);
3476 void CmiMultipleIsend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3478   _CmiMultipleSend(destPE, len, sizes, msgComps, 1);
3481 /****************************************************************************
3482 * DESCRIPTION : This function initializes the main handler required for the
3483 *               CmiMultipleSend() function to work. 
3484 *               
3485 *               This function should be called once in any Converse program
3486 *               that uses CmiMultipleSend()
3488 ****************************************************************************/
3490 static void CmiMultiMsgHandler(char *msgWhole);
3492 void CmiInitMultipleSend(void)
3494   CpvInitialize(int,CmiMainHandlerIDP); 
3495   CpvAccess(CmiMainHandlerIDP) =
3496     CmiRegisterHandler((CmiHandler)CmiMultiMsgHandler);
3499 /****************************************************************************
3500 * DESCRIPTION : This function is the main handler that splits up the messages
3501 *               CmiMultipleSend() pastes together. 
3503 ****************************************************************************/
3505 static void CmiMultiMsgHandler(char *msgWhole)
3507   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3508   int offset=sizeof(CmiMultipleSendHeader);
3509   int m;
3510   for (m=0;m<len;m++) {
3511 #if CMK_USE_IBVERBS
3512     infiCmiChunkHeader *ch=(infiCmiChunkHeader *)(msgWhole+offset);
3513     char *msg=(msgWhole+offset+sizeof(infiCmiChunkHeader));
3514     int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3515     ch->chunkHeader.setRef(msgWhole-msg);
3516     ch->metaData =  registerMultiSendMesg(msg,msgSize);
3517 #else
3518     CmiChunkHeader *ch=(CmiChunkHeader *)(msgWhole+offset);
3519     char *msg=(msgWhole+offset+sizeof(CmiChunkHeader));
3520     int msgSize=ch->size; /* Size of user portion of message (plus padding at end) */
3521     ch->setRef(msgWhole-msg);
3522 #endif          
3523     /* Link new message to owner via a negative ref pointer */
3524     CmiReference(msg); /* Follows link & increases reference count of *msgWhole* */
3525     CmiSyncSendAndFree(CmiMyPe(), msgSize, msg);
3526 #if CMK_USE_IBVERBS
3527     offset+= sizeof(infiCmiChunkHeader) + msgSize;
3528 #else
3529     offset+= sizeof(CmiChunkHeader) + msgSize;
3530 #endif          
3531   }
3532   /* Release our reference to the whole message.  The message will
3533      only actually be deleted once all its sub-messages are free'd as well. */
3534   CmiFree(msgWhole);
3537 /****************************************************************************
3538 * Hypercube broadcast message passing.
3539 ****************************************************************************/
3541 int HypercubeGetBcastDestinations(int mype, int total_pes, int k, int *dest_pes) {
3542   int num_pes = 0;
3543   for ( ; k>=0; --k) {
3544     /* add the processor destination at level k if it exist */
3545     dest_pes[num_pes] = mype ^ (1<<k);
3546     if (dest_pes[num_pes] >= total_pes) {
3547       /* find the first proc in the other part of the current dimention */
3548       dest_pes[num_pes] &= (~0u)<<k;
3549       /* if the first proc there is over CmiNumPes() then there is no other
3550          dimension, otherwise if it is valid compute my correspondent in such
3551          a way to minimize the load for every processor */
3552       if (total_pes>dest_pes[num_pes]) dest_pes[num_pes] += (mype - (mype & ((~0u)<<k))) % (total_pes - dest_pes[num_pes]);
3553       }
3554     if (dest_pes[num_pes] < total_pes) {
3555       /* if the destination is in the acceptable range increment num_pes */
3556       ++num_pes;
3557     }
3558   }
3559   return num_pes;
3563 /****************************************************************************
3564 * DESCRIPTION : This function initializes the main handler required for the
3565 *               Immediate message
3566 *               
3567 *               This function should be called once in any Converse program
3569 ****************************************************************************/
3571 int _immediateLock = 0; /* if locked, all immediate message handling will be delayed. */
3572 int _immediateFlag = 0; /* if set, there is delayed immediate message. */
3574 CpvDeclare(int, CmiImmediateMsgHandlerIdx); /* Main handler that is run on every node */
3576 /* xdl is the real handler */
3577 static void CmiImmediateMsgHandler(char *msg)
3579   CmiSetHandler(msg, CmiGetXHandler(msg));
3580   CmiHandleMessage(msg);
3583 void CmiInitImmediateMsg(void)
3585   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
3586   CpvAccess(CmiImmediateMsgHandlerIdx) =
3587     CmiRegisterHandler((CmiHandler)CmiImmediateMsgHandler);
3590 /*#if !CMK_IMMEDIATE_MSG
3591 #if !CMK_MACHINE_PROGRESS_DEFINED
3592 void CmiProbeImmediateMsg()
3595 #endif
3596 #endif*/
3598 /******** Idle timeout module (+idletimeout=30) *********/
3600 typedef struct {
3601   int idle_timeout;/*Milliseconds to wait idle before aborting*/
3602   int is_idle;/*Boolean currently-idle flag*/
3603   int call_count;/*Number of timeout calls currently in flight*/
3604 } cmi_cpu_idlerec;
3606 static void on_timeout(cmi_cpu_idlerec *rec,double curWallTime)
3608   rec->call_count--;
3609   if(rec->call_count==0 && rec->is_idle==1) {
3610     CmiError("Idle time on PE %d exceeded specified timeout.\n", CmiMyPe());
3611     CmiAbort("Exiting.\n");
3612   }
3614 static void on_idle(cmi_cpu_idlerec *rec,double curWallTime)
3616   CcdCallFnAfter((CcdVoidFn)on_timeout, rec, rec->idle_timeout);
3617   rec->call_count++; /*Keeps track of overlapping timeout calls.*/  
3618   rec->is_idle = 1;
3620 static void on_busy(cmi_cpu_idlerec *rec,double curWallTime)
3622   rec->is_idle = 0;
3624 static void CIdleTimeoutInit(char **argv)
3626   int idle_timeout=0; /*Seconds to wait*/
3627   CmiGetArgIntDesc(argv,"+idle-timeout",&idle_timeout,"Abort if idle for this many seconds");
3628   if(idle_timeout != 0) {
3629     cmi_cpu_idlerec *rec=(cmi_cpu_idlerec *)malloc(sizeof(cmi_cpu_idlerec));
3630     _MEMCHECK(rec);
3631     rec->idle_timeout=idle_timeout*1000;
3632     rec->is_idle=0;
3633     rec->call_count=0;
3634     CcdCallOnCondition(CcdPROCESSOR_BEGIN_IDLE, (CcdVoidFn)on_idle, rec);
3635     CcdCallOnCondition(CcdPROCESSOR_BEGIN_BUSY, (CcdVoidFn)on_busy, rec);
3636   }
3639 /*****************************************************************************
3641  * Converse Initialization
3643  *****************************************************************************/
3645 CMI_EXTERNC void CrnInit(void);
3646 CMI_EXTERNC void CmiIsomallocInit(char **argv);
3647 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3648 void CmiIOInit(char **argv);
3649 #endif
3651 /* defined in cpuaffinity.c */
3652 CMI_EXTERNC void CmiInitCPUAffinityUtil(void);
3654 static void CmiProcessPriority(char **argv)
3656   int dummy, nicelevel=-100;      /* process priority */
3657   CmiGetArgIntDesc(argv,"+nice",&nicelevel,"Set the process priority level");
3658   /* ignore others */
3659   while (CmiGetArgIntDesc(argv,"+nice",&dummy,"Set the process priority level"));
3660   /* call setpriority once on each process to set process's priority */
3661   if (CmiMyRank() == 0 && nicelevel != -100)  {
3662 #ifndef _WIN32
3663     if (0!=setpriority(PRIO_PROCESS, 0, nicelevel))  {
3664       CmiPrintf("[%d] setpriority failed with value %d. \n", CmiMyPe(), nicelevel);
3665       perror("setpriority");
3666       CmiAbort("setpriority failed.");
3667     }
3668     else
3669       CmiPrintf("[%d] Charm++: setpriority %d\n", CmiMyPe(), nicelevel);
3670 #else
3671     HANDLE hProcess = GetCurrentProcess();
3672     DWORD dwPriorityClass = NORMAL_PRIORITY_CLASS;
3673     const char *prio_str = "NORMAL_PRIORITY_CLASS";
3674     BOOL status;
3675     /*
3676        <-20:      real time
3677        -20--10:   high 
3678        -10-0:     above normal
3679        0:         normal
3680        0-10:      below normal
3681        10-:       idle
3682     */
3683     if (0) ;
3684 #ifdef BELOW_NORMAL_PRIORITY_CLASS
3685     else if (nicelevel<10 && nicelevel>0) {
3686       dwPriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
3687       prio_str = "BELOW_NORMAL_PRIORITY_CLASS";
3688     }
3689 #endif
3690     else if (nicelevel>0) {
3691       dwPriorityClass = IDLE_PRIORITY_CLASS;
3692       prio_str = "IDLE_PRIORITY_CLASS";
3693     }
3694     else if (nicelevel<=-20) {
3695       dwPriorityClass = REALTIME_PRIORITY_CLASS;
3696       prio_str = "REALTIME_PRIORITY_CLASS";
3697     }
3698 #ifdef ABOVE_NORMAL_PRIORITY_CLASS
3699     else if (nicelevel>-10 && nicelevel<0) {
3700       dwPriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
3701       prio_str = "ABOVE_NORMAL_PRIORITY_CLASS";
3702     }
3703 #endif
3704     else if (nicelevel<0) {
3705       dwPriorityClass = HIGH_PRIORITY_CLASS;
3706       prio_str = "HIGH_PRIORITY_CLASS";
3707     }
3708     status = SetPriorityClass(hProcess, dwPriorityClass);
3709     if (!status)  {
3710         int err=GetLastError();
3711         CmiPrintf("SetPriorityClass failed errno=%d, WSAerr=%d\n",errno, err);
3712         CmiAbort("SetPriorityClass failed.");
3713     }
3714     else
3715       CmiPrintf("[%d] Charm++: setpriority %s\n", CmiMyPe(), prio_str);
3716 #endif
3717   }
3720 void CommunicationServerInit(void)
3722 #if CMK_IMMEDIATE_MSG
3723 #if CMI_QD
3724   CQdCpvInit();
3725 #endif
3726   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
3727 #endif
3731 static int testEndian(void)
3733         int test=0x1c;
3734         unsigned char *c=(unsigned char *)&test;
3735         if (c[sizeof(int)-1]==0x1c)
3736                 /* Macintosh and most workstations are big-endian */
3737                 return 1;   /* Big-endian machine */
3738         if (c[0]==0x1c)
3739                 /* Intel x86 PC's, and DEC VAX are little-endian */
3740                 return 0;  /* Little-endian machine */
3741         return -2;  /*Unknown integer type */
3744 int CmiEndianness(void)
3746   static int _cmi_endianness = -1;
3747   if (_cmi_endianness == -1) _cmi_endianness = testEndian();
3748   CmiAssert(_cmi_endianness != -2);
3749   return  _cmi_endianness;
3752 #if CMK_USE_TSAN
3753 /* This fixes bug #713, which is caused by tsan deadlocking inside
3754  * a 'write' syscall inside a mutex. */
3755 static void checkTSanOptions(void)
3757   char *env = getenv("TSAN_OPTIONS");
3759   if (!env ||
3760       !strstr(env, "log_path=") ||
3761       strstr(env, "log_path=stdout") ||
3762       strstr(env, "log_path=stderr")) {
3763     CmiAbort("TSAN output must be redirected to disk.\n"
3764              "Run this program with TSAN_OPTIONS=\"log_path=filename\"");
3765   }
3767 #endif
3769 #if CMK_CCS_AVAILABLE
3770 CMI_EXTERNC_VARIABLE int ccsRunning;
3771 int ccsRunning;
3772 #endif
3774 CMI_EXTERNC_VARIABLE int quietModeRequested;
3775 int quietModeRequested;  // user has requested quiet mode
3776 CMI_EXTERNC_VARIABLE int quietMode;
3777 int quietMode; // quiet mode active (CmiPrintf's are disabled)
3778 CmiSpanningTreeInfo* _topoTree = NULL;
3781   Main Converse initialization routine.  This routine is 
3782   called by the machine file (machine.C) to set up Converse.
3783   It's "Common" because it's shared by all the machine.C files.
3784   
3785   The main task of this routine is to set up all the Cpv's
3786   (message queues, handler tables, etc.) used during main execution.
3787   
3788   On SMP versions, this initialization routine is called by 
3789   *all* processors of a node simultaniously.  It's *also* called
3790   by the communication thread, which is rather strange but needed
3791   for immediate messages.  Each call to this routine expects a 
3792   different copy of the argv arguments, so use CmiCopyArgs(argv).
3793   
3794   Requires:
3795     - A working network layer.
3796     - Working Cpv's and CmiNodeBarrier.
3797     - CthInit to already have been called.  CthInit is called
3798       from the machine layer directly, because some machine layers
3799       (like uth) use Converse threads internally.
3801   Initialization is somewhat subtle, in that various modules
3802   won't work properly until they're initialized.  For example,
3803   nobody can register handlers before calling CmiHandlerInit.
3805 CMI_EXTERNC
3806 void ConverseCommonInit(char **argv)
3808   CpvInitialize(int, _urgentSend);
3809   CpvAccess(_urgentSend) = 0;
3810   CpvInitialize(int,interopExitFlag);
3811   CpvAccess(interopExitFlag) = 0;
3813   CpvInitialize(int,_curRestartPhase);
3814   CpvAccess(_curRestartPhase)=1;
3815   CmiArgInit(argv);
3816   CmiMemoryInit(argv);
3817 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3818   CmiIOInit(argv);
3819 #endif
3820   if (CmiMyPe() == 0)
3821       CmiPrintf("Converse/Charm++ Commit ID: %s\n", CmiCommitID);
3823   CpvInitialize(int, cmiMyPeIdle);
3824   CpvAccess(cmiMyPeIdle) = 0;
3826 #if CONVERSE_POOL
3827   CmiPoolAllocInit(30);  
3828 #endif
3829   CmiTmpInit(argv);
3830   CmiTimerInit(argv);
3831   CstatsInit(argv);
3832   CmiInitCPUAffinityUtil();
3834   CcdModuleInit(argv);
3835   CmiHandlerInit();
3836   CmiReductionsInit();
3837   CIdleTimeoutInit(argv);
3838   
3839 #if CMK_SHARED_VARS_POSIX_THREADS_SMP /*Used by the netlrts-*-smp and multicore versions*/
3840   if(CmiGetArgFlagDesc(argv, "+CmiSpinOnIdle", "Force the runtime system to spin on message reception when idle, rather than sleeping")) {
3841     if(CmiMyRank() == 0) _Cmi_forceSpinOnIdle = 1;
3842   }
3843   if(CmiGetArgFlagDesc(argv, "+CmiSleepOnIdle", "Force the runtime system to sleep when idle, rather than spinning on message reception")) {
3844     if(CmiMyRank() == 0) _Cmi_sleepOnIdle = 1;
3845   }
3846   if(CmiGetArgFlagDesc(argv,"+CmiNoProcForComThread","Is there an extra processor for the communication thread on each node(only for netlrts-smp-*) ?")){
3847     if (CmiMyPe() == 0) {
3848       CmiPrintf("Charm++> Note: The option +CmiNoProcForComThread has been superseded by +CmiSleepOnIdle\n");
3849     }
3850     if(CmiMyRank() == 0) _Cmi_sleepOnIdle=1;
3851   }
3852   if (_Cmi_sleepOnIdle && _Cmi_forceSpinOnIdle) {
3853     if(CmiMyRank() == 0) CmiAbort("The option +CmiSpinOnIdle is mutually exclusive with the options +CmiSleepOnIdle and +CmiNoProcForComThread");
3854   }
3855 #endif
3856         
3857 #if CMK_TRACE_ENABLED
3858   traceInit(argv);
3859 /*initTraceCore(argv);*/ /* projector */
3860 #endif
3861   CmiProcessPriority(argv);
3863 #if CMK_USE_TSAN
3864   checkTSanOptions();
3865 #endif
3867   CmiPersistentInit();
3868   CmiIsomallocInit(argv);
3869   // Initialize converse handlers for supporting generic Direct Nocopy API
3870   CmiOnesidedDirectInit();
3871   CmiDeliversInit();
3872   CsdInit(argv);
3873 #if CMK_CCS_AVAILABLE
3874   ccsRunning = 0;
3875   CcsInit(argv);
3876 #endif
3877   CpdInit();
3878   CthSchedInit();
3879   CmiGroupInit();
3880   CmiMulticastInit();
3881   CmiInitMultipleSend();
3882 #if CMI_QD
3883   CQdInit();
3884 #endif
3886   CrnInit();
3887   CmiInitImmediateMsg();
3888   CldModuleInit(argv);
3889   
3890 #if CMK_CELL
3891   void CmiInitCell();
3892   CmiInitCell();
3893 #endif
3895   /* main thread is suspendable */
3897   CthSetSuspendable(CthSelf(), 0);
3900 #if CMK_BIGSIM_CHARM
3901    /* have to initialize QD here instead of _initCharm */
3902   initQd(argv);
3903 #endif
3906 CMI_EXTERNC
3907 void ConverseCommonExit(void)
3909   CcsImpl_kill();
3911 #if CMK_TRACE_ENABLED
3912   traceClose();
3913 /*closeTraceCore();*/ /* projector */
3914 #endif
3916 #if CMI_IO_BUFFER_EXPLICIT
3917   CmiFlush(stdout);  /* end of program, always flush */
3918 #endif
3920 #if CMK_CELL
3921   CloseOffloadAPI();
3922 #endif
3924 #if CMK_CUDA
3925   // ensure all PEs have finished GPU work before destructing
3926   if(CmiMyRank() < CmiMyNodeSize()) {
3927     CmiNodeBarrier();
3928   }
3929   if (CmiMyRank() == 0) {
3930     exitHybridAPI();
3931   }
3932 #endif
3933   seedBalancerExit();
3934   EmergencyExit();
3938 #if CMK_CELL != 0
3940 extern void register_accel_spe_funcs(void);
3942 void CmiInitCell(void)
3944   // Create a unique string for each PPE to use for the timing
3945   //   data file's name
3946   char fileNameBuf[64];
3947   sprintf(fileNameBuf, "speTiming.%d", CmiMyPe());
3949   InitOffloadAPI(offloadCallback, NULL, NULL, fileNameBuf);
3950   //CcdCallOnConditionKeep(CcdPERIODIC, 
3951   //      (CcdVoidFn) OffloadAPIProgress, NULL);
3952   CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,
3953       (CcdVoidFn) OffloadAPIProgress, NULL);
3955   // Register accelerated entry methods on the PPE
3956   register_accel_spe_funcs();
3959 #include "cell-api.c"
3961 #endif
3963 /****
3964  * CW Lee - 9/14/2005
3965  * Added a mechanism to allow some control over machines with extremely
3966  * inefficient terminal IO mechanisms. Case in point: the XT3 has a
3967  * 20ms flush overhead along with about 25MB/s bandwidth for IO. This,
3968  * coupled with a default setup using unbuffered stdout introduced
3969  * severe overheads (and hence limiting scaling) for applications like 
3970  * NAMD.
3971  */
3972 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3973 void CmiIOInit(char **argv) {
3974   CpvInitialize(int, expIOFlushFlag);
3975 #if CMI_IO_BUFFER_EXPLICIT
3976   /* 
3977      Support for an explicit buffer only makes sense if the machine
3978      layer does not wish to make its own implementation.
3980      Placing this after CmiMemoryInit() means that CmiMemoryInit()
3981      MUST NOT make use of stdout if an explicit buffer is requested.
3983      The setvbuf function may only be used after opening a stream and
3984      before any other operations have been performed on it
3985   */
3986   CpvInitialize(char*, explicitIOBuffer);
3987   CpvInitialize(int, expIOBufferSize);
3988   if (!CmiGetArgIntDesc(argv,"+io_buffer_size", &CpvAccess(expIOBufferSize),
3989                         "Explicit IO Buffer Size")) {
3990     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3991   }
3992   if (CpvAccess(expIOBufferSize) <= 0) {
3993     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3994   }
3995   CpvAccess(explicitIOBuffer) = (char*)CmiAlloc(CpvAccess(expIOBufferSize)*
3996                                                 sizeof(char));
3997   if (setvbuf(stdout, CpvAccess(explicitIOBuffer), _IOFBF, 
3998               CpvAccess(expIOBufferSize))) {
3999     CmiAbort("Explicit IO Buffering failed\n");
4000   }
4001 #endif
4002 #if CMI_IO_FLUSH_USER
4003   /* system default to have user control flushing of IO */
4004   /* Now look for user override */
4005   CpvAccess(expIOFlushFlag) = !CmiGetArgFlagDesc(argv,"+io_flush_system",
4006                                                  "System Controls IO Flush");
4007 #else
4008   /* system default to have system handle IO flushing */
4009   /* Now look for user override */
4010   CpvAccess(expIOFlushFlag) = CmiGetArgFlagDesc(argv,"+io_flush_user",
4011                                                 "User Controls IO Flush");
4012 #endif
4014 #endif
4016 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
4018 void CmiPrintf(const char *format, ...)
4020   if (quietMode) return;
4021   CpdSystemEnter();
4022   {
4023   va_list args;
4024   va_start(args,format);
4025   vfprintf(stdout,format, args);
4026   if (CpvInitialized(expIOFlushFlag) && !CpvAccess(expIOFlushFlag)) {
4027     CmiFlush(stdout);
4028   }
4029   va_end(args);
4030 #if CMK_CCS_AVAILABLE && CMK_CMIPRINTF_IS_A_BUILTIN
4031   if (CpvAccess(cmiArgDebugFlag)) {
4032     va_start(args,format);
4033     print_node0(format, args);
4034     va_end(args);
4035   }
4036 #endif
4037   }
4038   CpdSystemExit();
4041 void CmiError(const char *format, ...)
4043   CpdSystemEnter();
4044   {
4045   va_list args;
4046   va_start(args,format);
4047   vfprintf(stderr,format, args);
4048   CmiFlush(stderr);  /* stderr is always flushed */
4049   va_end(args);
4050 #if CMK_CCS_AVAILABLE && CMK_CMIPRINTF_IS_A_BUILTIN
4051   if (CpvAccess(cmiArgDebugFlag)) {
4052     va_start(args,format);
4053     print_node0(format, args);
4054     va_end(args);
4055   }
4056 #endif
4057   }
4058   CpdSystemExit();
4061 #endif
4063 void __cmi_assert(const char *errmsg)
4065   CmiError("[%d] %s\n", CmiMyPe(), errmsg);
4066   CmiAbort(errmsg);
4069 char *CmiCopyMsg(char *msg, int len)
4071   char *copy = (char *)CmiAlloc(len);
4072   _MEMCHECK(copy);
4073   memcpy(copy, msg, len);
4074   return copy;
4077 CMI_EXTERNC
4078 unsigned char computeCheckSum(unsigned char *data, int len)
4080   int i;
4081   unsigned char ret = 0;
4082   for (i=0; i<len; i++) ret ^= (unsigned char)data[i];
4083   return ret;
4086 /* Flag for bigsim's out-of-core emulation */
4087 int _BgOutOfCoreFlag=0; /*indicate the type of memory operation (in or out) */
4088 int _BgInOutOfCoreMode=0; /*indicate whether the emulation is in the out-of-core emulation mode */
4090 #if !CMK_HAS_LOG2
4091 unsigned int CmiILog2(unsigned int val) {
4092   unsigned int log = 0u;
4093   if ( val != 0u ) {
4094       while ( val > (1u<<log) ) { log++; }
4095   }
4096   return log;
4098 double CmiLog2(double x) {
4099   return log(x)/log(2);
4101 #endif
4103 /* for bigsim */
4104 int CmiMyRank_(void)
4106   return CmiMyRank();
4109 double CmiReadSize(const char *str)
4111     double val;
4112     if (strpbrk(str,"Gg")) {
4113         //sscanf(str, "%llf", &val);
4114         //val = strtod(str, &p);
4115         val = atof(str);
4116         val *= 1024ll*1024*1024;
4117     }
4118     else if (strpbrk(str,"Mm")) {
4119         val = atof(str);
4120         val *= 1024*1024;
4121     }
4122     else if (strpbrk(str,"Kk")) {
4123         val = atof(str);
4124         val *= 1024;
4125     }
4126     else {
4127         val = atof(str);
4128     }
4129     return val;
4132 void CmiSetPeHelpsOtherThreads(int input) {
4133   CpvAccess(isHelperOn) = input;
4134   CmiMemoryWriteFence();
4137 /*@}*/