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/platform/ppc.h>
1249 CpvStaticDeclare(uint64_t, inittime);
1250 CpvStaticDeclare(double, clocktick);
1252 int CmiTimerIsSynchronized(void)
1257 int CmiTimerAbsolute(void)
1262 double CmiStartTimer(void)
1267 double CmiInitTime(void)
1269 return CpvAccess(inittime);
1272 static inline uint64_t PPC64_TimeBase(void)
1274 register volatile uint64_t result;
1276 /* For 64-bit only */
1286 void CmiTimerInit(char **argv)
1288 CpvInitialize(double, clocktick);
1289 CpvInitialize(unsigned long, inittime);
1290 CpvAccess(clocktick) = 1.0 / ((double) __ppc_get_timebase_freq());
1292 /* try to synchronize calling barrier */
1298 CpvAccess(inittime) = PPC64_TimeBase ();
1301 double CmiWallTimer(void)
1303 uint64_t currenttime;
1304 currenttime = PPC64_TimeBase();
1305 return CpvAccess(clocktick)*(currenttime-CpvAccess(inittime));
1308 double CmiCpuTimer(void)
1310 return CmiWallTimer();
1313 double CmiTimer(void)
1315 return CmiWallTimer();
1321 #if CMK_TIMER_USE_WIN32API
1323 CpvStaticDeclare(double, inittime_wallclock);
1324 CpvStaticDeclare(double, inittime_virtual);
1326 double CmiStartTimer(void)
1331 int CmiTimerAbsolute(void)
1336 double CmiInitTime(void)
1338 return CpvAccess(inittime_wallclock);
1341 void CmiTimerInit(char **argv)
1346 CpvInitialize(double, inittime_wallclock);
1347 CpvInitialize(double, inittime_virtual);
1349 CpvAccess(inittime_wallclock) = tv.time*1.0 + tv.millitm*0.001;
1351 CpvAccess(inittime_virtual) = ((double) ru)/CLOCKS_PER_SEC;
1354 double CmiCpuTimer(void)
1360 currenttime = (double) ru/CLOCKS_PER_SEC;
1362 return currenttime - CpvAccess(inittime_virtual);
1365 double CmiWallTimer(void)
1371 currenttime = tv.time*1.0 + tv.millitm*0.001;
1373 return currenttime - CpvAccess(inittime_wallclock);
1377 double CmiTimer(void)
1379 return CmiCpuTimer();
1384 #if CMK_TIMER_USE_RTC
1386 static double clocktick;
1387 CpvStaticDeclare(long long, inittime_wallclock);
1389 double CmiStartTimer(void)
1394 double CmiInitTime(void)
1396 return CpvAccess(inittime_wallclock);
1399 void CmiTimerInit(char **argv)
1401 CpvInitialize(long long, inittime_wallclock);
1402 CpvAccess(inittime_wallclock) = _rtc();
1403 clocktick = 1.0 / (double)(sysconf(_SC_SV2_USER_TIME_RATE));
1406 int CmiTimerAbsolute(void)
1411 double CmiWallTimer(void)
1416 return (clocktick * (now - CpvAccess(inittime_wallclock)));
1419 double CmiCpuTimer(void)
1421 return CmiWallTimer();
1424 double CmiTimer(void)
1426 return CmiCpuTimer();
1431 #if CMK_TIMER_USE_AIX_READ_TIME
1433 #include <sys/time.h>
1435 static timebasestruct_t inittime_wallclock;
1436 static double clocktick;
1437 CpvStaticDeclare(double, inittime_virtual);
1439 double CmiStartTimer(void)
1444 double CmiInitTime(void)
1446 return inittime_wallclock;
1449 void CmiTimerInit(char **argv)
1453 if (CmiMyRank() == 0) {
1454 read_wall_time(&inittime_wallclock, TIMEBASE_SZ);
1455 time_base_to_time(&inittime_wallclock, TIMEBASE_SZ);
1458 CpvInitialize(double, inittime_virtual);
1460 CpvAccess(inittime_virtual) =
1461 (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1462 (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1465 int CmiTimerAbsolute(void)
1470 double CmiWallTimer(void)
1474 timebasestruct_t now;
1475 read_wall_time(&now, TIMEBASE_SZ);
1476 time_base_to_time(&now, TIMEBASE_SZ);
1478 secs = now.tb_high - inittime_wallclock.tb_high;
1479 n_secs = now.tb_low - inittime_wallclock.tb_low;
1482 n_secs += 1000000000;
1484 curt = secs*1.0 + n_secs*1e-9;
1488 double CmiCpuTimer(void)
1495 (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1496 (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1497 return currenttime - CpvAccess(inittime_virtual);
1500 double CmiTimer(void)
1502 return CmiWallTimer();
1507 #ifndef CMK_USE_SPECIAL_MESSAGE_QUEUE_CHECK
1508 /** Return 1 if our outgoing message queue
1509 for this node is longer than this many bytes. */
1510 int CmiLongSendQueue(int forNode,int longerThanBytes) {
1515 #if CMK_SIGNAL_USE_SIGACTION
1518 void CmiSignal(int sig1, int sig2, int sig3, void (*handler)(int))
1520 struct sigaction in, out ;
1521 in.sa_handler = handler;
1522 sigemptyset(&in.sa_mask);
1523 if (sig1) sigaddset(&in.sa_mask, sig1);
1524 if (sig2) sigaddset(&in.sa_mask, sig2);
1525 if (sig3) sigaddset(&in.sa_mask, sig3);
1527 if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1528 if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1529 if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1533 #if CMK_SIGNAL_USE_SIGACTION_WITH_RESTART
1536 void CmiSignal(int sig1, int sig2, int sig3, void (*handler)(int))
1538 struct sigaction in, out ;
1539 in.sa_handler = handler;
1540 sigemptyset(&in.sa_mask);
1541 if (sig1) sigaddset(&in.sa_mask, sig1);
1542 if (sig2) sigaddset(&in.sa_mask, sig2);
1543 if (sig3) sigaddset(&in.sa_mask, sig3);
1544 in.sa_flags = SA_RESTART;
1545 if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1546 if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1547 if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1552 * @addtogroup ConverseScheduler
1556 /*****************************************************************************
1558 * The following is the CsdScheduler function. A common
1559 * implementation is provided below. The machine layer can provide an
1560 * alternate implementation if it so desires.
1562 * void CmiDeliversInit()
1564 * - CmiInit promises to call this before calling CmiDeliverMsgs
1565 * or any of the other functions in this section.
1567 * int CmiDeliverMsgs(int maxmsgs)
1569 * - CmiDeliverMsgs will retrieve up to maxmsgs that were transmitted
1570 * with the Cmi, and will invoke their handlers. It does not wait
1571 * if no message is unavailable. Instead, it returns the quantity
1572 * (maxmsgs-delivered), where delivered is the number of messages it
1575 * void CmiDeliverSpecificMsg(int handlerno)
1577 * - Waits for a message with the specified handler to show up, then
1578 * invokes the message's handler. Note that unlike CmiDeliverMsgs,
1579 * This function _does_ wait.
1581 * For this common implementation to work, the machine layer must provide the
1584 * void *CmiGetNonLocal()
1586 * - returns a message just retrieved from some other PE, not from
1587 * local. If no such message exists, returns 0.
1589 * CpvExtern(CdsFifo, CmiLocalQueue);
1591 * - a FIFO queue containing all messages from the local processor.
1593 *****************************************************************************/
1595 void CsdBeginIdle(void)
1598 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1599 _LOG_E_PROC_IDLE(); /* projector */
1601 #if CMK_SMP && CMK_TASKQUEUE
1602 if (CpvAccess(cmiMyPeIdle) !=1) {
1603 CpvAccess(cmiMyPeIdle) = 1;
1604 CmiMemoryAtomicIncrement(CsvAccess(idleThreadsCnt), memory_order_relaxed);
1607 CpvAccess(cmiMyPeIdle) = 1;
1609 CcdRaiseCondition(CcdPROCESSOR_BEGIN_IDLE) ;
1612 void CsdStillIdle(void)
1614 CcdRaiseCondition(CcdPROCESSOR_STILL_IDLE);
1617 void CsdEndIdle(void)
1619 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1620 _LOG_E_PROC_BUSY(); /* projector */
1622 #if CMK_SMP && CMK_TASKQUEUE
1623 if (CpvAccess(cmiMyPeIdle) != 0){
1624 CpvAccess(cmiMyPeIdle) = 0;
1625 CmiMemoryAtomicDecrement(CsvAccess(idleThreadsCnt), memory_order_relaxed);
1628 CpvAccess(cmiMyPeIdle) = 0;
1630 CcdRaiseCondition(CcdPROCESSOR_BEGIN_BUSY) ;
1633 extern int _exitHandlerIdx;
1635 /** Takes a message and calls its corresponding handler. */
1636 void CmiHandleMessage(void *msg)
1638 /* this is wrong because it counts the Charm++ messages in sched queue
1639 CpvAccess(cQdState)->mProcessed++;
1642 CmiUInt2 handlerIdx=CmiGetHandler(msg); /* Save handler for use after msg is gone */
1643 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1644 _LOG_E_HANDLER_BEGIN(handlerIdx); /* projector */
1645 /* setMemoryStatus(1) */ /* charmdebug */
1651 /* if((!CpvAccess(_validProcessors)[CmiMyPe()]) && handler != _exitHandlerIdx){
1655 MESSAGE_PHASE_CHECK(msg)
1656 #if CMK_ERROR_CHECKING
1657 if (handlerIdx >= CpvAccess(CmiHandlerCount)) {
1658 CmiAbort("Msg handler does not exist, possible race condition during init\n");
1661 h=&CmiHandlerToInfo(handlerIdx);
1662 #if CMK_ERROR_CHECKING
1663 if (h->hdlr == NULL) {
1664 CmiAbort("Msg handler does not exist, possible race condition during init\n");
1667 (h->hdlr)(msg,h->userPtr);
1668 #if CMK_TRACE_ENABLED
1669 /* setMemoryStatus(0) */ /* charmdebug */
1670 //_LOG_E_HANDLER_END(handlerIdx); /* projector */
1674 #if CMK_CMIDELIVERS_USE_COMMON_CODE
1676 void CmiDeliversInit(void)
1680 int CmiDeliverMsgs(int maxmsgs)
1682 return CsdScheduler(maxmsgs);
1685 #if CMK_OBJECT_QUEUE_AVAILABLE
1686 CpvDeclare(void *, CsdObjQueue);
1689 void CsdSchedulerState_new(CsdSchedulerState_t *s)
1691 #if CMK_OBJECT_QUEUE_AVAILABLE
1692 s->objQ=CpvAccess(CsdObjQueue);
1694 s->localQ=CpvAccess(CmiLocalQueue);
1695 s->schedQ=CpvAccess(CsdSchedQueue);
1696 s->localCounter=&(CpvAccess(CsdLocalCounter));
1697 #if CMK_NODE_QUEUE_AVAILABLE
1698 s->nodeQ=CsvAccess(CsdNodeQueue);
1699 s->nodeLock=CsvAccess(CsdNodeQueueLock);
1701 #if CMK_GRID_QUEUE_AVAILABLE
1702 s->gridQ=CpvAccess(CsdGridQueue);
1704 #if CMK_SMP && CMK_TASKQUEUE
1705 s->taskQ = CpvAccess(CsdTaskQueue);
1706 s->suspendedTaskQ = CpvAccess(CmiSuspendedTaskQueue);
1711 /** Dequeue and return the next message from the unprocessed message queues.
1713 * This function encapsulates the multiple queues that exist for holding unprocessed
1714 * messages and the rules for the order in which to check them. There are five (5)
1715 * different Qs that converse uses to store and retrieve unprocessed messages. These
1717 * Q Purpose Type internal DeQ logic
1718 * -----------------------------------------------------------
1719 * - PE offnode pcQ FIFO
1720 * - PE onnode CkQ FIFO
1721 * - Node offnode pcQ FIFO
1722 * - Node onnode prioQ prio-based
1723 * - Scheduler prioQ prio-based
1725 * The PE queues hold messages that are destined for a specific PE. There is one such
1726 * queue for every PE within a charm node. The node queues hold messages that are
1727 * destined to that node. There is only one of each node queue within a charm node.
1728 * Finally there is also a charm++ message queue for each PE.
1730 * The offnode queues are meant for holding messages that arrive from outside the
1731 * node. The onnode queues hold messages that are generated within the same charm
1734 * The PE and node level offnode queues are accessed via functions CmiGetNonLocal()
1735 * and CmiGetNonLocalNodeQ(). These are implemented separately by each machine layer
1736 * and hide the implementation specifics for each layer.
1738 * The PE onnode queue is implemented as a FIFO CkQ and is initialized via a call to
1739 * CdsFifo_Create(). The node local queue and the scheduler queue are both priority
1740 * queues. They are initialized via calls to CqsCreate() which gives each of them
1741 * three separate internal queues for different priority ranges (-ve, 0 and +ve).
1742 * Access to these queues is via pointers stored in the struct CsdSchedulerState that
1743 * is passed into this function.
1745 * The order in which these queues are checked is described below. The function
1746 * proceeds to the next queue in the list only if it does not find any messages in
1747 * the current queue. The first message that is found is returned, terminating the
1749 * (1) offnode queue for this PE
1750 * (2) onnode queue for this PE
1751 * (3) offnode queue for this node
1752 * (4) highest priority msg from onnode queue or scheduler queue
1754 * @note: Across most (all?) machine layers, the two GetNonLocal functions simply
1755 * access (after observing adequate locking rigor) structs representing the scheduler
1756 * state, to dequeue from the queues stored within them. The structs (CmiStateStruct
1757 * and CmiNodeStateStruct) implement these queues as \ref Machine "pc (producer-consumer)
1758 * queues". The functions also perform other necessary actions like PumpMsgs() etc.
1761 void *CsdNextMessage(CsdSchedulerState_t *s) {
1763 if((*(s->localCounter))-- >0)
1765 /* This avoids a race condition with migration detected by megatest*/
1766 msg=CdsFifo_Dequeue(s->localQ);
1770 CpvAccess(cQdState)->mProcessed++;
1774 CqsDequeue(s->schedQ,(void **)&msg);
1775 if (msg!=NULL) return msg;
1778 *(s->localCounter)=CsdLocalMax;
1779 if ( NULL!=(msg=CmiGetNonLocal()) ||
1780 NULL!=(msg=CdsFifo_Dequeue(s->localQ)) ) {
1782 CpvAccess(cQdState)->mProcessed++;
1786 #if CMK_GRID_QUEUE_AVAILABLE
1787 /*#warning "CsdNextMessage: CMK_GRID_QUEUE_AVAILABLE" */
1788 CqsDequeue (s->gridQ, (void **) &msg);
1793 #if CMK_SMP && CMK_TASKQUEUE
1795 msg = CmiSuspendedTaskPop();
1800 msg = TaskQueuePop((TaskQueue)s->taskQ);
1805 #if CMK_NODE_QUEUE_AVAILABLE
1806 /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1807 if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;
1808 #if !CMK_NO_MSG_PRIOS
1809 if (!CqsEmpty(s->nodeQ)
1810 && CqsPrioGT(CqsGetPriority(s->schedQ),
1811 CqsGetPriority(s->nodeQ))) {
1812 if(CmiTryLock(s->nodeLock) == 0) {
1813 CqsDequeue(s->nodeQ,(void **)&msg);
1814 CmiUnlock(s->nodeLock);
1815 if (msg!=NULL) return msg;
1820 #if CMK_OBJECT_QUEUE_AVAILABLE
1821 /*#warning "CsdNextMessage: CMK_OBJECT_QUEUE_AVAILABLE" */
1822 if (NULL!=(msg=CdsFifo_Dequeue(s->objQ))) {
1827 CqsDequeue(s->schedQ,(void **)&msg);
1828 if (msg!=NULL) return msg;
1834 void *CsdNextLocalNodeMessage(CsdSchedulerState_t *s) {
1836 #if CMK_NODE_QUEUE_AVAILABLE
1837 /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1838 /*if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;*/
1839 if (!CqsEmpty(s->nodeQ))
1841 CmiLock(s->nodeLock);
1842 CqsDequeue(s->nodeQ,(void **)&msg);
1843 CmiUnlock(s->nodeLock);
1844 if (msg!=NULL) return msg;
1851 int CsdScheduler(int maxmsgs)
1853 if (maxmsgs<0) CsdScheduleForever();
1854 else if (maxmsgs==0)
1856 else /*(maxmsgs>0)*/
1857 return CsdScheduleCount(maxmsgs);
1861 /*Declare the standard scheduler housekeeping*/
1862 #define SCHEDULE_TOP \
1864 int *CsdStopFlag_ptr = &CpvAccess(CsdStopFlag); \
1865 int cycle = CpvAccess(CsdStopFlag); \
1866 CsdSchedulerState_t state;\
1867 CsdSchedulerState_new(&state);
1869 /*A message is available-- process it*/
1870 #define SCHEDULE_MESSAGE \
1871 CmiHandleMessage(msg);\
1872 if (*CsdStopFlag_ptr != cycle) break;
1874 /*No message available-- go (or remain) idle*/
1875 #if CSD_NO_IDLE_TRACING
1876 #define SCHEDULE_IDLE /* do nothing */
1878 #define SCHEDULE_IDLE \
1879 if (!isIdle) {isIdle=1;CsdBeginIdle();}\
1880 else CsdStillIdle();\
1881 if (*CsdStopFlag_ptr != cycle) {\
1890 extern void CkClearAllArrayElements(void);
1893 extern void machine_OffloadAPIProgress(void);
1895 /** The main scheduler loop that repeatedly executes messages from a queue, forever. */
1896 void CsdScheduleForever(void)
1899 #define CMK_CELL_PROGRESS_FREQ 96 /* (MSG-Q Entries x1.5) */
1900 int progressCount = CMK_CELL_PROGRESS_FREQ;
1907 /* The interoperation will cost this little overhead in scheduling */
1908 if(CharmLibInterOperate) {
1909 if(CpvAccess(interopExitFlag)) {
1910 CpvAccess(interopExitFlag) = 0;
1916 // check if any GPU work needs to be processed
1917 if (CpvAccess(n_hapi_events) > 0) {
1921 msg = CsdNextMessage(&state);
1922 if (msg!=NULL) { /*A message is available-- process it*/
1923 #if !CSD_NO_IDLE_TRACING
1924 if (isIdle) {isIdle=0;CsdEndIdle();}
1929 if (progressCount <= 0) {
1930 /*OffloadAPIProgress();*/
1931 machine_OffloadAPIProgress();
1932 progressCount = CMK_CELL_PROGRESS_FREQ;
1936 } else { /*No message available-- go (or remain) idle*/
1940 /*OffloadAPIProgress();*/
1941 machine_OffloadAPIProgress();
1942 progressCount = CMK_CELL_PROGRESS_FREQ;
1945 #if !CSD_NO_PERIODIC
1950 int CsdScheduleCount(int maxmsgs)
1955 msg = CsdNextMessage(&state);
1956 if (msg!=NULL) { /*A message is available-- process it*/
1957 #if !CSD_NO_IDLE_TRACING
1958 if (isIdle) {isIdle=0;CsdEndIdle();}
1962 if (maxmsgs==0) break;
1963 } else { /*No message available-- go (or remain) idle*/
1966 #if !CSD_NO_PERIODIC
1973 void CsdSchedulePoll(void)
1978 #if !CSD_NO_PERIODIC
1981 /*CmiMachineProgressImpl(); ??? */
1982 if (NULL!=(msg = CsdNextMessage(&state)))
1990 void CsdScheduleNodePoll(void)
1996 /*CmiMachineProgressImpl(); ??? */
1997 if (NULL!=(msg = CsdNextLocalNodeMessage(&state)))
2005 void CmiDeliverSpecificMsg(int handler)
2008 void *localqueue = CpvAccess(CmiLocalQueue);
2012 #if !CSD_NO_PERIODIC
2016 if (side) msg = (int *)CmiGetNonLocal();
2017 else msg = (int *)CdsFifo_Dequeue(localqueue);
2019 if (CmiGetHandler(msg)==handler) {
2021 CpvAccess(cQdState)->mProcessed++;
2023 CmiHandleMessage(msg);
2026 CdsFifo_Enqueue(localqueue, msg);
2032 #endif /* CMK_CMIDELIVERS_USE_COMMON_CODE */
2034 /***************************************************************************
2036 * Standin Schedulers.
2038 * We use the following strategy to make sure somebody's always running
2039 * the scheduler (CsdScheduler). Initially, we assume the main thread
2040 * is responsible for this. If the main thread blocks, we create a
2041 * "standin scheduler" thread to replace it. If the standin scheduler
2042 * blocks, we create another standin scheduler to replace that one,
2043 * ad infinitum. Collectively, the main thread and all the standin
2044 * schedulers are called "scheduling threads".
2046 * Suppose the main thread is blocked waiting for data, and a standin
2047 * scheduler is running instead. Suppose, then, that the data shows
2048 * up and the main thread is CthAwakened. This causes a token to be
2049 * pushed into the queue. When the standin pulls the token from the
2050 * queue and handles it, the standin goes to sleep, and control shifts
2051 * back to the main thread. In this way, unnecessary standins are put
2052 * back to sleep. These sleeping standins are stored on the
2053 * CthSleepingStandins list.
2055 ***************************************************************************/
2057 CpvStaticDeclare(CthThread, CthMainThread);
2058 CpvStaticDeclare(CthThread, CthSchedulingThread);
2059 CpvStaticDeclare(CthThread, CthSleepingStandins);
2060 CpvDeclare(int , CthResumeNormalThreadIdx);
2061 CpvStaticDeclare(int , CthResumeSchedulingThreadIdx);
2064 CpvDeclare (int, CthResumeStealableThreadIdx);
2065 CpvDeclare (int, CthResumeSuspendedStealableThreadIdx);
2068 void CthStandinCode(void *arg)
2073 /* this fix the function pointer for thread migration and pup */
2074 static CthThread CthSuspendNormalThread(void)
2076 return CpvAccess(CthSchedulingThread);
2079 void CthEnqueueSchedulingThread(CthThreadToken *token, int, int, unsigned int*);
2080 CthThread CthSuspendSchedulingThread(void);
2082 CthThread CthSuspendSchedulingThread(void)
2084 CthThread succ = CpvAccess(CthSleepingStandins);
2087 CpvAccess(CthSleepingStandins) = CthGetNext(succ);
2089 succ = CthCreate(CthStandinCode, 0, 256000);
2090 CthSetStrategy(succ,
2091 CthEnqueueSchedulingThread,
2092 CthSuspendSchedulingThread);
2095 CpvAccess(CthSchedulingThread) = succ;
2099 /* Notice: For changes to the following function, make sure the function CthResumeNormalThreadDebug is also kept updated. */
2101 void CthResumeNormalThread(CthThreadToken* token)
2103 CthThread t = token->thread;
2105 /* BIGSIM_OOC DEBUGGING
2106 CmiPrintf("Resume normal thread with token[%p] ==> thread[%p]\n", token, t);
2113 #if CMK_TRACE_ENABLED
2114 #if ! CMK_TRACE_IN_CHARM
2115 if(CpvAccess(traceOn))
2117 /* if(CpvAccess(_traceCoreOn))
2118 resumeTraceCore();*/
2122 /* BIGSIM_OOC DEBUGGING
2123 CmiPrintf("In CthResumeNormalThread: ");
2124 CthPrintThdMagic(t);
2127 CthSetPrev(t, CthSelf());
2131 CthScheduledDecrement();
2132 CthSetPrev(CthSelf(), 0);
2136 void CthResumeSchedulingThread(CthThreadToken *token)
2138 CthThread t = token->thread;
2139 CthThread me = CthSelf();
2140 if (me == CpvAccess(CthMainThread)) {
2141 CthEnqueueSchedulingThread(CthGetToken(me),CQS_QUEUEING_FIFO, 0, 0);
2143 CthSetNext(me, CpvAccess(CthSleepingStandins));
2144 CpvAccess(CthSleepingStandins) = me;
2146 CpvAccess(CthSchedulingThread) = t;
2147 #if CMK_TRACE_ENABLED
2148 #if ! CMK_TRACE_IN_CHARM
2149 if(CpvAccess(traceOn))
2151 /* if(CpvAccess(_traceCoreOn))
2152 resumeTraceCore();*/
2156 CthSetPrev(t, CthSelf());
2160 CthScheduledDecrement();
2161 CthSetPrev(CthSelf(), 0);
2165 void CthEnqueueNormalThread(CthThreadToken* token, int s,
2166 int pb,unsigned int *prio)
2168 CmiSetHandler(token, CpvAccess(CthResumeNormalThreadIdx));
2169 CsdEnqueueGeneral(token, s, pb, prio);
2172 void CthEnqueueSchedulingThread(CthThreadToken* token, int s,
2173 int pb,unsigned int *prio)
2175 CmiSetHandler(token, CpvAccess(CthResumeSchedulingThreadIdx));
2176 CsdEnqueueGeneral(token, s, pb, prio);
2179 void CthSetStrategyDefault(CthThread t)
2182 CthEnqueueNormalThread,
2183 CthSuspendNormalThread);
2186 /* Use work-stealing queue for scheduling threads
2187 We use the previous scheduling handlers while we push the message into the work-stealing queue
2189 void CthResumeStealableThread(CthThreadToken *token)
2191 CthThread t = token->thread;
2192 CthSetNext(t, CthSelf());
2193 #if CMK_TRACE_ENABLED
2194 #if ! CMK_TRACE_IN_CHARM
2195 if(CpvAccess(traceOn))
2199 CthSetPrev(t, CthSelf());
2201 CthScheduledDecrement();
2202 CthSetPrev(CthSelf(), 0);
2205 void CthEnqueueStealableThread(CthThreadToken * token, int s, int pb, unsigned int *prio) {
2206 CmiSetHandler(token, CpvAccess(CthResumeStealableThreadIdx));
2207 CsdTaskEnqueue((void*)token);
2211 void CthEnqueueSuspendedStealableThread(CthThreadToken * token, int s, int pb, unsigned int *prio)
2213 CthThread t = token->thread;
2214 int targetRank = CthGetThreadID(t)->id[2];
2215 CthSetStrategyWorkStealing(t);
2216 if (targetRank == CmiMyRank()) {
2217 CthEnqueueStealableThread(token,s,pb,prio);
2220 CmiSetHandler(token, CpvAccess(CthResumeSuspendedStealableThreadIdx));
2221 CmiSuspendedTaskEnqueue(targetRank ,(void*)token);
2225 void CthResumeSuspendedStealableThread(CthThreadToken *token) {
2226 CthEnqueueStealableThread(token, 0, 0, NULL);
2229 CthThread CthSuspendStealableThread()
2231 CthThread succ = CthGetNext(CthSelf());
2232 #if CMK_ERROR_CHECKING
2234 CmiAbort("successor is invalid\n");
2239 void CthSetStrategyWorkStealing(CthThread t)
2241 CthSetStrategy(t, CthEnqueueStealableThread, CthSuspendStealableThread);
2244 void CthSetStrategySuspendedWorkStealing(CthThread t)
2246 CthSetStrategy(t, CthEnqueueSuspendedStealableThread, CthSuspendStealableThread);
2252 CpvInitialize(CthThread, CthMainThread);
2253 CpvInitialize(CthThread, CthSchedulingThread);
2254 CpvInitialize(CthThread, CthSleepingStandins);
2255 CpvInitialize(int , CthResumeNormalThreadIdx);
2256 CpvInitialize(int , CthResumeSchedulingThreadIdx);
2258 CpvInitialize(int , CthResumeStealableThreadIdx);
2259 CpvInitialize(int , CthResumeSuspendedStealableThreadIdx);
2261 CpvAccess(CthMainThread) = CthSelf();
2262 CpvAccess(CthSchedulingThread) = CthSelf();
2263 CpvAccess(CthSleepingStandins) = 0;
2264 CpvAccess(CthResumeNormalThreadIdx) =
2265 CmiRegisterHandler((CmiHandler)CthResumeNormalThread);
2266 CpvAccess(CthResumeSchedulingThreadIdx) =
2267 CmiRegisterHandler((CmiHandler)CthResumeSchedulingThread);
2268 CthSetStrategy(CthSelf(),
2269 CthEnqueueSchedulingThread,
2270 CthSuspendSchedulingThread);
2273 CpvAccess(CthResumeStealableThreadIdx) = CmiRegisterHandler((CmiHandler)CthResumeStealableThread);
2274 CpvAccess(CthResumeSuspendedStealableThreadIdx) = CmiRegisterHandler((CmiHandler)CthResumeSuspendedStealableThread);
2278 void CsdInit(char **argv)
2280 CpvInitialize(Queue, CsdSchedQueue);
2281 CpvInitialize(int, CsdStopFlag);
2282 CpvInitialize(int, CsdLocalCounter);
2283 int argCsdLocalMax=CSD_LOCAL_MAX_DEFAULT;
2284 int argmaxset = CmiGetArgIntDesc(argv,"+csdLocalMax",&argCsdLocalMax,"Set the max number of local messages to process before forcing a check for remote messages.");
2285 if (CmiMyRank() == 0 ) CsdLocalMax = argCsdLocalMax;
2286 CpvAccess(CsdLocalCounter) = argCsdLocalMax;
2287 CpvAccess(CsdSchedQueue) = CqsCreate();
2288 #if CMK_SMP && CMK_TASKQUEUE
2289 CsvInitialize(unsigned int, idleThreadsCnt);
2290 CsvAccess(idleThreadsCnt) = 0;
2292 #if CMK_USE_STL_MSGQ
2293 if (CmiMyPe() == 0) CmiPrintf("Charm++> Using STL-based msgQ:\n");
2295 #if CMK_RANDOMIZED_MSGQ
2296 if (CmiMyPe() == 0) CmiPrintf("Charm++> Using randomized msgQ. Priorities will not be respected!\n");
2297 #elif CMK_NO_MSG_PRIOS
2298 if (CmiMyPe() == 0) CmiPrintf("Charm++> Message priorities have been turned off and will not be respected.\n");
2301 #if CMK_OBJECT_QUEUE_AVAILABLE
2302 CpvInitialize(Queue, CsdObjQueue);
2303 CpvAccess(CsdObjQueue) = CdsFifo_Create();
2306 #if CMK_NODE_QUEUE_AVAILABLE
2307 CsvInitialize(CmiLock, CsdNodeQueueLock);
2308 CsvInitialize(Queue, CsdNodeQueue);
2309 if (CmiMyRank() ==0) {
2310 CsvAccess(CsdNodeQueueLock) = CmiCreateLock();
2311 CsvAccess(CsdNodeQueue) = CqsCreate();
2313 CmiNodeAllBarrier();
2316 #if CMK_GRID_QUEUE_AVAILABLE
2317 CsvInitialize(Queue, CsdGridQueue);
2318 CpvAccess(CsdGridQueue) = CqsCreate();
2321 #if CMK_SMP && CMK_TASKQUEUE
2322 CpvInitialize(Queue, CsdTaskQueue);
2323 CpvInitialize(void *, CmiSuspendedTaskQueue);
2324 CpvAccess(CsdTaskQueue) = (Queue)TaskQueueCreate();
2326 CpvAccess(CsdStopFlag) = 0;
2327 CpvInitialize(int, isHelperOn);
2328 CpvAccess(isHelperOn) = 1; // Turn on this bit by default for threads to be used for CkLoop and OpenMP integration
2329 CmiMemoryWriteFence();
2330 #if CMK_SMP && CMK_TASKQUEUE
2342 /*****************************************************************************
2346 * The last parameter "system" is by default at zero, in which case the normal
2347 * messages are sent. If it is set to 1, the CmiChunkHeader prepended to every
2348 * CmiAllocced message will also be sent (except for the first one). Useful for
2349 * AllToAll communication, and other system features. If system is 1, also all
2350 * the messages will be padded to 8 bytes. Thus, the caller must be aware of
2353 ****************************************************************************/
2355 #if CMK_VECTOR_SEND_USES_COMMON_CODE
2357 void CmiSyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2361 VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(infiCmiChunkHeader));
2363 VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(CmiChunkHeader));
2365 CmiSyncSendAndFree(destPE, total, mesg);
2368 CmiCommHandle CmiASyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2369 CmiSyncVectorSend(destPE, n, sizes, msgs);
2373 void CmiSyncVectorSendAndFree(int destPE, int n, int *sizes, char **msgs) {
2375 CmiSyncVectorSend(destPE, n, sizes, msgs);
2376 for(i=0;i<n;i++) CmiFree(msgs[i]);
2383 /*****************************************************************************
2385 * Reduction management
2387 * Only one reduction can be active at a single time in the program.
2388 * Moreover, since every call is supposed to pass in the same arguments,
2389 * having some static variables is not a problem for multithreading.
2391 * Except for "data" and "size", all the other parameters (which are all function
2392 * pointers) MUST be the same in every processor. Having different processors
2393 * pass in different function pointers results in an undefined behaviour.
2395 * The data passed in to CmiReduce and CmiNodeReduce is deleted by the system,
2396 * and MUST be allocated with CmiAlloc. The data passed in to the "Struct"
2397 * functions is deleted with the provided function, or it is left intact if no
2398 * function is specified.
2400 * The destination handler for the the first form MUST be embedded into the
2403 * The pup function is used to pup the input data structure into a message to
2404 * be sent to the parent processor. This pup routine is currently used only
2405 * for sizing and packing, NOT unpacking. It MUST be non-null.
2407 * The merge function receives as first parameter the input "data", being it
2408 * a message or a complex data structure (it is up to the user to interpret it
2409 * correctly), and a list of incoming (packed) messages from the children.
2410 * The merge function is responsible to delete "data" if this is no longer needed.
2411 * The system will be in charge of deleting the messages passed in as the second
2412 * argument, and the return value of the function (using the provided deleteFn in
2413 * the second version, or CmiFree in the first). The merge function can return
2414 * data if the merge can be performed in-place. It MUST be non-null.
2416 * At the destination, on processor zero, the final data returned by the last
2417 * merge call will not be deleted by the system, and the CmiHandler function
2418 * will be in charge of its deletion.
2420 * CmiReduce/CmiReduceStruct MUST be called once by every processor,
2421 * CmiNodeReduce/CmiNodeReduceStruct MUST be called once by every node, and in
2422 * particular by the rank zero in each node.
2423 ****************************************************************************/
2425 CpvStaticDeclare(int, CmiReductionMessageHandler);
2426 CpvStaticDeclare(int, CmiReductionDynamicRequestHandler);
2428 CpvStaticDeclare(CmiReduction**, _reduce_info);
2429 CpvStaticDeclare(int, _reduce_info_size); /* This is the log2 of the size of the array */
2430 CpvStaticDeclare(CmiUInt2, _reduce_seqID_global); /* This is used only by global reductions */
2431 CpvStaticDeclare(CmiUInt2, _reduce_seqID_request);
2432 CpvStaticDeclare(CmiUInt2, _reduce_seqID_dynamic);
2435 CmiReductionID_globalOffset = 0, /* Reductions that involve the whole set of processors */
2436 CmiReductionID_requestOffset = 1, /* Reductions IDs that are requested by all the processors (i.e during intialization) */
2437 CmiReductionID_dynamicOffset = 2, /* Reductions IDs that are requested by only one processor (typically at runtime) */
2438 CmiReductionID_multiplier = 3
2441 CmiReduction* CmiGetReductionCreate(int id, short int numChildren) {
2442 int index = id & ~((~0u)<<CpvAccess(_reduce_info_size));
2443 CmiReduction *red = CpvAccess(_reduce_info)[index];
2444 if (red != NULL && red->seqID != id) {
2445 /* The table needs to be expanded */
2446 CmiAbort("Too many simultaneous reductions");
2448 if (red == NULL || red->numChildren < numChildren) {
2449 CmiReduction *newred;
2450 CmiAssert(red == NULL || red->localContributed == 0);
2451 if (numChildren == 0) numChildren = 4;
2452 newred = (CmiReduction*)malloc(sizeof(CmiReduction)+numChildren*sizeof(void*));
2453 newred->numRemoteReceived = 0;
2454 newred->localContributed = 0;
2457 memcpy(newred, red, sizeof(CmiReduction)+red->numChildren*sizeof(void*));
2461 red->numChildren = numChildren;
2462 red->remoteData = (char**)(red+1);
2463 CpvAccess(_reduce_info)[index] = red;
2468 CmiReduction* CmiGetReduction(int id) {
2469 return CmiGetReductionCreate(id, 0);
2472 void CmiClearReduction(int id) {
2473 int index = id & ~((~0u)<<CpvAccess(_reduce_info_size));
2474 free(CpvAccess(_reduce_info)[index]);
2475 CpvAccess(_reduce_info)[index] = NULL;
2478 CmiReduction* CmiGetNextReduction(short int numChildren) {
2479 int id = CpvAccess(_reduce_seqID_global);
2480 CpvAccess(_reduce_seqID_global) += CmiReductionID_multiplier;
2481 if (id > 0xFFF0) CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2482 return CmiGetReductionCreate(id, numChildren);
2485 CmiReductionID CmiGetGlobalReduction(void) {
2486 return CpvAccess(_reduce_seqID_request)+=CmiReductionID_multiplier;
2489 CmiReductionID CmiGetDynamicReduction(void) {
2490 if (CmiMyPe() != 0) CmiAbort("Cannot call CmiGetDynamicReduction on processors other than zero!\n");
2491 return CpvAccess(_reduce_seqID_dynamic)+=CmiReductionID_multiplier;
2494 void CmiReductionHandleDynamicRequest(char *msg) {
2495 int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2497 int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+values[1];
2498 values[0] = CmiGetDynamicReduction();
2499 CmiSetHandler(msg, CmiGetXHandler(msg));
2501 CmiSyncSendAndFree(pe, size, msg);
2503 CmiSyncBroadcastAllAndFree(size, msg);
2507 void CmiGetDynamicReductionRemote(int handlerIdx, int pe, int dataSize, void *data) {
2508 int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+dataSize;
2509 char *msg = (char*)CmiAlloc(size);
2510 int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2512 values[1] = dataSize;
2513 CmiSetXHandler(msg, handlerIdx);
2514 if (dataSize) memcpy(msg+CmiMsgHeaderSizeBytes+2*sizeof(int), data, dataSize);
2515 if (CmiMyPe() == 0) {
2516 CmiReductionHandleDynamicRequest(msg);
2518 /* send the request to processor 0 */
2519 CmiSetHandler(msg, CpvAccess(CmiReductionDynamicRequestHandler));
2520 CmiSyncSendAndFree(0, size, msg);
2524 void CmiSendReduce(CmiReduction *red) {
2525 void *mergedData, *msg;
2527 if (!red->localContributed || red->numChildren != red->numRemoteReceived) return;
2528 mergedData = red->localData;
2529 msg_size = red->localSize;
2530 if (red->numChildren > 0) {
2532 if (red->ops.pupFn != NULL) {
2533 offset = CmiReservedHeaderSize;
2534 for (i=0; i<red->numChildren; ++i) red->remoteData[i] += offset;
2536 mergedData = (red->ops.mergeFn)(&msg_size, red->localData, (void **)red->remoteData, red->numChildren);
2537 for (i=0; i<red->numChildren; ++i) CmiFree(red->remoteData[i] - offset);
2539 /*CpvAccess(_reduce_num_children) = 0;*/
2540 /*CpvAccess(_reduce_received) = 0;*/
2542 if (red->parent != -1) {
2543 if (red->ops.pupFn != NULL) {
2544 pup_er p = pup_new_sizer();
2545 (red->ops.pupFn)(p, mergedData);
2546 msg_size = pup_size(p) + CmiReservedHeaderSize;
2548 msg = CmiAlloc(msg_size);
2549 p = pup_new_toMem((void*)(((char*)msg)+CmiReservedHeaderSize));
2550 (red->ops.pupFn)(p, mergedData);
2552 if (red->ops.deleteFn != NULL) (red->ops.deleteFn)(red->localData);
2554 CmiSetHandler(msg, CpvAccess(CmiReductionMessageHandler));
2555 CmiSetRedID(msg, red->seqID);
2556 /*CmiPrintf("CmiSendReduce(%d): sending %d bytes to %d\n",CmiMyPe(),msg_size,red->parent);*/
2557 CmiSyncSendAndFree(red->parent, msg_size, msg);
2559 (red->ops.destination)(msg);
2561 CmiClearReduction(red->seqID);
2564 void *CmiReduceMergeFn_random(int *size, void *data, void** remote, int n) {
2568 void CmiResetGlobalReduceSeqID(void) {
2569 CpvAccess(_reduce_seqID_global) = 0;
2572 static void CmiGlobalReduce(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReduction *red) {
2573 CmiAssert(red->localContributed == 0);
2574 red->localContributed = 1;
2575 red->localData = msg;
2576 red->localSize = size;
2577 red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2578 red->parent = CmiSpanTreeParent(CmiMyPe());
2579 red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2580 red->ops.mergeFn = mergeFn;
2581 red->ops.pupFn = NULL;
2582 /*CmiPrintf("[%d] CmiReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2586 static void CmiGlobalReduceStruct(void *data, CmiReducePupFn pupFn,
2587 CmiReduceMergeFn mergeFn, CmiHandler dest,
2588 CmiReduceDeleteFn deleteFn, CmiReduction *red) {
2589 CmiAssert(red->localContributed == 0);
2590 red->localContributed = 1;
2591 red->localData = data;
2593 red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2594 red->parent = CmiSpanTreeParent(CmiMyPe());
2595 red->ops.destination = dest;
2596 red->ops.mergeFn = mergeFn;
2597 red->ops.pupFn = pupFn;
2598 red->ops.deleteFn = deleteFn;
2599 /*CmiPrintf("[%d] CmiReduceStruct::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2603 void CmiReduce(void *msg, int size, CmiReduceMergeFn mergeFn) {
2604 CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2605 CmiGlobalReduce(msg, size, mergeFn, red);
2608 void CmiReduceStruct(void *data, CmiReducePupFn pupFn,
2609 CmiReduceMergeFn mergeFn, CmiHandler dest,
2610 CmiReduceDeleteFn deleteFn) {
2611 CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2612 CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2615 void CmiReduceID(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2616 CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2617 CmiGlobalReduce(msg, size, mergeFn, red);
2620 void CmiReduceStructID(void *data, CmiReducePupFn pupFn,
2621 CmiReduceMergeFn mergeFn, CmiHandler dest,
2622 CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2623 CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2624 CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2627 void CmiListReduce(int npes, int *pes, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2628 CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2630 CmiAssert(red->localContributed == 0);
2631 red->localContributed = 1;
2632 red->localData = msg;
2633 red->localSize = size;
2634 for (myPos=0; myPos<npes; ++myPos) {
2635 if (pes[myPos] == CmiMyPe()) break;
2637 CmiAssert(myPos < npes);
2638 red->numChildren = npes - (myPos << 2) - 1;
2639 if (red->numChildren > 4) red->numChildren = 4;
2640 if (red->numChildren < 0) red->numChildren = 0;
2641 if (myPos == 0) red->parent = -1;
2642 else red->parent = pes[(myPos - 1) >> 2];
2643 red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2644 red->ops.mergeFn = mergeFn;
2645 red->ops.pupFn = NULL;
2646 /*CmiPrintf("[%d] CmiListReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2650 void CmiListReduceStruct(int npes, int *pes,
2651 void *data, CmiReducePupFn pupFn,
2652 CmiReduceMergeFn mergeFn, CmiHandler dest,
2653 CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2654 CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2656 CmiAssert(red->localContributed == 0);
2657 red->localContributed = 1;
2658 red->localData = data;
2660 for (myPos=0; myPos<npes; ++myPos) {
2661 if (pes[myPos] == CmiMyPe()) break;
2663 CmiAssert(myPos < npes);
2664 red->numChildren = npes - (myPos << 2) - 1;
2665 if (red->numChildren > 4) red->numChildren = 4;
2666 if (red->numChildren < 0) red->numChildren = 0;
2667 red->parent = (myPos - 1) >> 2;
2668 if (myPos == 0) red->parent = -1;
2669 red->ops.destination = dest;
2670 red->ops.mergeFn = mergeFn;
2671 red->ops.pupFn = pupFn;
2672 red->ops.deleteFn = deleteFn;
2676 void CmiGroupReduce(CmiGroup grp, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2678 CmiLookupGroup(grp, &npes, &pes);
2679 CmiListReduce(npes, pes, msg, size, mergeFn, id);
2682 void CmiGroupReduceStruct(CmiGroup grp, void *data, CmiReducePupFn pupFn,
2683 CmiReduceMergeFn mergeFn, CmiHandler dest,
2684 CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2686 CmiLookupGroup(grp, &npes, &pes);
2687 CmiListReduceStruct(npes, pes, data, pupFn, mergeFn, dest, deleteFn, id);
2690 void CmiNodeReduce(void *data, int size, CmiReduceMergeFn mergeFn, int redID, int numChildren, int parent) {
2691 CmiAbort("Feel free to implement CmiNodeReduce...");
2693 CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2694 CpvAccess(_reduce_data) = data;
2695 CpvAccess(_reduce_data_size) = size;
2696 CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2697 _reduce_destination = (CmiHandler)CmiGetHandlerFunction(data);
2698 _reduce_pupFn = NULL;
2699 _reduce_mergeFn = mergeFn;
2700 CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2701 if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(size);
2705 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int redID) {
2706 CmiNodeReduce(data, size, mergeFn, redID, CmiNumNodeSpanTreeChildren(CmiMyNode()),
2707 CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2709 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int numChildren, int parent) {
2710 CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), numChildren, parent);
2712 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int)) {
2713 CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), CmiNumNodeSpanTreeChildren(CmiMyNode()),
2714 CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2718 void CmiNodeReduceStruct(void *data, CmiReducePupFn pupFn,
2719 CmiReduceMergeFn mergeFn, CmiHandler dest,
2720 CmiReduceDeleteFn deleteFn) {
2721 CmiAbort("Feel free to implement CmiNodeReduceStruct...");
2723 CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2724 CpvAccess(_reduce_data) = data;
2725 CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2726 _reduce_destination = dest;
2727 _reduce_pupFn = pupFn;
2728 _reduce_mergeFn = mergeFn;
2729 _reduce_deleteFn = deleteFn;
2730 CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2731 if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(0);
2735 void CmiHandleReductionMessage(void *msg) {
2736 CmiReduction *red = CmiGetReduction(CmiGetRedID(msg));
2737 if (red->numRemoteReceived == red->numChildren) red = CmiGetReductionCreate(CmiGetRedID(msg), red->numChildren+4);
2738 red->remoteData[red->numRemoteReceived++] = (char *)msg;
2739 /*CmiPrintf("[%d] CmiReduce::remote %hd\n",CmiMyPe(),red->seqID);*/
2742 CpvAccess(_reduce_msg_list)[CpvAccess(_reduce_received)++] = msg;
2743 if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce();
2744 / *else CmiPrintf("CmiHandleReductionMessage(%d): %d - %d\n",CmiMyPe(),CpvAccess(_reduce_received),CpvAccess(_reduce_num_children));*/
2747 void CmiReductionsInit(void) {
2749 CpvInitialize(int, CmiReductionMessageHandler);
2750 CpvAccess(CmiReductionMessageHandler) = CmiRegisterHandler((CmiHandler)CmiHandleReductionMessage);
2751 CpvInitialize(int, CmiReductionDynamicRequestHandler);
2752 CpvAccess(CmiReductionDynamicRequestHandler) = CmiRegisterHandler((CmiHandler)CmiReductionHandleDynamicRequest);
2753 CpvInitialize(CmiUInt2, _reduce_seqID_global);
2754 CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2755 CpvInitialize(CmiUInt2, _reduce_seqID_request);
2756 CpvAccess(_reduce_seqID_request) = CmiReductionID_requestOffset;
2757 CpvInitialize(CmiUInt2, _reduce_seqID_dynamic);
2758 CpvAccess(_reduce_seqID_dynamic) = CmiReductionID_dynamicOffset;
2759 CpvInitialize(int, _reduce_info_size);
2760 CpvAccess(_reduce_info_size) = 4;
2761 CpvInitialize(CmiReduction**, _reduce_info);
2762 CpvAccess(_reduce_info) = (CmiReduction **)malloc(16*sizeof(CmiReduction*));
2763 for (i=0; i<16; ++i) CpvAccess(_reduce_info)[i] = NULL;
2766 /*****************************************************************************
2770 ****************************************************************************/
2772 #if CMK_MULTICAST_DEF_USE_COMMON_CODE
2774 typedef struct GroupDef_s
2777 char core[CmiMsgHeaderSizeBytes];
2778 struct GroupDef_s *next;
2786 #define GROUPTAB_SIZE 101
2788 CpvStaticDeclare(int, CmiGroupHandlerIndex);
2789 CpvStaticDeclare(int, CmiGroupCounter);
2790 CpvStaticDeclare(GroupDef *, CmiGroupTable);
2792 void CmiGroupHandler(GroupDef def)
2794 /* receive group definition, insert into group table */
2795 GroupDef *table = CpvAccess(CmiGroupTable);
2796 unsigned int hashval, bucket;
2797 hashval = (def->group.id ^ def->group.pe);
2798 bucket = hashval % GROUPTAB_SIZE;
2799 def->core.next = table[bucket];
2800 table[bucket] = def;
2803 CmiGroup CmiEstablishGroup(int npes, int *pes)
2805 /* build new group definition, broadcast it */
2806 CmiGroup grp; GroupDef def; int len, i;
2807 grp.id = CpvAccess(CmiGroupCounter)++;
2809 len = sizeof(struct GroupDef_s)+(npes*sizeof(int));
2810 def = (GroupDef)CmiAlloc(len);
2813 for (i=0; i<npes; i++)
2814 def->pes[i] = pes[i];
2815 CmiSetHandler(def, CpvAccess(CmiGroupHandlerIndex));
2816 CmiSyncBroadcastAllAndFree(len, def);
2820 void CmiLookupGroup(CmiGroup grp, int *npes, int **pes)
2822 unsigned int hashval, bucket; GroupDef def;
2823 GroupDef *table = CpvAccess(CmiGroupTable);
2824 hashval = (grp.id ^ grp.pe);
2825 bucket = hashval % GROUPTAB_SIZE;
2826 for (def=table[bucket]; def; def=def->core.next) {
2827 if ((def->group.id == grp.id)&&(def->group.pe == grp.pe)) {
2833 *npes = 0; *pes = 0;
2836 void CmiGroupInit(void)
2838 CpvInitialize(int, CmiGroupHandlerIndex);
2839 CpvInitialize(int, CmiGroupCounter);
2840 CpvInitialize(GroupDef *, CmiGroupTable);
2841 CpvAccess(CmiGroupHandlerIndex) = CmiRegisterHandler((CmiHandler)CmiGroupHandler);
2842 CpvAccess(CmiGroupCounter) = 0;
2843 CpvAccess(CmiGroupTable) =
2844 (GroupDef*)calloc(GROUPTAB_SIZE, sizeof(GroupDef));
2845 if (CpvAccess(CmiGroupTable) == 0)
2846 CmiAbort("Memory Allocation Error");
2851 /*****************************************************************************
2853 * Common List-Cast and Multicast Code
2855 ****************************************************************************/
2857 #if CMK_MULTICAST_LIST_USE_COMMON_CODE
2859 void CmiSyncListSendFn(int npes, int *pes, int len, char *msg)
2862 #if CMK_BROADCAST_USE_CMIREFERENCE
2863 for(i=0;i<npes;i++) {
2864 if (pes[i] == CmiMyPe())
2865 CmiSyncSend(pes[i], len, msg);
2868 CmiSyncSendAndFree(pes[i], len, msg);
2872 for(i=0;i<npes;i++) {
2873 CmiSyncSend(pes[i], len, msg);
2878 CmiCommHandle CmiAsyncListSendFn(int npes, int *pes, int len, char *msg)
2880 /* A better asynchronous implementation may be wanted, but at least it works */
2881 CmiSyncListSendFn(npes, pes, len, msg);
2882 return (CmiCommHandle) 0;
2885 void CmiFreeListSendFn(int npes, int *pes, int len, char *msg)
2887 #if CMK_BROADCAST_USE_CMIREFERENCE
2889 CmiSyncSendAndFree(pes[0], len, msg);
2892 CmiSyncListSendFn(npes, pes, len, msg);
2896 for(i=0;i<npes-1;i++) {
2897 CmiSyncSend(pes[i], len, msg);
2900 CmiSyncSendAndFree(pes[npes-1], len, msg);
2908 #if CMK_MULTICAST_GROUP_USE_COMMON_CODE
2910 typedef struct MultiMsg_s
2912 char core[CmiMsgHeaderSizeBytes];
2920 CpvDeclare(int, CmiMulticastHandlerIndex);
2922 void CmiMulticastDeliver(MultiMsg msg)
2924 int npes, *pes; int olen, nlen, pos, child1, child2;
2925 olen = msg->origlen;
2926 nlen = olen + sizeof(struct MultiMsg_s);
2927 CmiLookupGroup(msg->group, &npes, &pes);
2929 CmiSyncSendAndFree(CmiMyPe(), nlen, msg);
2936 if (msg->pos == -1) {
2938 CmiSyncSendAndFree(pes[0], nlen, msg);
2942 child1 = ((pos+1)<<1);
2944 if (child1 < npes) {
2946 CmiSyncSend(pes[child1], nlen, msg);
2948 if (child2 < npes) {
2950 CmiSyncSend(pes[child2], nlen, msg);
2952 if(olen < sizeof(struct MultiMsg_s)) {
2953 memcpy(msg, msg+1, olen);
2955 memcpy(msg, (((char*)msg)+olen), sizeof(struct MultiMsg_s));
2957 CmiSyncSendAndFree(CmiMyPe(), olen, msg);
2960 void CmiMulticastHandler(MultiMsg msg)
2962 CmiMulticastDeliver(msg);
2965 void CmiSyncMulticastFn(CmiGroup grp, int len, char *msg)
2967 int newlen; MultiMsg newmsg;
2968 newlen = len + sizeof(struct MultiMsg_s);
2969 newmsg = (MultiMsg)CmiAlloc(newlen);
2970 if(len < sizeof(struct MultiMsg_s)) {
2971 memcpy(newmsg+1, msg, len);
2973 memcpy(newmsg+1, msg+sizeof(struct MultiMsg_s), len-sizeof(struct MultiMsg_s));
2974 memcpy(((char *)newmsg+len), msg, sizeof(struct MultiMsg_s));
2976 newmsg->group = grp;
2977 newmsg->origlen = len;
2979 CmiSetHandler(newmsg, CpvAccess(CmiMulticastHandlerIndex));
2980 CmiMulticastDeliver(newmsg);
2983 void CmiFreeMulticastFn(CmiGroup grp, int len, char *msg)
2985 CmiSyncMulticastFn(grp, len, msg);
2989 CmiCommHandle CmiAsyncMulticastFn(CmiGroup grp, int len, char *msg)
2991 CmiError("Async Multicast not implemented.");
2992 return (CmiCommHandle) 0;
2995 void CmiMulticastInit(void)
2997 CpvInitialize(int, CmiMulticastHandlerIndex);
2998 CpvAccess(CmiMulticastHandlerIndex) =
2999 CmiRegisterHandler((CmiHandler)CmiMulticastHandler);
3003 extern void CmiMulticastInit(void);
3006 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
3007 extern void *arena_malloc(int size);
3008 extern void arena_free(void *blockPtr);
3011 /***************************************************************************
3013 * Memory Allocation routines
3015 * A block of memory can consist of multiple chunks. Each chunk has
3016 * a sizefield and a refcount. The first chunk's refcount is a reference
3017 * count. That's how many CmiFrees it takes to free the message.
3018 * Subsequent chunks have a refcount which is less than zero. This is
3019 * the offset back to the start of the first chunk.
3021 * Each chunk has a CmiChunkHeader before the user data, with the fields:
3023 * size: The user-allocated size of the chunk, in bytes.
3025 * ref: A magic reference count object. Ordinary blocks start with
3026 * reference count 1. When the reference count reaches zero,
3027 * the block is deleted. To support nested buffers, the
3028 * reference count can also be negative, which means it is
3029 * a byte offset to the enclosing buffer's reference count.
3031 ***************************************************************************/
3034 void *CmiAlloc(int size)
3039 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
3040 res = (char*) arena_malloc(size+sizeof(CmiChunkHeader));
3041 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
3042 res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
3043 #elif CMK_CONVERSE_UGNI || CMK_OFI
3044 res =(char *) LrtsAlloc(size, sizeof(CmiChunkHeader));
3046 res =(char *) CmiPoolAlloc(size+sizeof(CmiChunkHeader));
3047 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
3048 MPI_Alloc_mem(size+sizeof(CmiChunkHeader), MPI_INFO_NULL, &res);
3049 #elif CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
3050 res = (char *) CmiAlloc_bgq(size+sizeof(CmiChunkHeader));
3051 #elif CMK_SMP && CMK_PPC_ATOMIC_QUEUE
3052 res = (char *) CmiAlloc_ppcq(size+sizeof(CmiChunkHeader));
3054 res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
3060 CpvAccess(MemoryUsage) += size+sizeof(CmiChunkHeader);
3061 CpvAccess(AllocCount)++;
3062 CpvAccess(BlocksAllocated)++;
3063 if (CpvAccess(MemoryUsage) > CpvAccess(HiWaterMark)) {
3064 CpvAccess(HiWaterMark) = CpvAccess(MemoryUsage);
3066 if (CpvAccess(MemoryUsage) > 1.1 * CpvAccess(ReportedHiWaterMark)) {
3067 CmiPrintf("HIMEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
3068 CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
3069 CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
3070 CpvAccess(ReportedHiWaterMark) = CpvAccess(MemoryUsage);
3072 if ((CpvAccess(AllocCount) % 1000) == 0) {
3073 CmiPrintf("MEM 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);
3079 res+=sizeof(CmiChunkHeader);
3080 CmiAssert((intptr_t)res % ALIGN_BYTES == 0);
3082 CmiInitMsgHeader(res, size);
3084 SIZEFIELD(res)=size;
3085 REFFIELDSET(res, 1);
3089 void *CmiRdmaAlloc(int size) {
3092 #if CMK_CONVERSE_UGNI
3093 res = (char *)LrtsRdmaAlloc(size, sizeof(CmiChunkHeader));
3094 #elif CMK_USE_IBVERBS || CMK_USE_IBUD
3095 res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
3097 res = (char *)LrtsAlloc(size, sizeof(CmiChunkHeader));
3099 res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
3103 res+=sizeof(CmiChunkHeader);
3104 CmiAssert((intptr_t)res % ALIGN_BYTES == 0);
3106 CmiInitMsgHeader(res, size);
3107 SIZEFIELD(res)=size;
3108 REFFIELDSET(res, 1);
3113 /** Follow the header links out to the most enclosing block */
3114 static void *CmiAllocFindEnclosing(void *blk) {
3115 int refCount = REFFIELD(blk);
3116 while (refCount < 0) {
3117 blk = (void *)((char*)blk+refCount); /* Jump to enclosing block */
3118 refCount = REFFIELD(blk);
3123 void CmiInitMsgHeader(void *msg, int size) {
3124 #if CMK_ONESIDED_IMPL
3125 // Set zcMsgType in the converse message header to CMK_REG_NO_ZC_MSG
3126 if(size >= CmiMsgHeaderSizeBytes)
3127 CMI_ZC_MSGTYPE(msg) = CMK_REG_NO_ZC_MSG;
3131 int CmiGetReference(void *blk)
3133 return REFFIELD(CmiAllocFindEnclosing(blk));
3136 /** Increment the reference count for this block's owner.
3137 This call must be matched by an equivalent CmiFree. */
3138 void CmiReference(void *blk)
3140 REFFIELDINC(CmiAllocFindEnclosing(blk));
3143 /** Return the size of the user portion of this block. */
3144 int CmiSize(void *blk)
3146 return SIZEFIELD(blk);
3149 /** Decrement the reference count for this block. */
3150 void CmiFree(void *blk)
3152 void *parentBlk=CmiAllocFindEnclosing(blk);
3153 int refCount=REFFIELDDEC(parentBlk);
3154 #if CMK_ERROR_CHECKING
3155 if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
3156 CmiAbort("CmiFree reference count was zero-- is this a duplicate free?");
3158 if(refCount==1) { /* This was the last reference to the block-- free it */
3160 int size=SIZEFIELD(parentBlk);
3161 if (size > 1000000000) /* Absurdly large size field-- warning */
3162 CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
3163 CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader));
3164 CpvAccess(BlocksAllocated)--;
3167 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
3168 arena_free(BLKSTART(parentBlk));
3169 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
3170 /* is this message the head of a MultipleSend that we received?
3171 Then the parts with INFIMULTIPOOL have metadata which must be
3172 unregistered and freed. */
3173 #ifdef CMK_IBVERS_CLEAN_MULTIPLESEND
3174 if(CmiGetHandler(parentBlk)==CpvAccess(CmiMainHandlerIDP))
3176 infi_freeMultipleSend(parentBlk);
3179 infi_CmiFree(BLKSTART(parentBlk));
3180 #elif CMK_CONVERSE_UGNI || CMK_OFI
3181 LrtsFree(BLKSTART(parentBlk));
3183 CmiPoolFree(BLKSTART(parentBlk));
3184 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
3185 MPI_Free_mem(parentBlk);
3186 #elif CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
3187 CmiFree_bgq(BLKSTART(parentBlk));
3188 #elif CMK_SMP && CMK_PPC_ATOMIC_QUEUE
3189 CmiFree_ppcq(BLKSTART(parentBlk));
3191 free_nomigrate(BLKSTART(parentBlk));
3196 void CmiRdmaFree(void *blk)
3198 void *parentBlk=CmiAllocFindEnclosing(blk);
3199 int refCount=REFFIELDDEC(parentBlk);
3200 #if CMK_ERROR_CHECKING
3201 if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
3202 CmiAbort("CmiRdmaFree reference count was zero-- is this a duplicate free?");
3204 if(refCount==1) { /* This was the last reference to the block-- free it */
3206 int size=SIZEFIELD(parentBlk);
3207 if (size > 1000000000) /* Absurdly large size field-- warning */
3208 CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
3209 CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader));
3210 CpvAccess(BlocksAllocated)--;
3213 #if CMK_CONVERSE_UGNI
3214 LrtsRdmaFree(BLKSTART(parentBlk));
3215 #elif CMK_USE_IBVERBS || CMK_USE_IBUD
3216 infi_CmiFree(BLKSTART(parentBlk));
3218 LrtsFree(BLKSTART(parentBlk));
3220 free_nomigrate(BLKSTART(parentBlk));
3226 /***************************************************************************
3228 * Temporary-memory Allocation routines
3230 * This buffer augments the storage available on the regular machine stack
3231 * for fairly large temporary buffers, which allows us to use smaller machine
3234 ***************************************************************************/
3236 #define CMI_TMP_BUF_MAX 16*1024 /* Allow this much temporary storage. */
3239 char *buf; /* Start of temporary buffer */
3240 int cur; /* First unused location in temporary buffer */
3241 int max; /* Length of temporary buffer */
3243 CpvDeclare(CmiTmpBuf_t,CmiTmpBuf); /* One temporary buffer per PE */
3245 static void CmiTmpSetup(CmiTmpBuf_t *b) {
3246 b->buf=(char *)malloc(CMI_TMP_BUF_MAX);
3248 b->max=CMI_TMP_BUF_MAX;
3251 void *CmiTmpAlloc(int size) {
3252 if (!CpvInitialized(CmiTmpBuf)) {
3253 return malloc(size);
3255 else { /* regular case */
3256 CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3258 if (b->cur+size>b->max) {
3259 if (b->max==0) /* We're just uninitialized */
3261 else /* We're really out of space! */
3262 return malloc(size);
3269 void CmiTmpFree(void *t) {
3270 if (!CpvInitialized(CmiTmpBuf)) {
3273 else { /* regular case */
3274 CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3275 /* t should point into our temporary buffer: figure out where */
3276 int cur=((const char *)t)-b->buf;
3277 if (cur<0 || cur>b->max) {
3285 void CmiTmpInit(char **argv) {
3286 CpvInitialize(CmiTmpBuf_t,CmiTmpBuf);
3287 /* Set up this processor's temporary buffer */
3288 CmiTmpSetup(&CpvAccess(CmiTmpBuf));
3291 /******************************************************************************
3293 Cross-platform directory creation
3295 ****************************************************************************/
3297 /* Windows directory creation: */
3298 #include <windows.h>
3300 void CmiMkdir(const char *dirName) {
3301 CreateDirectory(dirName,NULL);
3304 int CmiGetPageSize(void)
3306 SYSTEM_INFO system_info;
3307 GetSystemInfo(&system_info);
3308 return system_info.dwPageSize;
3311 /* UNIX directory creation */
3313 #include <sys/stat.h> /* from "mkdir" man page */
3314 #include <sys/types.h>
3316 void CmiMkdir(const char *dirName) {
3317 mkdir(dirName,0777);
3320 int CmiGetPageSize(void)
3322 #if CMK_HAS_GETPAGESIZE
3323 return getpagesize();
3325 return CMK_MEMORY_PAGESIZE;
3332 /******************************************************************************
3334 Multiple Send function
3336 ****************************************************************************/
3342 /****************************************************************************
3343 * DESCRIPTION : This function call allows the user to send multiple messages
3344 * from one processor to another, all intended for differnet
3349 * destPE, len, int sizes[0..len-1], char *messages[0..len-1]
3351 ****************************************************************************/
3352 /* Round up message size to the message granularity.
3353 Does this by adding, then truncating.
3355 static int roundUpSize(unsigned int s) {
3356 return (int)((s+sizeof(double)-1)&~(sizeof(double)-1));
3358 /* Return the amount of message padding required for a message
3359 with this many user bytes.
3361 static int paddingSize(unsigned int s) {
3362 return roundUpSize(s)-s;
3365 /* Message header for a bundle of multiple-sent messages */
3367 char convHeader[CmiMsgHeaderSizeBytes];
3368 int nMessages; /* Number of distinct messages bundled below. */
3369 double pad; /* To align the first message, which follows this header */
3370 } CmiMultipleSendHeader;
3372 #if CMK_USE_IBVERBS | CMK_USE_IBUD
3373 /* given a pointer to a multisend message clean up the metadata */
3375 void infi_freeMultipleSend(void *msgWhole)
3377 int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3378 double pad=((CmiMultipleSendHeader *)msgWhole)->pad;
3379 int offset=sizeof(CmiMultipleSendHeader);
3382 if (pad != 1234567.89) return;
3385 /*unreg meta, free meta, move the ptr */
3386 /* note these weird little things are not pooled */
3387 /* do NOT free the message here, we are only a part of this buffer*/
3388 infiCmiChunkHeader *ch = (infiCmiChunkHeader *)((char *)msgWhole + offset);
3389 char *msg = (char *)msgWhole + offset + sizeof(infiCmiChunkHeader);
3390 int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3391 infi_unregAndFreeMeta(ch->metaData);
3392 offset+= sizeof(infiCmiChunkHeader) + msgSize;
3398 static void _CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[], int immed)
3400 CmiMultipleSendHeader header;
3401 int m; /* Outgoing message */
3403 CmiInitMsgHeader(header.convHeader, sizeof(CmiMultipleSendHeader));
3405 infiCmiChunkHeader *msgHdr;
3407 CmiChunkHeader *msgHdr; /* Chunk headers for each message */
3410 double pad = 0; /* padding required */
3411 int vecLen; /* Number of pieces in outgoing message vector */
3412 int *vecSizes; /* Sizes of each piece we're sending out. */
3413 char **vecPtrs; /* Pointers to each piece we're sending out. */
3414 int vec; /* Entry we're currently filling out in above array */
3417 msgHdr = (infiCmiChunkHeader *)CmiTmpAlloc(len * sizeof(infiCmiChunkHeader));
3419 msgHdr = (CmiChunkHeader *)CmiTmpAlloc(len * sizeof(CmiChunkHeader));
3422 /* Allocate memory for the outgoing vector*/
3423 vecLen=1+3*len; /* Header and 3 parts per message */
3424 vecSizes = (int *)CmiTmpAlloc(vecLen * sizeof(int));
3425 vecPtrs = (char **)CmiTmpAlloc(vecLen * sizeof(char *));
3428 /* Build the header */
3429 header.nMessages=len;
3430 CmiSetHandler(&header, CpvAccess(CmiMainHandlerIDP));
3431 header.pad = 1234567.89;
3432 #if CMK_IMMEDIATE_MSG
3433 if (immed) CmiBecomeImmediate(&header);
3435 vecSizes[vec]=sizeof(header); vecPtrs[vec]=(char *)&header;
3438 /* Build an entry for each message:
3439 | CmiChunkHeader | Message data | Message padding | ...next message entry ...
3441 for (m=0;m<len;m++) {
3443 msgHdr[m].chunkHeader.size=roundUpSize(sizes[m]); /* Size of message and padding */
3444 msgHdr[m].chunkHeader.setRef(0); /* Reference count will be filled out on receive side */
3445 msgHdr[m].metaData=NULL;
3447 msgHdr[m].size=roundUpSize(sizes[m]); /* Size of message and padding */
3448 msgHdr[m].setRef(0); /* Reference count will be filled out on receive side */
3451 /* First send the message's CmiChunkHeader (for use on receive side) */
3453 vecSizes[vec]=sizeof(infiCmiChunkHeader);
3455 vecSizes[vec]=sizeof(CmiChunkHeader);
3457 vecPtrs[vec]=(char *)&msgHdr[m];
3460 /* Now send the actual message data */
3461 vecSizes[vec]=sizes[m]; vecPtrs[vec]=msgComps[m];
3464 /* Now send padding to align the next message on a double-boundary */
3465 vecSizes[vec]=paddingSize(sizes[m]); vecPtrs[vec]=(char *)&pad;
3468 CmiAssert(vec==vecLen);
3470 CmiSyncVectorSend(destPE, vecLen, vecSizes, vecPtrs);
3472 CmiTmpFree(vecPtrs); /* CmiTmp: Be sure to throw away in opposite order of allocation */
3473 CmiTmpFree(vecSizes);
3477 void CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3479 _CmiMultipleSend(destPE, len, sizes, msgComps, 0);
3482 void CmiMultipleIsend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3484 _CmiMultipleSend(destPE, len, sizes, msgComps, 1);
3487 /****************************************************************************
3488 * DESCRIPTION : This function initializes the main handler required for the
3489 * CmiMultipleSend() function to work.
3491 * This function should be called once in any Converse program
3492 * that uses CmiMultipleSend()
3494 ****************************************************************************/
3496 static void CmiMultiMsgHandler(char *msgWhole);
3498 void CmiInitMultipleSend(void)
3500 CpvInitialize(int,CmiMainHandlerIDP);
3501 CpvAccess(CmiMainHandlerIDP) =
3502 CmiRegisterHandler((CmiHandler)CmiMultiMsgHandler);
3505 /****************************************************************************
3506 * DESCRIPTION : This function is the main handler that splits up the messages
3507 * CmiMultipleSend() pastes together.
3509 ****************************************************************************/
3511 static void CmiMultiMsgHandler(char *msgWhole)
3513 int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3514 int offset=sizeof(CmiMultipleSendHeader);
3516 for (m=0;m<len;m++) {
3518 infiCmiChunkHeader *ch=(infiCmiChunkHeader *)(msgWhole+offset);
3519 char *msg=(msgWhole+offset+sizeof(infiCmiChunkHeader));
3520 int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3521 ch->chunkHeader.setRef(msgWhole-msg);
3522 ch->metaData = registerMultiSendMesg(msg,msgSize);
3524 CmiChunkHeader *ch=(CmiChunkHeader *)(msgWhole+offset);
3525 char *msg=(msgWhole+offset+sizeof(CmiChunkHeader));
3526 int msgSize=ch->size; /* Size of user portion of message (plus padding at end) */
3527 ch->setRef(msgWhole-msg);
3529 /* Link new message to owner via a negative ref pointer */
3530 CmiReference(msg); /* Follows link & increases reference count of *msgWhole* */
3531 CmiSyncSendAndFree(CmiMyPe(), msgSize, msg);
3533 offset+= sizeof(infiCmiChunkHeader) + msgSize;
3535 offset+= sizeof(CmiChunkHeader) + msgSize;
3538 /* Release our reference to the whole message. The message will
3539 only actually be deleted once all its sub-messages are free'd as well. */
3543 /****************************************************************************
3544 * Hypercube broadcast message passing.
3545 ****************************************************************************/
3547 int HypercubeGetBcastDestinations(int mype, int total_pes, int k, int *dest_pes) {
3549 for ( ; k>=0; --k) {
3550 /* add the processor destination at level k if it exist */
3551 dest_pes[num_pes] = mype ^ (1<<k);
3552 if (dest_pes[num_pes] >= total_pes) {
3553 /* find the first proc in the other part of the current dimention */
3554 dest_pes[num_pes] &= (~0u)<<k;
3555 /* if the first proc there is over CmiNumPes() then there is no other
3556 dimension, otherwise if it is valid compute my correspondent in such
3557 a way to minimize the load for every processor */
3558 if (total_pes>dest_pes[num_pes]) dest_pes[num_pes] += (mype - (mype & ((~0u)<<k))) % (total_pes - dest_pes[num_pes]);
3560 if (dest_pes[num_pes] < total_pes) {
3561 /* if the destination is in the acceptable range increment num_pes */
3569 /****************************************************************************
3570 * DESCRIPTION : This function initializes the main handler required for the
3573 * This function should be called once in any Converse program
3575 ****************************************************************************/
3577 int _immediateLock = 0; /* if locked, all immediate message handling will be delayed. */
3578 int _immediateFlag = 0; /* if set, there is delayed immediate message. */
3580 CpvDeclare(int, CmiImmediateMsgHandlerIdx); /* Main handler that is run on every node */
3582 /* xdl is the real handler */
3583 static void CmiImmediateMsgHandler(char *msg)
3585 CmiSetHandler(msg, CmiGetXHandler(msg));
3586 CmiHandleMessage(msg);
3589 void CmiInitImmediateMsg(void)
3591 CpvInitialize(int,CmiImmediateMsgHandlerIdx);
3592 CpvAccess(CmiImmediateMsgHandlerIdx) =
3593 CmiRegisterHandler((CmiHandler)CmiImmediateMsgHandler);
3596 /*#if !CMK_IMMEDIATE_MSG
3597 #if !CMK_MACHINE_PROGRESS_DEFINED
3598 void CmiProbeImmediateMsg()
3604 /******** Idle timeout module (+idletimeout=30) *********/
3607 int idle_timeout;/*Milliseconds to wait idle before aborting*/
3608 int is_idle;/*Boolean currently-idle flag*/
3609 int call_count;/*Number of timeout calls currently in flight*/
3612 static void on_timeout(cmi_cpu_idlerec *rec,double curWallTime)
3615 if(rec->call_count==0 && rec->is_idle==1) {
3616 CmiError("Idle time on PE %d exceeded specified timeout.\n", CmiMyPe());
3617 CmiAbort("Exiting.\n");
3620 static void on_idle(cmi_cpu_idlerec *rec,double curWallTime)
3622 CcdCallFnAfter((CcdVoidFn)on_timeout, rec, rec->idle_timeout);
3623 rec->call_count++; /*Keeps track of overlapping timeout calls.*/
3626 static void on_busy(cmi_cpu_idlerec *rec,double curWallTime)
3630 static void CIdleTimeoutInit(char **argv)
3632 int idle_timeout=0; /*Seconds to wait*/
3633 CmiGetArgIntDesc(argv,"+idle-timeout",&idle_timeout,"Abort if idle for this many seconds");
3634 if(idle_timeout != 0) {
3635 cmi_cpu_idlerec *rec=(cmi_cpu_idlerec *)malloc(sizeof(cmi_cpu_idlerec));
3637 rec->idle_timeout=idle_timeout*1000;
3640 CcdCallOnCondition(CcdPROCESSOR_BEGIN_IDLE, (CcdVoidFn)on_idle, rec);
3641 CcdCallOnCondition(CcdPROCESSOR_BEGIN_BUSY, (CcdVoidFn)on_busy, rec);
3645 /*****************************************************************************
3647 * Converse Initialization
3649 *****************************************************************************/
3651 CMI_EXTERNC void CrnInit(void);
3652 CMI_EXTERNC void CmiIsomallocInit(char **argv);
3653 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3654 void CmiIOInit(char **argv);
3657 /* defined in cpuaffinity.C */
3658 CMI_EXTERNC void CmiInitCPUAffinityUtil(void);
3660 static void CmiProcessPriority(char **argv)
3662 int dummy, nicelevel=-100; /* process priority */
3663 CmiGetArgIntDesc(argv,"+nice",&nicelevel,"Set the process priority level");
3665 while (CmiGetArgIntDesc(argv,"+nice",&dummy,"Set the process priority level"));
3666 /* call setpriority once on each process to set process's priority */
3667 if (CmiMyRank() == 0 && nicelevel != -100) {
3669 if (0!=setpriority(PRIO_PROCESS, 0, nicelevel)) {
3670 CmiPrintf("[%d] setpriority failed with value %d. \n", CmiMyPe(), nicelevel);
3671 perror("setpriority");
3672 CmiAbort("setpriority failed.");
3675 CmiPrintf("[%d] Charm++: setpriority %d\n", CmiMyPe(), nicelevel);
3677 HANDLE hProcess = GetCurrentProcess();
3678 DWORD dwPriorityClass = NORMAL_PRIORITY_CLASS;
3679 const char *prio_str = "NORMAL_PRIORITY_CLASS";
3690 #ifdef BELOW_NORMAL_PRIORITY_CLASS
3691 else if (nicelevel<10 && nicelevel>0) {
3692 dwPriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
3693 prio_str = "BELOW_NORMAL_PRIORITY_CLASS";
3696 else if (nicelevel>0) {
3697 dwPriorityClass = IDLE_PRIORITY_CLASS;
3698 prio_str = "IDLE_PRIORITY_CLASS";
3700 else if (nicelevel<=-20) {
3701 dwPriorityClass = REALTIME_PRIORITY_CLASS;
3702 prio_str = "REALTIME_PRIORITY_CLASS";
3704 #ifdef ABOVE_NORMAL_PRIORITY_CLASS
3705 else if (nicelevel>-10 && nicelevel<0) {
3706 dwPriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
3707 prio_str = "ABOVE_NORMAL_PRIORITY_CLASS";
3710 else if (nicelevel<0) {
3711 dwPriorityClass = HIGH_PRIORITY_CLASS;
3712 prio_str = "HIGH_PRIORITY_CLASS";
3714 status = SetPriorityClass(hProcess, dwPriorityClass);
3716 int err=GetLastError();
3717 CmiPrintf("SetPriorityClass failed errno=%d, WSAerr=%d\n",errno, err);
3718 CmiAbort("SetPriorityClass failed.");
3721 CmiPrintf("[%d] Charm++: setpriority %s\n", CmiMyPe(), prio_str);
3726 void CommunicationServerInit(void)
3728 #if CMK_IMMEDIATE_MSG
3732 CpvInitialize(int,CmiImmediateMsgHandlerIdx);
3737 static int testEndian(void)
3740 unsigned char *c=(unsigned char *)&test;
3741 if (c[sizeof(int)-1]==0x1c)
3742 /* Macintosh and most workstations are big-endian */
3743 return 1; /* Big-endian machine */
3745 /* Intel x86 PC's, and DEC VAX are little-endian */
3746 return 0; /* Little-endian machine */
3747 return -2; /*Unknown integer type */
3750 int CmiEndianness(void)
3752 static int _cmi_endianness = -1;
3753 if (_cmi_endianness == -1) _cmi_endianness = testEndian();
3754 CmiAssert(_cmi_endianness != -2);
3755 return _cmi_endianness;
3759 /* This fixes bug #713, which is caused by tsan deadlocking inside
3760 * a 'write' syscall inside a mutex. */
3761 static void checkTSanOptions(void)
3763 char *env = getenv("TSAN_OPTIONS");
3766 !strstr(env, "log_path=") ||
3767 strstr(env, "log_path=stdout") ||
3768 strstr(env, "log_path=stderr")) {
3769 CmiAbort("TSAN output must be redirected to disk.\n"
3770 "Run this program with TSAN_OPTIONS=\"log_path=filename\"");
3775 #if CMK_CCS_AVAILABLE
3776 CMI_EXTERNC_VARIABLE int ccsRunning;
3780 CMI_EXTERNC_VARIABLE int quietModeRequested;
3781 int quietModeRequested; // user has requested quiet mode
3782 CMI_EXTERNC_VARIABLE int quietMode;
3783 int quietMode; // quiet mode active (CmiPrintf's are disabled)
3784 CmiSpanningTreeInfo* _topoTree = NULL;
3787 Main Converse initialization routine. This routine is
3788 called by the machine file (machine.C) to set up Converse.
3789 It's "Common" because it's shared by all the machine.C files.
3791 The main task of this routine is to set up all the Cpv's
3792 (message queues, handler tables, etc.) used during main execution.
3794 On SMP versions, this initialization routine is called by
3795 *all* processors of a node simultaniously. It's *also* called
3796 by the communication thread, which is rather strange but needed
3797 for immediate messages. Each call to this routine expects a
3798 different copy of the argv arguments, so use CmiCopyArgs(argv).
3801 - A working network layer.
3802 - Working Cpv's and CmiNodeBarrier.
3803 - CthInit to already have been called. CthInit is called
3804 from the machine layer directly, because some machine layers
3805 (like uth) use Converse threads internally.
3807 Initialization is somewhat subtle, in that various modules
3808 won't work properly until they're initialized. For example,
3809 nobody can register handlers before calling CmiHandlerInit.
3812 void ConverseCommonInit(char **argv)
3814 CpvInitialize(int, _urgentSend);
3815 CpvAccess(_urgentSend) = 0;
3816 CpvInitialize(int,interopExitFlag);
3817 CpvAccess(interopExitFlag) = 0;
3819 CpvInitialize(int,_curRestartPhase);
3820 CpvAccess(_curRestartPhase)=1;
3822 CmiMemoryInit(argv);
3823 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3827 CmiPrintf("Converse/Charm++ Commit ID: %s\n", CmiCommitID);
3829 CpvInitialize(int, cmiMyPeIdle);
3830 CpvAccess(cmiMyPeIdle) = 0;
3833 CmiPoolAllocInit(30);
3838 CmiInitCPUAffinityUtil();
3840 CcdModuleInit(argv);
3842 CmiReductionsInit();
3843 CIdleTimeoutInit(argv);
3845 #if CMK_SHARED_VARS_POSIX_THREADS_SMP /*Used by the netlrts-*-smp and multicore versions*/
3846 if(CmiGetArgFlagDesc(argv, "+CmiSpinOnIdle", "Force the runtime system to spin on message reception when idle, rather than sleeping")) {
3847 if(CmiMyRank() == 0) _Cmi_forceSpinOnIdle = 1;
3849 if(CmiGetArgFlagDesc(argv, "+CmiSleepOnIdle", "Force the runtime system to sleep when idle, rather than spinning on message reception")) {
3850 if(CmiMyRank() == 0) _Cmi_sleepOnIdle = 1;
3852 if(CmiGetArgFlagDesc(argv,"+CmiNoProcForComThread","Is there an extra processor for the communication thread on each node(only for netlrts-smp-*) ?")){
3853 if (CmiMyPe() == 0) {
3854 CmiPrintf("Charm++> Note: The option +CmiNoProcForComThread has been superseded by +CmiSleepOnIdle\n");
3856 if(CmiMyRank() == 0) _Cmi_sleepOnIdle=1;
3858 if (_Cmi_sleepOnIdle && _Cmi_forceSpinOnIdle) {
3859 if(CmiMyRank() == 0) CmiAbort("The option +CmiSpinOnIdle is mutually exclusive with the options +CmiSleepOnIdle and +CmiNoProcForComThread");
3863 #if CMK_TRACE_ENABLED
3865 /*initTraceCore(argv);*/ /* projector */
3867 CmiProcessPriority(argv);
3873 CmiPersistentInit();
3874 CmiIsomallocInit(argv);
3875 // Initialize converse handlers for supporting generic Direct Nocopy API
3876 CmiOnesidedDirectInit();
3879 #if CMK_CCS_AVAILABLE
3887 CmiInitMultipleSend();
3893 CmiInitImmediateMsg();
3894 CldModuleInit(argv);
3901 /* main thread is suspendable */
3903 CthSetSuspendable(CthSelf(), 0);
3906 #if CMK_BIGSIM_CHARM
3907 /* have to initialize QD here instead of _initCharm */
3913 void ConverseCommonExit(void)
3917 #if CMK_TRACE_ENABLED
3919 /*closeTraceCore();*/ /* projector */
3922 #if CMI_IO_BUFFER_EXPLICIT
3923 CmiFlush(stdout); /* end of program, always flush */
3931 // ensure all PEs have finished GPU work before destructing
3932 if(CmiMyRank() < CmiMyNodeSize()) {
3935 if (CmiMyRank() == 0) {
3946 extern void register_accel_spe_funcs(void);
3948 void CmiInitCell(void)
3950 // Create a unique string for each PPE to use for the timing
3952 char fileNameBuf[64];
3953 sprintf(fileNameBuf, "speTiming.%d", CmiMyPe());
3955 InitOffloadAPI(offloadCallback, NULL, NULL, fileNameBuf);
3956 //CcdCallOnConditionKeep(CcdPERIODIC,
3957 // (CcdVoidFn) OffloadAPIProgress, NULL);
3958 CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,
3959 (CcdVoidFn) OffloadAPIProgress, NULL);
3961 // Register accelerated entry methods on the PPE
3962 register_accel_spe_funcs();
3965 #include "cell-api.c"
3970 * CW Lee - 9/14/2005
3971 * Added a mechanism to allow some control over machines with extremely
3972 * inefficient terminal IO mechanisms. Case in point: the XT3 has a
3973 * 20ms flush overhead along with about 25MB/s bandwidth for IO. This,
3974 * coupled with a default setup using unbuffered stdout introduced
3975 * severe overheads (and hence limiting scaling) for applications like
3978 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3979 void CmiIOInit(char **argv) {
3980 CpvInitialize(int, expIOFlushFlag);
3981 #if CMI_IO_BUFFER_EXPLICIT
3983 Support for an explicit buffer only makes sense if the machine
3984 layer does not wish to make its own implementation.
3986 Placing this after CmiMemoryInit() means that CmiMemoryInit()
3987 MUST NOT make use of stdout if an explicit buffer is requested.
3989 The setvbuf function may only be used after opening a stream and
3990 before any other operations have been performed on it
3992 CpvInitialize(char*, explicitIOBuffer);
3993 CpvInitialize(int, expIOBufferSize);
3994 if (!CmiGetArgIntDesc(argv,"+io_buffer_size", &CpvAccess(expIOBufferSize),
3995 "Explicit IO Buffer Size")) {
3996 CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3998 if (CpvAccess(expIOBufferSize) <= 0) {
3999 CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
4001 CpvAccess(explicitIOBuffer) = (char*)CmiAlloc(CpvAccess(expIOBufferSize)*
4003 if (setvbuf(stdout, CpvAccess(explicitIOBuffer), _IOFBF,
4004 CpvAccess(expIOBufferSize))) {
4005 CmiAbort("Explicit IO Buffering failed\n");
4008 #if CMI_IO_FLUSH_USER
4009 /* system default to have user control flushing of IO */
4010 /* Now look for user override */
4011 CpvAccess(expIOFlushFlag) = !CmiGetArgFlagDesc(argv,"+io_flush_system",
4012 "System Controls IO Flush");
4014 /* system default to have system handle IO flushing */
4015 /* Now look for user override */
4016 CpvAccess(expIOFlushFlag) = CmiGetArgFlagDesc(argv,"+io_flush_user",
4017 "User Controls IO Flush");
4022 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
4024 void CmiPrintf(const char *format, ...)
4026 if (quietMode) return;
4030 va_start(args,format);
4031 vfprintf(stdout,format, args);
4032 if (CpvInitialized(expIOFlushFlag) && !CpvAccess(expIOFlushFlag)) {
4036 #if CMK_CCS_AVAILABLE && CMK_CMIPRINTF_IS_A_BUILTIN
4037 if (CpvAccess(cmiArgDebugFlag)) {
4038 va_start(args,format);
4039 print_node0(format, args);
4047 void CmiError(const char *format, ...)
4052 va_start(args,format);
4053 vfprintf(stderr,format, args);
4054 CmiFlush(stderr); /* stderr is always flushed */
4056 #if CMK_CCS_AVAILABLE && CMK_CMIPRINTF_IS_A_BUILTIN
4057 if (CpvAccess(cmiArgDebugFlag)) {
4058 va_start(args,format);
4059 print_node0(format, args);
4069 void __cmi_assert(const char *errmsg)
4071 CmiError("[%d] %s\n", CmiMyPe(), errmsg);
4075 char *CmiCopyMsg(char *msg, int len)
4077 char *copy = (char *)CmiAlloc(len);
4079 memcpy(copy, msg, len);
4084 unsigned char computeCheckSum(unsigned char *data, int len)
4087 unsigned char ret = 0;
4088 for (i=0; i<len; i++) ret ^= (unsigned char)data[i];
4092 /* Flag for bigsim's out-of-core emulation */
4093 int _BgOutOfCoreFlag=0; /*indicate the type of memory operation (in or out) */
4094 int _BgInOutOfCoreMode=0; /*indicate whether the emulation is in the out-of-core emulation mode */
4097 unsigned int CmiILog2(unsigned int val) {
4098 unsigned int log = 0u;
4100 while ( val > (1u<<log) ) { log++; }
4104 double CmiLog2(double x) {
4105 return log(x)/log(2);
4110 int CmiMyRank_(void)
4115 double CmiReadSize(const char *str)
4118 if (strpbrk(str,"Gg")) {
4119 //sscanf(str, "%llf", &val);
4120 //val = strtod(str, &p);
4122 val *= 1024ll*1024*1024;
4124 else if (strpbrk(str,"Mm")) {
4128 else if (strpbrk(str,"Kk")) {
4138 void CmiSetPeHelpsOtherThreads(int input) {
4139 CpvAccess(isHelperOn) = input;
4140 CmiMemoryWriteFence();