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
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
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".
45 @ingroup ConverseScheduler
56 #ifndef __STDC_FORMAT_MACROS
57 # define __STDC_FORMAT_MACROS
59 #ifndef __STDC_LIMIT_MACROS
60 # define __STDC_LIMIT_MACROS
66 #include <sys/resource.h>
68 #define snprintf _snprintf
72 #include "conv-trace.h"
73 #include "sockRoutines.h"
75 #if CMK_SMP && CMK_TASKQUEUE
76 #include "taskqueue.h"
77 #include "conv-taskQ.h"
80 #include "ccs-server.h"
81 #include "memory-isomalloc.h"
83 #include "converseEvents.h" /* projector */
84 #include "traceCoreCommon.h" /* projector */
85 #include "machineEvents.h" /* projector */
88 CMI_EXTERNC_VARIABLE const char * const CmiCommitID;
91 CMI_EXTERNC void initQd(char **argv);
101 void CmiPoolAllocInit(int numBins);
104 #if CMK_CONDS_USE_SPECIAL_CODE
105 CmiSwitchToPEFnPtr CmiSwitchToPE;
108 CpvExtern(int, _traceCoreOn); /* projector */
109 CMI_EXTERNC void CcdModuleInit(char **);
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>
119 #if CMK_TIMER_USE_TIMES
120 #include <sys/times.h>
125 #if CMK_TIMER_USE_GETRUSAGE
126 #include <sys/time.h>
127 #include <sys/resource.h>
130 #if CMK_TIMER_USE_RDTSC
135 #include <sys/time.h>
136 #include <sys/resource.h>
139 #ifdef CMK_TIMER_USE_WIN32API
142 #include <sys/types.h>
143 #include <sys/timeb.h>
146 #ifdef CMK_HAS_ASCTIME
150 #include "quiescence.h"
152 #if USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
156 #if CMK_TRACE_ENABLED
158 void traceAddThreadListeners(CthThread tid, struct envelope *env);
161 CMI_EXTERNC void seedBalancerExit(void);
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;
179 CpvDeclare(char *, _validProcessors);
182 CpvExtern(int, n_hapi_events);
184 void hapiPollEvents();
186 void exitHybridAPI();
189 /*****************************************************************************
191 * Unix Stub Functions
193 ****************************************************************************/
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);
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);
216 #if CMK_NODE_QUEUE_AVAILABLE
218 void *CmiGetNonLocalNodeQ();
221 CpvDeclare(Queue, CsdSchedQueue);
224 /* The Queue where the Prefetch Thread puts the messages from CsdSchedQueue */
225 CpvDeclare(Queue, CsdPrefetchQueue);
226 pthread_mutex_t prefetchLock;
229 #if CMK_NODE_QUEUE_AVAILABLE
230 CsvDeclare(Queue, CsdNodeQueue);
231 CsvDeclare(CmiNodeLock, CsdNodeQueueLock);
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
242 void *infi_CmiAlloc(int size);
244 void infi_CmiFree(void *ptr);
245 void infi_freeMultipleSend(void *ptr);
247 void infi_unregAndFreeMeta(void *ch);
250 #if CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
251 CMI_EXTERNC void * CmiAlloc_bgq (int size);
252 CMI_EXTERNC void CmiFree_bgq (void * buf);
255 #if CMK_SMP && CMK_PPC_ATOMIC_QUEUE
256 CMI_EXTERNC void * CmiAlloc_ppcq (int size);
257 CMI_EXTERNC void CmiFree_ppcq (void * buf);
260 #if CMK_GRID_QUEUE_AVAILABLE
261 CpvDeclare(void *, CkGridObject);
262 CpvDeclare(Queue, CsdGridQueue);
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*);
272 CpvStaticDeclare(int, cmiMyPeIdle);
273 #if CMK_SMP && CMK_TASKQUEUE
274 CsvDeclare(unsigned int, idleThreadsCnt);
275 CpvDeclare(Queue, CsdTaskQueue);
276 CpvDeclare(void *, CmiSuspendedTaskQueue);
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 *****************************************************************************/
296 int messageQueueOverflow;
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.
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 */
318 static int CLAlistLen=0;
319 static int CLAlistMax=0;
320 static CLA *CLAlist=NULL;
323 static void CmiAddCLA(const char *arg,const char *param,const char *desc) {
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 */
329 CmiPrintf(CLAformatString,arg,param,desc);
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. */
336 if (CLAlistLen>CLAlistMax) { /*Grow the CLA list */
337 CLAlistMax=16+2*CLAlistLen;
338 temp = (CLA *)realloc(CLAlist,sizeof(CLA)*CLAlistMax);
343 CmiAbort("Reallocation failed for CLAlist\n");
347 CLAlist[i].param=param;
348 CLAlist[i].desc=desc;
352 /** Print out the stored list of CLA's */
353 static void CmiPrintCLAs(void) {
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++) {
360 CmiPrintf(CLAformatString,c->arg,c->param,c->desc);
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.
369 void CmiArgInit(char **argv) {
372 for (i=0;argv[i]!=NULL;i++)
374 if (0==strcmp(argv[i],"-?") ||
375 0==strcmp(argv[i],"-h") ||
376 0==strcmp(argv[i],"--help"))
379 /* Don't delete arg: CmiDeleteArgs(&argv[i],1);
380 Leave it there for user program to see... */
384 if (CmiMyPe()==0) { /* Throw away list of stored CLA's */
385 CLAlistLen=CLAlistMax=0;
386 free(CLAlist); CLAlist=NULL;
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);
405 /** Count the number of non-NULL arguments in list*/
406 int CmiGetArgc(char **argv)
410 while (argv[i++]!=NULL)
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));
421 for (i=0;i<=argc;i++)
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)
434 while ((argv[i]=argv[i+k])!=NULL)
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)
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!");
454 CmiDeleteArgs(&argv[i],2);
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) {
468 CmiAddCLA(arg,"number",desc);
469 if (!CmiGetArgStringDesc(argv,arg,&number,NULL)) return 0;
470 if (1!=sscanf(number,"%lg",optDest)) return 0;
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)
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;
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;
500 case '0':case '1':case '2':case '3':case '4':
501 case '5':case '6':case '7':case '8':case '9':
503 opt=&argv[i][argLen]; nDel=1; break;
505 continue; /*False alarm-- skip it*/
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");
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");
518 CmiDeleteArgs(&argv[i],nDel);
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)
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;
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;
543 case '0':case '1':case '2':case '3':case '4':
544 case '5':case '6':case '7':case '8':case '9':
546 opt=&argv[i][argLen]; nDel=1; break;
548 continue; /*False alarm-- skip it*/
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");
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");
561 CmiDeleteArgs(&argv[i],nDel);
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)
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);
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);
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. */
617 /* now *lParen=='(', so trim it*/
620 while (*rParen!=')') {
621 if (*rParen==0) return ret; /* No right parenthesis at all. */
624 /* now *rParen==')', so trim it*/
625 *rParen=trimname?0:' ';
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";
640 if (0==strncmp(name,"CthResume",9)) return "Resumed thread";
641 if (0==strncmp(name,"qt_args",7)) return "Converse thread";
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) {
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;
656 const char *trimmed=_implTrimParenthesis(names[i], 0);
657 const char *print=trimmed;
658 const char *sys=_implGetBacktraceSys(print);
660 CmiPrintf(" [%d] Charm++ Runtime: %s (%s)\n",i,sys,print);
661 break; /*Stop when we hit Charm++ runtime.*/
663 CmiPrintf(" [%d:%d] %s\n",CmiMyPe(),i,print);
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);
683 int CmiIsFortranLibraryCall(void) {
684 #if CMK_USE_BACKTRACE
688 CmiBacktraceRecord(stackPtrs,1,&nLevels);
691 char **names=CmiBacktraceLookup(stackPtrs,nLevels);
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
702 { /* CmiPrintf("[%d] NAME:%s\n", CmiMyPe(), trimmed); */
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)
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;
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;
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;
761 int CstatMemory(int i)
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);
797 memcpy(nu, tab, bytes);
799 memset(((char *)nu)+bytes, 0, (newbytes-bytes));
801 CpvAccess(CmiHandlerTable) = tab;
802 CpvAccess(CmiHandlerMax) = newmax;
805 void CmiAssignOnce(int* variable, int value) {
806 if (CmiMyRank() == 0) { *variable = value; }
810 void CmiNumberHandler(int n, CmiHandler h)
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!*/
818 void CmiNumberHandlerEx(int n, CmiHandlerEx h,void *userPtr) {
820 if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
821 tab = CpvAccess(CmiHandlerTable);
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
832 int CmiRegisterHandler(CmiHandler h)
834 int Count = CpvAccess(CmiHandlerCount);
835 CmiNumberHandler(Count, h);
836 CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
840 void CmiRegisterHandlerAssignOnce(CmiHandler h, int *index)
842 if (CmiMyRank() == 0) { *index = CmiRegisterHandler(h); }
843 else { CmiRegisterHandler(h); }
847 int CmiRegisterHandlerEx(CmiHandlerEx h,void *userPtr)
849 int Count = CpvAccess(CmiHandlerCount);
850 CmiNumberHandlerEx(Count, h, userPtr);
851 CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
855 void CmiRegisterHandlerExAssignOnce(CmiHandlerEx h, void *userPtr, int *index)
857 if (CmiMyRank() == 0) { *index = CmiRegisterHandlerEx(h, userPtr); }
858 else { CmiRegisterHandlerEx(h, userPtr); }
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;
871 int CmiRegisterHandlerGlobal(CmiHandler h)
873 int Global = CpvAccess(CmiHandlerGlobal);
875 CmiError("CmiRegisterHandlerGlobal must only be called on PE 0.\n");
876 CmiNumberHandler(Global, h);
877 CpvAccess(CmiHandlerGlobal) = Global+3;
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 /******************************************************************************
906 * Here are two possible implementations of CmiTimer. Some machines don't
907 * select either, and define the timer in machine.C instead.
909 *****************************************************************************/
913 char *CmiPrintDate(void)
919 local = localtime(&t);
920 return asctime(local);
925 char *CmiPrintDate(void)
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)
945 int CmiTimerAbsolute(void)
950 double CmiStartTimer(void)
955 double CmiInitTime(void)
957 return CpvAccess(inittime_wallclock);
960 void CmiTimerInit(char **argv)
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)
978 currenttime = (now - CpvAccess(inittime_wallclock)) * CpvAccess(clocktick);
979 return (currenttime);
982 double CmiCpuTimer(void)
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();
1001 #if CMK_TIMER_USE_GETRUSAGE
1004 # if CMK_HAS_RUSAGE_THREAD
1005 #define RUSAGE_WHO 1 /* RUSAGE_THREAD, only in latest Linux kernels */
1010 #define RUSAGE_WHO 0
1013 static double inittime_wallclock;
1014 CpvStaticDeclare(double, inittime_virtual);
1016 int CmiTimerIsSynchronized(void)
1021 int CmiTimerAbsolute(void)
1023 return _absoluteTime;
1026 double CmiStartTimer(void)
1031 double CmiInitTime(void)
1033 return inittime_wallclock;
1036 void CmiTimerInit(char **argv)
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 */
1044 /* try to synchronize calling barrier */
1049 if(CmiMyRank() == 0) /* initialize only once */
1051 inittime_wallclock = inithrc();
1053 CpvAccess(inittime_virtual) = inittime_wallclock;
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);
1064 /* CmiBarrierZero(); */
1068 double CmiCpuTimer(void)
1071 return CmiWallTimer();
1076 getrusage(RUSAGE_WHO, &ru);
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);
1081 return currenttime - CpvAccess(inittime_virtual);
1085 static double lastT = -1.0;
1087 double CmiWallTimer(void)
1090 currenttime = gethrctime();
1091 return _absoluteTime?currenttime+inittime_wallclock:currenttime;
1094 double CmiTimer(void)
1096 return CmiCpuTimer();
1101 #if CMK_TIMER_USE_RDTSC
1103 static double readMHz(void)
1109 CmiLock(_smp_mutex);
1110 fp = fopen("/proc/cpuinfo", "r");
1112 while(fgets(str, 1000, fp)!=0) {
1113 if(sscanf(str, "cpu MHz%[^:]",buf)==1)
1115 char *s = strchr(str, ':'); s=s+1;
1116 sscanf(s, "%lf", &x);
1118 CmiUnlock(_smp_mutex);
1122 CmiUnlock(_smp_mutex);
1123 CmiAbort("Cannot read CPU MHz from /proc/cpuinfo file.");
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)
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);
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);
1161 double CmiCpuTimer(void)
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);
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)
1185 int CmiTimerAbsolute(void)
1190 #include "hwi/include/bqc/A2_inlines.h"
1191 #include "spi/include/kernel/process.h"
1193 double CmiStartTimer(void)
1198 double CmiInitTime(void)
1200 return CpvAccess(inittime);
1203 void CmiTimerInit(char **argv)
1205 CpvInitialize(double, clocktick);
1206 CpvInitialize(unsigned long, inittime);
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 */
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();
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)
1258 int CmiTimerAbsolute(void)
1263 double CmiStartTimer(void)
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 */
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 */
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();
1327 #if CMK_TIMER_USE_WIN32API
1329 CpvStaticDeclare(double, inittime_wallclock);
1330 CpvStaticDeclare(double, inittime_virtual);
1332 double CmiStartTimer(void)
1337 int CmiTimerAbsolute(void)
1342 double CmiInitTime(void)
1344 return CpvAccess(inittime_wallclock);
1347 void CmiTimerInit(char **argv)
1352 CpvInitialize(double, inittime_wallclock);
1353 CpvInitialize(double, inittime_virtual);
1355 CpvAccess(inittime_wallclock) = tv.time*1.0 + tv.millitm*0.001;
1357 CpvAccess(inittime_virtual) = ((double) ru)/CLOCKS_PER_SEC;
1360 double CmiCpuTimer(void)
1366 currenttime = (double) ru/CLOCKS_PER_SEC;
1368 return currenttime - CpvAccess(inittime_virtual);
1371 double CmiWallTimer(void)
1377 currenttime = tv.time*1.0 + tv.millitm*0.001;
1379 return currenttime - CpvAccess(inittime_wallclock);
1383 double CmiTimer(void)
1385 return CmiCpuTimer();
1390 #if CMK_TIMER_USE_RTC
1392 static double clocktick;
1393 CpvStaticDeclare(long long, inittime_wallclock);
1395 double CmiStartTimer(void)
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)
1417 double CmiWallTimer(void)
1422 return (clocktick * (now - CpvAccess(inittime_wallclock)));
1425 double CmiCpuTimer(void)
1427 return CmiWallTimer();
1430 double CmiTimer(void)
1432 return CmiCpuTimer();
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)
1450 double CmiInitTime(void)
1452 return inittime_wallclock;
1455 void CmiTimerInit(char **argv)
1459 if (CmiMyRank() == 0) {
1460 read_wall_time(&inittime_wallclock, TIMEBASE_SZ);
1461 time_base_to_time(&inittime_wallclock, TIMEBASE_SZ);
1464 CpvInitialize(double, inittime_virtual);
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)
1476 double CmiWallTimer(void)
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;
1488 n_secs += 1000000000;
1490 curt = secs*1.0 + n_secs*1e-9;
1494 double CmiCpuTimer(void)
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();
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) {
1521 #if CMK_SIGNAL_USE_SIGACTION
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);
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);
1539 #if CMK_SIGNAL_USE_SIGACTION_WITH_RESTART
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);
1558 * @addtogroup ConverseScheduler
1562 /*****************************************************************************
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
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
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)
1604 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1605 _LOG_E_PROC_IDLE(); /* projector */
1607 #if CMK_SMP && CMK_TASKQUEUE
1608 if (CpvAccess(cmiMyPeIdle) !=1) {
1609 CpvAccess(cmiMyPeIdle) = 1;
1610 CmiMemoryAtomicIncrement(CsvAccess(idleThreadsCnt), memory_order_relaxed);
1613 CpvAccess(cmiMyPeIdle) = 1;
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 */
1628 #if CMK_SMP && CMK_TASKQUEUE
1629 if (CpvAccess(cmiMyPeIdle) != 0){
1630 CpvAccess(cmiMyPeIdle) = 0;
1631 CmiMemoryAtomicDecrement(CsvAccess(idleThreadsCnt), memory_order_relaxed);
1634 CpvAccess(cmiMyPeIdle) = 0;
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++;
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 */
1657 /* if((!CpvAccess(_validProcessors)[CmiMyPe()]) && handler != _exitHandlerIdx){
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");
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");
1673 (h->hdlr)(msg,h->userPtr);
1674 #if CMK_TRACE_ENABLED
1675 /* setMemoryStatus(0) */ /* charmdebug */
1676 //_LOG_E_HANDLER_END(handlerIdx); /* projector */
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);
1695 void CsdSchedulerState_new(CsdSchedulerState_t *s)
1697 #if CMK_OBJECT_QUEUE_AVAILABLE
1698 s->objQ=CpvAccess(CsdObjQueue);
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);
1707 #if CMK_GRID_QUEUE_AVAILABLE
1708 s->gridQ=CpvAccess(CsdGridQueue);
1710 #if CMK_SMP && CMK_TASKQUEUE
1711 s->taskQ = CpvAccess(CsdTaskQueue);
1712 s->suspendedTaskQ = CpvAccess(CmiSuspendedTaskQueue);
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
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
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
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.
1767 void *CsdNextMessage(CsdSchedulerState_t *s) {
1769 if((*(s->localCounter))-- >0)
1771 /* This avoids a race condition with migration detected by megatest*/
1772 msg=CdsFifo_Dequeue(s->localQ);
1776 CpvAccess(cQdState)->mProcessed++;
1780 CqsDequeue(s->schedQ,(void **)&msg);
1781 if (msg!=NULL) return msg;
1784 *(s->localCounter)=CsdLocalMax;
1785 if ( NULL!=(msg=CmiGetNonLocal()) ||
1786 NULL!=(msg=CdsFifo_Dequeue(s->localQ)) ) {
1788 CpvAccess(cQdState)->mProcessed++;
1792 #if CMK_GRID_QUEUE_AVAILABLE
1793 /*#warning "CsdNextMessage: CMK_GRID_QUEUE_AVAILABLE" */
1794 CqsDequeue (s->gridQ, (void **) &msg);
1799 #if CMK_SMP && CMK_TASKQUEUE
1801 msg = CmiSuspendedTaskPop();
1806 msg = TaskQueuePop((TaskQueue)s->taskQ);
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;
1826 #if CMK_OBJECT_QUEUE_AVAILABLE
1827 /*#warning "CsdNextMessage: CMK_OBJECT_QUEUE_AVAILABLE" */
1828 if (NULL!=(msg=CdsFifo_Dequeue(s->objQ))) {
1833 CqsDequeue(s->schedQ,(void **)&msg);
1834 if (msg!=NULL) return msg;
1840 void *CsdNextLocalNodeMessage(CsdSchedulerState_t *s) {
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))
1847 CmiLock(s->nodeLock);
1848 CqsDequeue(s->nodeQ,(void **)&msg);
1849 CmiUnlock(s->nodeLock);
1850 if (msg!=NULL) return msg;
1857 int CsdScheduler(int maxmsgs)
1859 if (maxmsgs<0) CsdScheduleForever();
1860 else if (maxmsgs==0)
1862 else /*(maxmsgs>0)*/
1863 return CsdScheduleCount(maxmsgs);
1867 /*Declare the standard scheduler housekeeping*/
1868 #define SCHEDULE_TOP \
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 */
1884 #define SCHEDULE_IDLE \
1885 if (!isIdle) {isIdle=1;CsdBeginIdle();}\
1886 else CsdStillIdle();\
1887 if (*CsdStopFlag_ptr != cycle) {\
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)
1905 #define CMK_CELL_PROGRESS_FREQ 96 /* (MSG-Q Entries x1.5) */
1906 int progressCount = CMK_CELL_PROGRESS_FREQ;
1913 /* The interoperation will cost this little overhead in scheduling */
1914 if(CharmLibInterOperate) {
1915 if(CpvAccess(interopExitFlag)) {
1916 CpvAccess(interopExitFlag) = 0;
1922 // check if any GPU work needs to be processed
1923 if (CpvAccess(n_hapi_events) > 0) {
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();}
1935 if (progressCount <= 0) {
1936 /*OffloadAPIProgress();*/
1937 machine_OffloadAPIProgress();
1938 progressCount = CMK_CELL_PROGRESS_FREQ;
1942 } else { /*No message available-- go (or remain) idle*/
1946 /*OffloadAPIProgress();*/
1947 machine_OffloadAPIProgress();
1948 progressCount = CMK_CELL_PROGRESS_FREQ;
1951 #if !CSD_NO_PERIODIC
1956 int CsdScheduleCount(int maxmsgs)
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();}
1968 if (maxmsgs==0) break;
1969 } else { /*No message available-- go (or remain) idle*/
1972 #if !CSD_NO_PERIODIC
1979 void CsdSchedulePoll(void)
1984 #if !CSD_NO_PERIODIC
1987 /*CmiMachineProgressImpl(); ??? */
1988 if (NULL!=(msg = CsdNextMessage(&state)))
1996 void CsdScheduleNodePoll(void)
2002 /*CmiMachineProgressImpl(); ??? */
2003 if (NULL!=(msg = CsdNextLocalNodeMessage(&state)))
2011 void CmiDeliverSpecificMsg(int handler)
2014 void *localqueue = CpvAccess(CmiLocalQueue);
2018 #if !CSD_NO_PERIODIC
2022 if (side) msg = (int *)CmiGetNonLocal();
2023 else msg = (int *)CdsFifo_Dequeue(localqueue);
2025 if (CmiGetHandler(msg)==handler) {
2027 CpvAccess(cQdState)->mProcessed++;
2029 CmiHandleMessage(msg);
2032 CdsFifo_Enqueue(localqueue, msg);
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);
2070 CpvDeclare (int, CthResumeStealableThreadIdx);
2071 CpvDeclare (int, CthResumeSuspendedStealableThreadIdx);
2074 void CthStandinCode(void *arg)
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);
2093 CpvAccess(CthSleepingStandins) = CthGetNext(succ);
2095 succ = CthCreate(CthStandinCode, 0, 256000);
2096 CthSetStrategy(succ,
2097 CthEnqueueSchedulingThread,
2098 CthSuspendSchedulingThread);
2101 CpvAccess(CthSchedulingThread) = succ;
2105 /* Notice: For changes to the following function, make sure the function CthResumeNormalThreadDebug is also kept updated. */
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);
2119 #if CMK_TRACE_ENABLED
2120 #if ! CMK_TRACE_IN_CHARM
2121 if(CpvAccess(traceOn))
2123 /* if(CpvAccess(_traceCoreOn))
2124 resumeTraceCore();*/
2128 /* BIGSIM_OOC DEBUGGING
2129 CmiPrintf("In CthResumeNormalThread: ");
2130 CthPrintThdMagic(t);
2133 CthSetPrev(t, CthSelf());
2137 CthScheduledDecrement();
2138 CthSetPrev(CthSelf(), 0);
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);
2149 CthSetNext(me, CpvAccess(CthSleepingStandins));
2150 CpvAccess(CthSleepingStandins) = me;
2152 CpvAccess(CthSchedulingThread) = t;
2153 #if CMK_TRACE_ENABLED
2154 #if ! CMK_TRACE_IN_CHARM
2155 if(CpvAccess(traceOn))
2157 /* if(CpvAccess(_traceCoreOn))
2158 resumeTraceCore();*/
2162 CthSetPrev(t, CthSelf());
2166 CthScheduledDecrement();
2167 CthSetPrev(CthSelf(), 0);
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)
2188 CthEnqueueNormalThread,
2189 CthSuspendNormalThread);
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))
2205 CthSetPrev(t, CthSelf());
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);
2226 CmiSetHandler(token, CpvAccess(CthResumeSuspendedStealableThreadIdx));
2227 CmiSuspendedTaskEnqueue(targetRank ,(void*)token);
2231 void CthResumeSuspendedStealableThread(CthThreadToken *token) {
2232 CthEnqueueStealableThread(token, 0, 0, NULL);
2235 CthThread CthSuspendStealableThread()
2237 CthThread succ = CthGetNext(CthSelf());
2238 #if CMK_ERROR_CHECKING
2240 CmiAbort("successor is invalid\n");
2245 void CthSetStrategyWorkStealing(CthThread t)
2247 CthSetStrategy(t, CthEnqueueStealableThread, CthSuspendStealableThread);
2250 void CthSetStrategySuspendedWorkStealing(CthThread t)
2252 CthSetStrategy(t, CthEnqueueSuspendedStealableThread, CthSuspendStealableThread);
2258 CpvInitialize(CthThread, CthMainThread);
2259 CpvInitialize(CthThread, CthSchedulingThread);
2260 CpvInitialize(CthThread, CthSleepingStandins);
2261 CpvInitialize(int , CthResumeNormalThreadIdx);
2262 CpvInitialize(int , CthResumeSchedulingThreadIdx);
2264 CpvInitialize(int , CthResumeStealableThreadIdx);
2265 CpvInitialize(int , CthResumeSuspendedStealableThreadIdx);
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);
2279 CpvAccess(CthResumeStealableThreadIdx) = CmiRegisterHandler((CmiHandler)CthResumeStealableThread);
2280 CpvAccess(CthResumeSuspendedStealableThreadIdx) = CmiRegisterHandler((CmiHandler)CthResumeSuspendedStealableThread);
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;
2298 #if CMK_USE_STL_MSGQ
2299 if (CmiMyPe() == 0) CmiPrintf("Charm++> Using STL-based msgQ:\n");
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");
2307 #if CMK_OBJECT_QUEUE_AVAILABLE
2308 CpvInitialize(Queue, CsdObjQueue);
2309 CpvAccess(CsdObjQueue) = CdsFifo_Create();
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();
2319 CmiNodeAllBarrier();
2322 #if CMK_GRID_QUEUE_AVAILABLE
2323 CsvInitialize(Queue, CsdGridQueue);
2324 CpvAccess(CsdGridQueue) = CqsCreate();
2327 #if CMK_SMP && CMK_TASKQUEUE
2328 CpvInitialize(Queue, CsdTaskQueue);
2329 CpvInitialize(void *, CmiSuspendedTaskQueue);
2330 CpvAccess(CsdTaskQueue) = (Queue)TaskQueueCreate();
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
2348 /*****************************************************************************
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
2359 ****************************************************************************/
2361 #if CMK_VECTOR_SEND_USES_COMMON_CODE
2363 void CmiSyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2367 VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(infiCmiChunkHeader));
2369 VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(CmiChunkHeader));
2371 CmiSyncSendAndFree(destPE, total, mesg);
2374 CmiCommHandle CmiASyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2375 CmiSyncVectorSend(destPE, n, sizes, msgs);
2379 void CmiSyncVectorSendAndFree(int destPE, int n, int *sizes, char **msgs) {
2381 CmiSyncVectorSend(destPE, n, sizes, msgs);
2382 for(i=0;i<n;i++) CmiFree(msgs[i]);
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.
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.
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.
2406 * The destination handler for the the first form MUST be embedded into the
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.
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.
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.
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);
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");
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;
2463 memcpy(newred, red, sizeof(CmiReduction)+red->numChildren*sizeof(void*));
2467 red->numChildren = numChildren;
2468 red->remoteData = (char**)(red+1);
2469 CpvAccess(_reduce_info)[index] = 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);
2503 int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+values[1];
2504 values[0] = CmiGetDynamicReduction();
2505 CmiSetHandler(msg, CmiGetXHandler(msg));
2507 CmiSyncSendAndFree(pe, size, msg);
2509 CmiSyncBroadcastAllAndFree(size, msg);
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);
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);
2524 /* send the request to processor 0 */
2525 CmiSetHandler(msg, CpvAccess(CmiReductionDynamicRequestHandler));
2526 CmiSyncSendAndFree(0, size, msg);
2530 void CmiSendReduce(CmiReduction *red) {
2531 void *mergedData, *msg;
2533 if (!red->localContributed || red->numChildren != red->numRemoteReceived) return;
2534 mergedData = red->localData;
2535 msg_size = red->localSize;
2536 if (red->numChildren > 0) {
2538 if (red->ops.pupFn != NULL) {
2539 offset = CmiReservedHeaderSize;
2540 for (i=0; i<red->numChildren; ++i) red->remoteData[i] += offset;
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);
2545 /*CpvAccess(_reduce_num_children) = 0;*/
2546 /*CpvAccess(_reduce_received) = 0;*/
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;
2554 msg = CmiAlloc(msg_size);
2555 p = pup_new_toMem((void*)(((char*)msg)+CmiReservedHeaderSize));
2556 (red->ops.pupFn)(p, mergedData);
2558 if (red->ops.deleteFn != NULL) (red->ops.deleteFn)(red->localData);
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);
2565 (red->ops.destination)(msg);
2567 CmiClearReduction(red->seqID);
2570 void *CmiReduceMergeFn_random(int *size, void *data, void** remote, int n) {
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);*/
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;
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);*/
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()));
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;
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);*/
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()));
2662 CmiAssert(red->localContributed == 0);
2663 red->localContributed = 1;
2664 red->localData = data;
2666 for (myPos=0; myPos<npes; ++myPos) {
2667 if (pes[myPos] == CmiMyPe()) break;
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;
2682 void CmiGroupReduce(CmiGroup grp, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
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) {
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...");
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);
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())));
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);
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);*/
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) {
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 /*****************************************************************************
2776 ****************************************************************************/
2778 #if CMK_MULTICAST_DEF_USE_COMMON_CODE
2780 typedef struct GroupDef_s
2783 char core[CmiMsgHeaderSizeBytes];
2784 struct GroupDef_s *next;
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)++;
2815 len = sizeof(struct GroupDef_s)+(npes*sizeof(int));
2816 def = (GroupDef)CmiAlloc(len);
2819 for (i=0; i<npes; i++)
2820 def->pes[i] = pes[i];
2821 CmiSetHandler(def, CpvAccess(CmiGroupHandlerIndex));
2822 CmiSyncBroadcastAllAndFree(len, def);
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)) {
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");
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)
2868 #if CMK_BROADCAST_USE_CMIREFERENCE
2869 for(i=0;i<npes;i++) {
2870 if (pes[i] == CmiMyPe())
2871 CmiSyncSend(pes[i], len, msg);
2874 CmiSyncSendAndFree(pes[i], len, msg);
2878 for(i=0;i<npes;i++) {
2879 CmiSyncSend(pes[i], len, msg);
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
2895 CmiSyncSendAndFree(pes[0], len, msg);
2898 CmiSyncListSendFn(npes, pes, len, msg);
2902 for(i=0;i<npes-1;i++) {
2903 CmiSyncSend(pes[i], len, msg);
2906 CmiSyncSendAndFree(pes[npes-1], len, msg);
2914 #if CMK_MULTICAST_GROUP_USE_COMMON_CODE
2916 typedef struct MultiMsg_s
2918 char core[CmiMsgHeaderSizeBytes];
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);
2935 CmiSyncSendAndFree(CmiMyPe(), nlen, msg);
2942 if (msg->pos == -1) {
2944 CmiSyncSendAndFree(pes[0], nlen, msg);
2948 child1 = ((pos+1)<<1);
2950 if (child1 < npes) {
2952 CmiSyncSend(pes[child1], nlen, msg);
2954 if (child2 < npes) {
2956 CmiSyncSend(pes[child2], nlen, msg);
2958 if(olen < sizeof(struct MultiMsg_s)) {
2959 memcpy(msg, msg+1, olen);
2961 memcpy(msg, (((char*)msg)+olen), sizeof(struct MultiMsg_s));
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);
2979 memcpy(newmsg+1, msg+sizeof(struct MultiMsg_s), len-sizeof(struct MultiMsg_s));
2980 memcpy(((char *)newmsg+len), msg, sizeof(struct MultiMsg_s));
2982 newmsg->group = grp;
2983 newmsg->origlen = len;
2985 CmiSetHandler(newmsg, CpvAccess(CmiMulticastHandlerIndex));
2986 CmiMulticastDeliver(newmsg);
2989 void CmiFreeMulticastFn(CmiGroup grp, int len, char *msg)
2991 CmiSyncMulticastFn(grp, len, 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);
3009 extern void CmiMulticastInit(void);
3012 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
3013 extern void *arena_malloc(int size);
3014 extern void arena_free(void *blockPtr);
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)
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));
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));
3060 res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
3066 CpvAccess(MemoryUsage) += size+sizeof(CmiChunkHeader);
3067 CpvAccess(AllocCount)++;
3068 CpvAccess(BlocksAllocated)++;
3069 if (CpvAccess(MemoryUsage) > CpvAccess(HiWaterMark)) {
3070 CpvAccess(HiWaterMark) = CpvAccess(MemoryUsage);
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);
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);
3085 res+=sizeof(CmiChunkHeader);
3086 CmiAssert((intptr_t)res % ALIGN_BYTES == 0);
3088 SIZEFIELD(res)=size;
3089 REFFIELDSET(res, 1);
3093 void *CmiRdmaAlloc(int size) {
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));
3101 res = (char *)LrtsAlloc(size, sizeof(CmiChunkHeader));
3103 res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
3107 res+=sizeof(CmiChunkHeader);
3108 CmiAssert((intptr_t)res % ALIGN_BYTES == 0);
3110 SIZEFIELD(res)=size;
3111 REFFIELDSET(res, 1);
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);
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?");
3153 if(refCount==1) { /* This was the last reference to the block-- free it */
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)--;
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))
3171 infi_freeMultipleSend(parentBlk);
3174 infi_CmiFree(BLKSTART(parentBlk));
3175 #elif CMK_CONVERSE_UGNI || CMK_OFI
3176 LrtsFree(BLKSTART(parentBlk));
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));
3186 free_nomigrate(BLKSTART(parentBlk));
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?");
3199 if(refCount==1) { /* This was the last reference to the block-- free it */
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)--;
3208 #if CMK_CONVERSE_UGNI
3209 LrtsRdmaFree(BLKSTART(parentBlk));
3210 #elif CMK_USE_IBVERBS || CMK_USE_IBUD
3211 infi_CmiFree(BLKSTART(parentBlk));
3213 LrtsFree(BLKSTART(parentBlk));
3215 free_nomigrate(BLKSTART(parentBlk));
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
3229 ***************************************************************************/
3231 #define CMI_TMP_BUF_MAX 16*1024 /* Allow this much temporary storage. */
3234 char *buf; /* Start of temporary buffer */
3235 int cur; /* First unused location in temporary buffer */
3236 int max; /* Length of temporary buffer */
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);
3243 b->max=CMI_TMP_BUF_MAX;
3246 void *CmiTmpAlloc(int size) {
3247 if (!CpvInitialized(CmiTmpBuf)) {
3248 return malloc(size);
3250 else { /* regular case */
3251 CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3253 if (b->cur+size>b->max) {
3254 if (b->max==0) /* We're just uninitialized */
3256 else /* We're really out of space! */
3257 return malloc(size);
3264 void CmiTmpFree(void *t) {
3265 if (!CpvInitialized(CmiTmpBuf)) {
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) {
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 ****************************************************************************/
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;
3306 /* UNIX directory creation */
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();
3320 return CMK_MEMORY_PAGESIZE;
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
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.
3356 static int paddingSize(unsigned int s) {
3357 return roundUpSize(s)-s;
3360 /* Message header for a bundle of multiple-sent messages */
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);
3377 if (pad != 1234567.89) return;
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;
3393 static void _CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[], int immed)
3395 CmiMultipleSendHeader header;
3396 int m; /* Outgoing message */
3399 infiCmiChunkHeader *msgHdr;
3401 CmiChunkHeader *msgHdr; /* Chunk headers for each message */
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 */
3411 msgHdr = (infiCmiChunkHeader *)CmiTmpAlloc(len * sizeof(infiCmiChunkHeader));
3413 msgHdr = (CmiChunkHeader *)CmiTmpAlloc(len * sizeof(CmiChunkHeader));
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 *));
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);
3429 vecSizes[vec]=sizeof(header); vecPtrs[vec]=(char *)&header;
3432 /* Build an entry for each message:
3433 | CmiChunkHeader | Message data | Message padding | ...next message entry ...
3435 for (m=0;m<len;m++) {
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;
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 */
3445 /* First send the message's CmiChunkHeader (for use on receive side) */
3447 vecSizes[vec]=sizeof(infiCmiChunkHeader);
3449 vecSizes[vec]=sizeof(CmiChunkHeader);
3451 vecPtrs[vec]=(char *)&msgHdr[m];
3454 /* Now send the actual message data */
3455 vecSizes[vec]=sizes[m]; vecPtrs[vec]=msgComps[m];
3458 /* Now send padding to align the next message on a double-boundary */
3459 vecSizes[vec]=paddingSize(sizes[m]); vecPtrs[vec]=(char *)&pad;
3462 CmiAssert(vec==vecLen);
3464 CmiSyncVectorSend(destPE, vecLen, vecSizes, vecPtrs);
3466 CmiTmpFree(vecPtrs); /* CmiTmp: Be sure to throw away in opposite order of allocation */
3467 CmiTmpFree(vecSizes);
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.
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);
3510 for (m=0;m<len;m++) {
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);
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);
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);
3527 offset+= sizeof(infiCmiChunkHeader) + msgSize;
3529 offset+= sizeof(CmiChunkHeader) + msgSize;
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. */
3537 /****************************************************************************
3538 * Hypercube broadcast message passing.
3539 ****************************************************************************/
3541 int HypercubeGetBcastDestinations(int mype, int total_pes, int k, int *dest_pes) {
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]);
3554 if (dest_pes[num_pes] < total_pes) {
3555 /* if the destination is in the acceptable range increment num_pes */
3563 /****************************************************************************
3564 * DESCRIPTION : This function initializes the main handler required for the
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()
3598 /******** Idle timeout module (+idletimeout=30) *********/
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*/
3606 static void on_timeout(cmi_cpu_idlerec *rec,double curWallTime)
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");
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.*/
3620 static void on_busy(cmi_cpu_idlerec *rec,double curWallTime)
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));
3631 rec->idle_timeout=idle_timeout*1000;
3634 CcdCallOnCondition(CcdPROCESSOR_BEGIN_IDLE, (CcdVoidFn)on_idle, rec);
3635 CcdCallOnCondition(CcdPROCESSOR_BEGIN_BUSY, (CcdVoidFn)on_busy, rec);
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);
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");
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) {
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.");
3669 CmiPrintf("[%d] Charm++: setpriority %d\n", CmiMyPe(), nicelevel);
3671 HANDLE hProcess = GetCurrentProcess();
3672 DWORD dwPriorityClass = NORMAL_PRIORITY_CLASS;
3673 const char *prio_str = "NORMAL_PRIORITY_CLASS";
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";
3690 else if (nicelevel>0) {
3691 dwPriorityClass = IDLE_PRIORITY_CLASS;
3692 prio_str = "IDLE_PRIORITY_CLASS";
3694 else if (nicelevel<=-20) {
3695 dwPriorityClass = REALTIME_PRIORITY_CLASS;
3696 prio_str = "REALTIME_PRIORITY_CLASS";
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";
3704 else if (nicelevel<0) {
3705 dwPriorityClass = HIGH_PRIORITY_CLASS;
3706 prio_str = "HIGH_PRIORITY_CLASS";
3708 status = SetPriorityClass(hProcess, dwPriorityClass);
3710 int err=GetLastError();
3711 CmiPrintf("SetPriorityClass failed errno=%d, WSAerr=%d\n",errno, err);
3712 CmiAbort("SetPriorityClass failed.");
3715 CmiPrintf("[%d] Charm++: setpriority %s\n", CmiMyPe(), prio_str);
3720 void CommunicationServerInit(void)
3722 #if CMK_IMMEDIATE_MSG
3726 CpvInitialize(int,CmiImmediateMsgHandlerIdx);
3731 static int testEndian(void)
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 */
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;
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");
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\"");
3769 #if CMK_CCS_AVAILABLE
3770 CMI_EXTERNC_VARIABLE int ccsRunning;
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.
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.
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).
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.
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;
3816 CmiMemoryInit(argv);
3817 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3821 CmiPrintf("Converse/Charm++ Commit ID: %s\n", CmiCommitID);
3823 CpvInitialize(int, cmiMyPeIdle);
3824 CpvAccess(cmiMyPeIdle) = 0;
3827 CmiPoolAllocInit(30);
3832 CmiInitCPUAffinityUtil();
3834 CcdModuleInit(argv);
3836 CmiReductionsInit();
3837 CIdleTimeoutInit(argv);
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;
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;
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");
3850 if(CmiMyRank() == 0) _Cmi_sleepOnIdle=1;
3852 if (_Cmi_sleepOnIdle && _Cmi_forceSpinOnIdle) {
3853 if(CmiMyRank() == 0) CmiAbort("The option +CmiSpinOnIdle is mutually exclusive with the options +CmiSleepOnIdle and +CmiNoProcForComThread");
3857 #if CMK_TRACE_ENABLED
3859 /*initTraceCore(argv);*/ /* projector */
3861 CmiProcessPriority(argv);
3867 CmiPersistentInit();
3868 CmiIsomallocInit(argv);
3869 // Initialize converse handlers for supporting generic Direct Nocopy API
3870 CmiOnesidedDirectInit();
3873 #if CMK_CCS_AVAILABLE
3881 CmiInitMultipleSend();
3887 CmiInitImmediateMsg();
3888 CldModuleInit(argv);
3895 /* main thread is suspendable */
3897 CthSetSuspendable(CthSelf(), 0);
3900 #if CMK_BIGSIM_CHARM
3901 /* have to initialize QD here instead of _initCharm */
3907 void ConverseCommonExit(void)
3911 #if CMK_TRACE_ENABLED
3913 /*closeTraceCore();*/ /* projector */
3916 #if CMI_IO_BUFFER_EXPLICIT
3917 CmiFlush(stdout); /* end of program, always flush */
3925 // ensure all PEs have finished GPU work before destructing
3926 if(CmiMyRank() < CmiMyNodeSize()) {
3929 if (CmiMyRank() == 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
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"
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
3972 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3973 void CmiIOInit(char **argv) {
3974 CpvInitialize(int, expIOFlushFlag);
3975 #if CMI_IO_BUFFER_EXPLICIT
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
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;
3992 if (CpvAccess(expIOBufferSize) <= 0) {
3993 CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3995 CpvAccess(explicitIOBuffer) = (char*)CmiAlloc(CpvAccess(expIOBufferSize)*
3997 if (setvbuf(stdout, CpvAccess(explicitIOBuffer), _IOFBF,
3998 CpvAccess(expIOBufferSize))) {
3999 CmiAbort("Explicit IO Buffering failed\n");
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");
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");
4016 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
4018 void CmiPrintf(const char *format, ...)
4020 if (quietMode) return;
4024 va_start(args,format);
4025 vfprintf(stdout,format, args);
4026 if (CpvInitialized(expIOFlushFlag) && !CpvAccess(expIOFlushFlag)) {
4030 #if CMK_CCS_AVAILABLE && CMK_CMIPRINTF_IS_A_BUILTIN
4031 if (CpvAccess(cmiArgDebugFlag)) {
4032 va_start(args,format);
4033 print_node0(format, args);
4041 void CmiError(const char *format, ...)
4046 va_start(args,format);
4047 vfprintf(stderr,format, args);
4048 CmiFlush(stderr); /* stderr is always flushed */
4050 #if CMK_CCS_AVAILABLE && CMK_CMIPRINTF_IS_A_BUILTIN
4051 if (CpvAccess(cmiArgDebugFlag)) {
4052 va_start(args,format);
4053 print_node0(format, args);
4063 void __cmi_assert(const char *errmsg)
4065 CmiError("[%d] %s\n", CmiMyPe(), errmsg);
4069 char *CmiCopyMsg(char *msg, int len)
4071 char *copy = (char *)CmiAlloc(len);
4073 memcpy(copy, msg, len);
4078 unsigned char computeCheckSum(unsigned char *data, int len)
4081 unsigned char ret = 0;
4082 for (i=0; i<len; i++) ret ^= (unsigned char)data[i];
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 */
4091 unsigned int CmiILog2(unsigned int val) {
4092 unsigned int log = 0u;
4094 while ( val > (1u<<log) ) { log++; }
4098 double CmiLog2(double x) {
4099 return log(x)/log(2);
4104 int CmiMyRank_(void)
4109 double CmiReadSize(const char *str)
4112 if (strpbrk(str,"Gg")) {
4113 //sscanf(str, "%llf", &val);
4114 //val = strtod(str, &p);
4116 val *= 1024ll*1024*1024;
4118 else if (strpbrk(str,"Mm")) {
4122 else if (strpbrk(str,"Kk")) {
4132 void CmiSetPeHelpsOtherThreads(int input) {
4133 CpvAccess(isHelperOn) = input;
4134 CmiMemoryWriteFence();