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 extern const char * const CmiCommitID;
91 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 void CcdModuleInit(char **);
110 void CmiMemoryInit(char **);
111 void CldModuleInit(char **);
113 #if CMK_WHEN_PROCESSOR_IDLE_USLEEP
114 #include <sys/types.h>
115 #include <sys/time.h>
118 #if CMK_TIMER_USE_TIMES
119 #include <sys/times.h>
124 #if CMK_TIMER_USE_GETRUSAGE
125 #include <sys/time.h>
126 #include <sys/resource.h>
129 #if CMK_TIMER_USE_RDTSC
134 #include <sys/time.h>
135 #include <sys/resource.h>
138 #ifdef CMK_TIMER_USE_WIN32API
141 #include <sys/types.h>
142 #include <sys/timeb.h>
145 #ifdef CMK_HAS_ASCTIME
149 #include "quiescence.h"
151 #if USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
155 #if CMK_TRACE_ENABLED
157 void traceAddThreadListeners(CthThread tid, struct envelope *env);
160 void seedBalancerExit(void);
161 void EmergencyExit(void);
163 //int cur_restart_phase = 1; /* checkpointing/restarting phase counter */
164 CpvDeclare(int,_curRestartPhase);
165 static int CsdLocalMax = CSD_LOCAL_MAX_DEFAULT;
167 int CharmLibInterOperate = 0;
168 CpvCExtern(int,interopExitFlag);
169 CpvDeclare(int,interopExitFlag);
171 CpvStaticDeclare(int, CmiMainHandlerIDP); /* Main handler for _CmiMultipleSend that is run on every node */
173 #if CMK_MEM_CHECKPOINT
174 void (*notify_crash_fn)(int) = NULL;
177 CpvDeclare(char *, _validProcessors);
180 CpvExtern(int, n_hapi_events);
181 extern "C" void hapiPollEvents();
182 extern "C" void exitHybridAPI();
185 /*****************************************************************************
187 * Unix Stub Functions
189 ****************************************************************************/
192 typedef unsigned long mmulong;
193 CpvDeclare(mmulong,MemoryUsage);
194 CpvDeclare(mmulong,HiWaterMark);
195 CpvDeclare(mmulong,ReportedHiWaterMark);
196 CpvDeclare(int,AllocCount);
197 CpvDeclare(int,BlocksAllocated);
200 #define MAX_HANDLERS 512
202 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
203 CpvDeclare(int,expIOFlushFlag);
204 #if CMI_IO_BUFFER_EXPLICIT
205 /* 250k not too large depending on how slow terminal IO is */
206 #define DEFAULT_IO_BUFFER_SIZE 250000
207 CpvDeclare(char*,explicitIOBuffer);
208 CpvDeclare(int,expIOBufferSize);
212 #if CMK_NODE_QUEUE_AVAILABLE
213 void *CmiGetNonLocalNodeQ();
216 CpvDeclare(Queue, CsdSchedQueue);
219 /* The Queue where the Prefetch Thread puts the messages from CsdSchedQueue */
220 CpvDeclare(Queue, CsdPrefetchQueue);
221 pthread_mutex_t prefetchLock;
224 #if CMK_NODE_QUEUE_AVAILABLE
225 CsvDeclare(Queue, CsdNodeQueue);
226 CsvDeclare(CmiNodeLock, CsdNodeQueueLock);
228 CpvDeclare(int, CsdStopFlag);
229 CpvDeclare(int, CsdLocalCounter);
231 CpvDeclare(int, _urgentSend);
233 CmiNodeLock _smp_mutex; /* for smp */
235 #if CMK_USE_IBVERBS | CMK_USE_IBUD
236 void *infi_CmiAlloc(int size);
237 void infi_CmiFree(void *ptr);
238 void infi_freeMultipleSend(void *ptr);
239 void infi_unregAndFreeMeta(void *ch);
242 #if CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
243 void * CmiAlloc_bgq (int size);
244 void CmiFree_bgq (void * buf);
247 #if CMK_SMP && CMK_PPC_ATOMIC_QUEUE
248 void * CmiAlloc_ppcq (int size);
249 void CmiFree_ppcq (void * buf);
252 #if CMK_GRID_QUEUE_AVAILABLE
253 CpvDeclare(void *, CkGridObject);
254 CpvDeclare(Queue, CsdGridQueue);
257 #if CMK_CRAYXE || CMK_CRAYXC || CMK_OFI
258 void* LrtsAlloc(int, int);
259 void* LrtsRdmaAlloc(int, int);
260 void LrtsFree(void*);
261 void LrtsRdmaFree(void*);
264 CpvStaticDeclare(int, cmiMyPeIdle);
265 #if CMK_SMP && CMK_TASKQUEUE
266 CsvDeclare(unsigned int, idleThreadsCnt);
267 CpvDeclare(Queue, CsdTaskQueue);
268 CpvDeclare(void *, CmiSuspendedTaskQueue);
271 CpvDeclare(int, isHelperOn);
273 extern int CmiMyLocalRank;
274 int CmiMyLocalRank; /* local rank only for scalable startup */
276 #if CMK_LOCKLESS_QUEUE
277 /*****************************************************************************
279 * MPSCQueue and MPMCQueue variables
281 *****************************************************************************/
287 int messageQueueOverflow;
290 /*****************************************************************************
292 * Command-Line Argument (CLA) parsing routines.
294 *****************************************************************************/
296 static int usageChecked=0; /* set when argv has been searched for a usage request */
297 static int printUsage=0; /* if set, print command-line usage information */
298 static const char *CLAformatString="%20s %10s %s\n";
300 /** This little list of CLA's holds the argument descriptions until it's
301 safe to print them--it's needed because the netlrts- versions don't have
302 printf until they're pretty well started.
305 const char *arg; /* Flag name, like "-foo"*/
306 const char *param; /* Argument's parameter type, like "integer" or "none"*/
307 const char *desc; /* Human-readable description of what it does */
309 static int CLAlistLen=0;
310 static int CLAlistMax=0;
311 static CLA *CLAlist=NULL;
314 static void CmiAddCLA(const char *arg,const char *param,const char *desc) {
316 if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
317 if (desc==NULL) return; /*It's an internal argument*/
318 if (usageChecked) { /* Printf should work now */
320 CmiPrintf(CLAformatString,arg,param,desc);
322 else { /* Printf doesn't work yet-- just add to the list.
323 This assumes the const char *'s are static references,
324 which is probably reasonable. */
327 if (CLAlistLen>CLAlistMax) { /*Grow the CLA list */
328 CLAlistMax=16+2*CLAlistLen;
329 temp = (CLA *)realloc(CLAlist,sizeof(CLA)*CLAlistMax);
334 CmiAbort("Reallocation failed for CLAlist\n");
338 CLAlist[i].param=param;
339 CLAlist[i].desc=desc;
343 /** Print out the stored list of CLA's */
344 static void CmiPrintCLAs(void) {
346 if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
347 CmiPrintf("Converse Machine Command-line Parameters:\n ");
348 CmiPrintf(CLAformatString,"Option:","Parameter:","Description:");
349 for (i=0;i<CLAlistLen;i++) {
351 CmiPrintf(CLAformatString,c->arg,c->param,c->desc);
356 * Determines if command-line usage information should be printed--
357 * that is, if a "-?", "-h", or "--help" flag is present.
358 * Must be called after printf is setup.
360 void CmiArgInit(char **argv) {
363 for (i=0;argv[i]!=NULL;i++)
365 if (0==strcmp(argv[i],"-?") ||
366 0==strcmp(argv[i],"-h") ||
367 0==strcmp(argv[i],"--help"))
370 /* Don't delete arg: CmiDeleteArgs(&argv[i],1);
371 Leave it there for user program to see... */
375 if (CmiMyPe()==0) { /* Throw away list of stored CLA's */
376 CLAlistLen=CLAlistMax=0;
377 free(CLAlist); CLAlist=NULL;
380 CmiUnlock(_smp_mutex);
383 /** Return 1 if we're currently printing command-line usage information. */
384 int CmiArgGivingUsage(void) {
385 return (CmiMyPe()==0) && printUsage;
388 /** Identifies the module that accepts the following command-line parameters */
389 void CmiArgGroup(const char *parentName,const char *groupName) {
390 if (CmiArgGivingUsage()) {
391 if (groupName==NULL) groupName=parentName; /* Start of a new group */
392 CmiPrintf("\n%s Command-line Parameters:\n",groupName);
396 /** Count the number of non-NULL arguments in list*/
397 int CmiGetArgc(char **argv)
401 while (argv[i++]!=NULL)
406 /** Return a new, heap-allocated copy of the argv array*/
407 char **CmiCopyArgs(char **argv)
409 int argc=CmiGetArgc(argv);
410 char **ret=(char **)malloc(sizeof(char *)*(argc+1));
412 for (i=0;i<=argc;i++)
417 /** Delete the first k argument from the given list, shifting
418 all other arguments down by k spaces.
419 e.g., argv=={"a","b","c","d",NULL}, k==3 modifies
420 argv={"d",NULL,"c","d",NULL}
422 void CmiDeleteArgs(char **argv,int k)
425 while ((argv[i]=argv[i+k])!=NULL)
429 /** Find the given argment and string option in argv.
430 If the argument is present, set the string option and
431 delete both from argv. If not present, return NULL.
432 e.g., arg=="-name" returns "bob" from
433 argv=={"a.out","foo","-name","bob","bar"},
434 and sets argv={"a.out","foo","bar"};
436 int CmiGetArgStringDesc(char **argv,const char *arg,char **optDest,const char *desc)
439 CmiAddCLA(arg,"string",desc);
440 for (i=0;argv[i]!=NULL;i++)
441 if (0==strcmp(argv[i],arg))
442 {/*We found the argument*/
443 if (argv[i+1]==NULL) CmiAbort("Argument not complete!");
445 CmiDeleteArgs(&argv[i],2);
448 return 0;/*Didn't find the argument*/
450 int CmiGetArgString(char **argv,const char *arg,char **optDest) {
451 return CmiGetArgStringDesc(argv,arg,optDest,"");
454 /** Find the given argument and floating-point option in argv.
455 Remove it and return 1; or return 0.
457 int CmiGetArgDoubleDesc(char **argv,const char *arg,double *optDest,const char *desc) {
459 CmiAddCLA(arg,"number",desc);
460 if (!CmiGetArgStringDesc(argv,arg,&number,NULL)) return 0;
461 if (1!=sscanf(number,"%lg",optDest)) return 0;
464 int CmiGetArgDouble(char **argv,const char *arg,double *optDest) {
465 return CmiGetArgDoubleDesc(argv,arg,optDest,"");
468 /** Find the given argument and integer option in argv.
469 If the argument is present, parse and set the numeric option,
470 delete both from argv, and return 1. If not present, return 0.
471 e.g., arg=="-pack" matches argv=={...,"-pack","27",...},
472 argv=={...,"-pack0xf8",...}, and argv=={...,"-pack=0777",...};
473 but not argv=={...,"-packsize",...}.
475 int CmiGetArgIntDesc(char **argv,const char *arg,int *optDest,const char *desc)
478 int argLen=strlen(arg);
479 CmiAddCLA(arg,"integer",desc);
480 for (i=0;argv[i]!=NULL;i++)
481 if (0==strncmp(argv[i],arg,argLen))
482 {/*We *may* have found the argument*/
483 const char *opt=NULL;
485 switch(argv[i][argLen]) {
486 case 0: /* like "-p","27" */
487 opt=argv[i+1]; nDel=2; break;
488 case '=': /* like "-p=27" */
489 opt=&argv[i][argLen+1]; nDel=1; break;
491 case '0':case '1':case '2':case '3':case '4':
492 case '5':case '6':case '7':case '8':case '9':
494 opt=&argv[i][argLen]; nDel=1; break;
496 continue; /*False alarm-- skip it*/
499 fprintf(stderr, "Command-line flag '%s' expects a numerical argument, "
500 "but none was provided\n", arg);
501 CmiAbort("Bad command-line argument\n");
503 if (sscanf(opt,"%i",optDest)<1) {
504 /*Bad command line argument-- die*/
505 fprintf(stderr,"Cannot parse %s option '%s' "
506 "as an integer.\n",arg,opt);
507 CmiAbort("Bad command-line argument\n");
509 CmiDeleteArgs(&argv[i],nDel);
512 return 0;/*Didn't find the argument-- dest is unchanged*/
514 int CmiGetArgInt(char **argv,const char *arg,int *optDest) {
515 return CmiGetArgIntDesc(argv,arg,optDest,"");
518 int CmiGetArgLongDesc(char **argv,const char *arg,CmiInt8 *optDest,const char *desc)
521 int argLen=strlen(arg);
522 CmiAddCLA(arg,"integer",desc);
523 for (i=0;argv[i]!=NULL;i++)
524 if (0==strncmp(argv[i],arg,argLen))
525 {/*We *may* have found the argument*/
526 const char *opt=NULL;
528 switch(argv[i][argLen]) {
529 case 0: /* like "-p","27" */
530 opt=argv[i+1]; nDel=2; break;
531 case '=': /* like "-p=27" */
532 opt=&argv[i][argLen+1]; nDel=1; break;
534 case '0':case '1':case '2':case '3':case '4':
535 case '5':case '6':case '7':case '8':case '9':
537 opt=&argv[i][argLen]; nDel=1; break;
539 continue; /*False alarm-- skip it*/
542 fprintf(stderr, "Command-line flag '%s' expects a numerical argument, "
543 "but none was provided\n", arg);
544 CmiAbort("Bad command-line argument\n");
546 if (sscanf(opt,"%" SCNd64,optDest)<1) {
547 /*Bad command line argument-- die*/
548 fprintf(stderr,"Cannot parse %s option '%s' "
549 "as a long integer.\n",arg,opt);
550 CmiAbort("Bad command-line argument\n");
552 CmiDeleteArgs(&argv[i],nDel);
555 return 0;/*Didn't find the argument-- dest is unchanged*/
557 int CmiGetArgLong(char **argv,const char *arg,CmiInt8 *optDest) {
558 return CmiGetArgLongDesc(argv,arg,optDest,"");
561 /** Find the given argument in argv. If present, delete
562 it and return 1; if not present, return 0.
563 e.g., arg=="-foo" matches argv=={...,"-foo",...} but not
564 argv={...,"-foobar",...}.
566 int CmiGetArgFlagDesc(char **argv,const char *arg,const char *desc)
569 CmiAddCLA(arg,"",desc);
570 for (i=0;argv[i]!=NULL;i++)
571 if (0==strcmp(argv[i],arg))
572 {/*We found the argument*/
573 CmiDeleteArgs(&argv[i],1);
576 return 0;/*Didn't find the argument*/
578 int CmiGetArgFlag(char **argv,const char *arg) {
579 return CmiGetArgFlagDesc(argv,arg,"");
582 void CmiDeprecateArgInt(char **argv,const char *arg,const char *desc,const char *warning)
584 int dummy = 0, found = CmiGetArgIntDesc(argv, arg, &dummy, desc);
590 /*****************************************************************************
592 * Stack tracing routines.
594 *****************************************************************************/
595 #include "cmibacktrace.C"
598 Convert "X(Y) Z" to "Y Z"-- remove text prior to first '(', and supress
599 the next parenthesis. Operates in-place on the character data.
600 or Convert X(Y) to "Y" only, when trimname=1
602 static char *_implTrimParenthesis(char *str, int trimname) {
603 char *lParen=str, *ret=NULL, *rParen=NULL;
604 while (*lParen!='(') {
605 if (*lParen==0) return str; /* No left parenthesis at all. */
608 /* now *lParen=='(', so trim it*/
611 while (*rParen!=')') {
612 if (*rParen==0) return ret; /* No right parenthesis at all. */
615 /* now *rParen==')', so trim it*/
616 *rParen=trimname?0:' ';
621 Return the text description of this trimmed routine name, if
622 it's a system-generated routine where we should stop printing.
623 This is probably overkill, but improves the appearance of callbacks.
625 static const char* _implGetBacktraceSys(const char *name) {
626 if (0==strncmp(name,"_call",5))
627 { /*it might be something we're interested in*/
628 if (0==strncmp(name,"_call_",6)) return "Call Entry Method";
629 if (0==strncmp(name,"_callthr_",9)) return "Call Threaded Entry Method";
631 if (0==strncmp(name,"CthResume",9)) return "Resumed thread";
632 if (0==strncmp(name,"qt_args",7)) return "Converse thread";
634 return 0; /*ordinary user routine-- just print normally*/
637 /** Print out the names of these function pointers. */
638 void CmiBacktracePrint(void **retPtrs,int nLevels) {
641 char **names=CmiBacktraceLookup(retPtrs,nLevels);
642 if (names==NULL) return;
643 CmiPrintf("[%d] Stack Traceback:\n", CmiMyPe());
644 for (i=0;i<nLevels;i++) {
645 if (names[i] == NULL) continue;
647 const char *trimmed=_implTrimParenthesis(names[i], 0);
648 const char *print=trimmed;
649 const char *sys=_implGetBacktraceSys(print);
651 CmiPrintf(" [%d] Charm++ Runtime: %s (%s)\n",i,sys,print);
652 break; /*Stop when we hit Charm++ runtime.*/
654 CmiPrintf(" [%d:%d] %s\n",CmiMyPe(),i,print);
662 /* Print (to stdout) the names of the functions that have been
663 called up to this point. nSkip is the number of routines on the
664 top of the stack to *not* print out. */
665 void CmiPrintStackTrace(int nSkip) {
666 #if CMK_USE_BACKTRACE
667 int nLevels=max_stack;
668 void *stackPtrs[max_stack];
669 CmiBacktraceRecord(stackPtrs,1+nSkip,&nLevels);
670 CmiBacktracePrint(stackPtrs,nLevels);
674 int CmiIsFortranLibraryCall(void) {
675 #if CMK_USE_BACKTRACE
679 CmiBacktraceRecord(stackPtrs,1,&nLevels);
682 char **names=CmiBacktraceLookup(stackPtrs,nLevels);
684 if (names==NULL) return 0;
685 for (i=0;i<nLevels;i++) {
686 if (names[i] == NULL) continue;
687 trimmed=_implTrimParenthesis(names[i], 1);
688 if (strncmp(trimmed, "for__", 5) == 0 /* ifort */
689 || strncmp(trimmed, "_xlf", 4) == 0 /* xlf90 */
690 || strncmp(trimmed, "_xlfBeginIO", 11) == 0
691 || strncmp(trimmed, "_gfortran_", 10) == 0
693 { /* CmiPrintf("[%d] NAME:%s\n", CmiMyPe(), trimmed); */
704 /*****************************************************************************
706 * Statistics: currently, the following statistics are not updated by converse.
708 *****************************************************************************/
710 CpvDeclare(int, CstatsMaxChareQueueLength);
711 CpvDeclare(int, CstatsMaxForChareQueueLength);
712 CpvDeclare(int, CstatsMaxFixedChareQueueLength);
713 CpvStaticDeclare(int, CstatPrintQueueStatsFlag);
714 CpvStaticDeclare(int, CstatPrintMemStatsFlag);
716 void CstatsInit(char ** argv)
720 CpvInitialize(mmulong,MemoryUsage);
721 CpvAccess(MemoryUsage) = 0;
722 CpvInitialize(mmulong,HiWaterMark);
723 CpvAccess(HiWaterMark) = 0;
724 CpvInitialize(mmulong,ReportedHiWaterMark);
725 CpvAccess(ReportedHiWaterMark) = 0;
726 CpvInitialize(int,AllocCount);
727 CpvAccess(AllocCount) = 0;
728 CpvInitialize(int,BlocksAllocated);
729 CpvAccess(BlocksAllocated) = 0;
732 CpvInitialize(int, CstatsMaxChareQueueLength);
733 CpvInitialize(int, CstatsMaxForChareQueueLength);
734 CpvInitialize(int, CstatsMaxFixedChareQueueLength);
735 CpvInitialize(int, CstatPrintQueueStatsFlag);
736 CpvInitialize(int, CstatPrintMemStatsFlag);
738 CpvAccess(CstatsMaxChareQueueLength) = 0;
739 CpvAccess(CstatsMaxForChareQueueLength) = 0;
740 CpvAccess(CstatsMaxFixedChareQueueLength) = 0;
741 CpvAccess(CstatPrintQueueStatsFlag) = 0;
742 CpvAccess(CstatPrintMemStatsFlag) = 0;
745 if (CmiGetArgFlagDesc(argv,"+mems", "Print memory statistics at shutdown"))
746 CpvAccess(CstatPrintMemStatsFlag)=1;
747 if (CmiGetArgFlagDesc(argv,"+qs", "Print queue statistics at shutdown"))
748 CpvAccess(CstatPrintQueueStatsFlag)=1;
752 int CstatMemory(int i)
757 int CstatPrintQueueStats(void)
759 return CpvAccess(CstatPrintQueueStatsFlag);
762 int CstatPrintMemStats(void)
764 return CpvAccess(CstatPrintMemStatsFlag);
767 /*****************************************************************************
769 * Cmi handler registration
771 *****************************************************************************/
773 CpvDeclare(CmiHandlerInfo*, CmiHandlerTable);
774 CpvStaticDeclare(int , CmiHandlerCount);
775 CpvStaticDeclare(int , CmiHandlerLocal);
776 CpvStaticDeclare(int , CmiHandlerGlobal);
777 CpvDeclare(int, CmiHandlerMax);
779 static void CmiExtendHandlerTable(int atLeastLen) {
780 int max = CpvAccess(CmiHandlerMax);
781 int newmax = (atLeastLen+(atLeastLen>>2)+32);
782 int bytes = max*sizeof(CmiHandlerInfo);
783 int newbytes = newmax*sizeof(CmiHandlerInfo);
784 CmiHandlerInfo *nu = (CmiHandlerInfo*)malloc(newbytes);
785 CmiHandlerInfo *tab = CpvAccess(CmiHandlerTable);
788 memcpy(nu, tab, bytes);
790 memset(((char *)nu)+bytes, 0, (newbytes-bytes));
792 CpvAccess(CmiHandlerTable) = tab;
793 CpvAccess(CmiHandlerMax) = newmax;
796 void CmiAssignOnce(int* variable, int value) {
797 if (CmiMyRank() == 0) { *variable = value; }
801 void CmiNumberHandler(int n, CmiHandler h)
804 if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
805 tab = CpvAccess(CmiHandlerTable);
806 tab[n].hdlr = (CmiHandlerEx)h; /* LIE! This assumes extra pointer will be ignored!*/
809 void CmiNumberHandlerEx(int n, CmiHandlerEx h,void *userPtr) {
811 if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
812 tab = CpvAccess(CmiHandlerTable);
814 tab[n].userPtr=userPtr;
817 #if CMI_LOCAL_GLOBAL_AVAILABLE /*Leave room for local and global handlers*/
818 # define DIST_BETWEEN_HANDLERS 3
819 #else /*No local or global handlers; ordinary handlers are back-to-back*/
820 # define DIST_BETWEEN_HANDLERS 1
823 int CmiRegisterHandler(CmiHandler h)
825 int Count = CpvAccess(CmiHandlerCount);
826 CmiNumberHandler(Count, h);
827 CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
831 void CmiRegisterHandlerAssignOnce(CmiHandler h, int *index)
833 if (CmiMyRank() == 0) { *index = CmiRegisterHandler(h); }
834 else { CmiRegisterHandler(h); }
838 int CmiRegisterHandlerEx(CmiHandlerEx h,void *userPtr)
840 int Count = CpvAccess(CmiHandlerCount);
841 CmiNumberHandlerEx(Count, h, userPtr);
842 CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
846 void CmiRegisterHandlerExAssignOnce(CmiHandlerEx h, void *userPtr, int *index)
848 if (CmiMyRank() == 0) { *index = CmiRegisterHandlerEx(h, userPtr); }
849 else { CmiRegisterHandlerEx(h, userPtr); }
853 #if CMI_LOCAL_GLOBAL_AVAILABLE
854 int CmiRegisterHandlerLocal(CmiHandler h)
856 int Local = CpvAccess(CmiHandlerLocal);
857 CmiNumberHandler(Local, h);
858 CpvAccess(CmiHandlerLocal) = Local+3;
862 int CmiRegisterHandlerGlobal(CmiHandler h)
864 int Global = CpvAccess(CmiHandlerGlobal);
866 CmiError("CmiRegisterHandlerGlobal must only be called on PE 0.\n");
867 CmiNumberHandler(Global, h);
868 CpvAccess(CmiHandlerGlobal) = Global+3;
873 static void _cmiZeroHandler(void *msg) {
874 CmiAbort("Converse zero handler executed-- was a message corrupted?\n");
877 static void CmiHandlerInit(void)
879 CpvInitialize(CmiHandlerInfo *, CmiHandlerTable);
880 CpvInitialize(int , CmiHandlerCount);
881 CpvInitialize(int , CmiHandlerLocal);
882 CpvInitialize(int , CmiHandlerGlobal);
883 CpvInitialize(int , CmiHandlerMax);
884 CpvAccess(CmiHandlerCount) = 0;
885 CpvAccess(CmiHandlerLocal) = 1;
886 CpvAccess(CmiHandlerGlobal) = 2;
887 CpvAccess(CmiHandlerMax) = 0; /* Table will be extended on the first registration*/
888 CpvAccess(CmiHandlerTable) = NULL;
889 CmiRegisterHandler((CmiHandler)_cmiZeroHandler);
893 /******************************************************************************
897 * Here are two possible implementations of CmiTimer. Some machines don't
898 * select either, and define the timer in machine.C instead.
900 *****************************************************************************/
904 char *CmiPrintDate(void)
910 local = localtime(&t);
911 return asctime(local);
916 char *CmiPrintDate(void)
923 static int _absoluteTime = 0;
925 #if CMK_TIMER_USE_TIMES
927 CpvStaticDeclare(double, clocktick);
928 CpvStaticDeclare(int,inittime_wallclock);
929 CpvStaticDeclare(int,inittime_virtual);
931 int CmiTimerIsSynchronized(void)
936 int CmiTimerAbsolute(void)
941 double CmiStartTimer(void)
946 double CmiInitTime(void)
948 return CpvAccess(inittime_wallclock);
951 void CmiTimerInit(char **argv)
954 CpvInitialize(double, clocktick);
955 CpvInitialize(int, inittime_wallclock);
956 CpvInitialize(int, inittime_virtual);
957 CpvAccess(inittime_wallclock) = times(&temp);
958 CpvAccess(inittime_virtual) = temp.tms_utime + temp.tms_stime;
959 CpvAccess(clocktick) = 1.0 / (sysconf(_SC_CLK_TCK));
962 double CmiWallTimer(void)
969 currenttime = (now - CpvAccess(inittime_wallclock)) * CpvAccess(clocktick);
970 return (currenttime);
973 double CmiCpuTimer(void)
980 now = temp.tms_stime + temp.tms_utime;
981 currenttime = (now - CpvAccess(inittime_virtual)) * CpvAccess(clocktick);
982 return (currenttime);
985 double CmiTimer(void)
987 return CmiCpuTimer();
992 #if CMK_TIMER_USE_GETRUSAGE
995 # if CMK_HAS_RUSAGE_THREAD
996 #define RUSAGE_WHO 1 /* RUSAGE_THREAD, only in latest Linux kernels */
1001 #define RUSAGE_WHO 0
1004 static double inittime_wallclock;
1005 CpvStaticDeclare(double, inittime_virtual);
1007 int CmiTimerIsSynchronized(void)
1012 int CmiTimerAbsolute(void)
1014 return _absoluteTime;
1017 double CmiStartTimer(void)
1022 double CmiInitTime(void)
1024 return inittime_wallclock;
1027 void CmiTimerInit(char **argv)
1030 CpvInitialize(double, inittime_virtual);
1032 int tmptime = CmiGetArgFlagDesc(argv,"+useAbsoluteTime", "Use system's absolute time as wallclock time.");
1033 if(CmiMyRank() == 0) _absoluteTime = tmptime; /* initialize only once */
1035 /* try to synchronize calling barrier */
1040 if(CmiMyRank() == 0) /* initialize only once */
1042 inittime_wallclock = inithrc();
1044 CpvAccess(inittime_virtual) = inittime_wallclock;
1046 getrusage(RUSAGE_WHO, &ru);
1047 CpvAccess(inittime_virtual) =
1048 (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1049 (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1055 /* CmiBarrierZero(); */
1059 double CmiCpuTimer(void)
1062 return CmiWallTimer();
1067 getrusage(RUSAGE_WHO, &ru);
1069 (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1070 (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1072 return currenttime - CpvAccess(inittime_virtual);
1076 static double lastT = -1.0;
1078 double CmiWallTimer(void)
1081 currenttime = gethrctime();
1082 return _absoluteTime?currenttime+inittime_wallclock:currenttime;
1085 double CmiTimer(void)
1087 return CmiCpuTimer();
1092 #if CMK_TIMER_USE_RDTSC
1094 static double readMHz(void)
1100 CmiLock(_smp_mutex);
1101 fp = fopen("/proc/cpuinfo", "r");
1103 while(fgets(str, 1000, fp)!=0) {
1104 if(sscanf(str, "cpu MHz%[^:]",buf)==1)
1106 char *s = strchr(str, ':'); s=s+1;
1107 sscanf(s, "%lf", &x);
1109 CmiUnlock(_smp_mutex);
1113 CmiUnlock(_smp_mutex);
1114 CmiAbort("Cannot read CPU MHz from /proc/cpuinfo file.");
1118 double _cpu_speed_factor;
1119 CpvStaticDeclare(double, inittime_virtual);
1120 CpvStaticDeclare(double, inittime_walltime);
1122 double CmiStartTimer(void)
1124 return CpvAccess(inittime_walltime);
1127 double CmiInitTime(void)
1129 return CpvAccess(inittime_walltime);
1132 void CmiTimerInit(char **argv)
1139 _cpu_speed_factor = 1.0/(readMHz()*1.0e6);
1140 rdtsc(); rdtsc(); rdtsc(); rdtsc(); rdtsc();
1141 CpvInitialize(double, inittime_walltime);
1142 CpvAccess(inittime_walltime) = CmiWallTimer();
1143 CpvInitialize(double, inittime_virtual);
1145 CpvAccess(inittime_virtual) =
1146 (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1147 (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1152 double CmiCpuTimer(void)
1159 (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1160 (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1161 return currenttime - CpvAccess(inittime_virtual);
1166 #if CMK_TIMER_USE_BLUEGENEQ /* This module just compiles with GCC charm. */
1168 CpvStaticDeclare(unsigned long, inittime);
1169 CpvStaticDeclare(double, clocktick);
1171 int CmiTimerIsSynchronized(void)
1176 int CmiTimerAbsolute(void)
1181 #include "hwi/include/bqc/A2_inlines.h"
1182 #include "spi/include/kernel/process.h"
1184 double CmiStartTimer(void)
1189 double CmiInitTime(void)
1191 return CpvAccess(inittime);
1194 void CmiTimerInit(char **argv)
1196 CpvInitialize(double, clocktick);
1197 CpvInitialize(unsigned long, inittime);
1200 Kernel_GetPersonality(&pers, sizeof(pers));
1201 uint32_t clockMhz = pers.Kernel_Config.FreqMHz;
1202 CpvAccess(clocktick) = 1.0 / (clockMhz * 1e6);
1204 /*fprintf(stderr, "Blue Gene/Q running at clock speed of %d Mhz\n", clockMhz);*/
1206 /* try to synchronize calling barrier */
1212 CpvAccess(inittime) = GetTimeBase ();
1215 double CmiWallTimer(void)
1217 unsigned long long currenttime;
1218 currenttime = GetTimeBase();
1219 return CpvAccess(clocktick)*(currenttime-CpvAccess(inittime));
1222 double CmiCpuTimer(void)
1224 return CmiWallTimer();
1227 double CmiTimer(void)
1229 return CmiWallTimer();
1235 #if CMK_TIMER_USE_PPC64
1237 #include <sys/time.h>
1238 #include <sys/platform/ppc.h>
1240 CpvStaticDeclare(uint64_t, inittime);
1241 CpvStaticDeclare(double, clocktick);
1243 int CmiTimerIsSynchronized(void)
1248 int CmiTimerAbsolute(void)
1253 double CmiStartTimer(void)
1258 double CmiInitTime(void)
1260 return CpvAccess(inittime);
1263 static inline uint64_t PPC64_TimeBase(void)
1265 register volatile uint64_t result;
1267 /* For 64-bit only */
1277 void CmiTimerInit(char **argv)
1279 CpvInitialize(double, clocktick);
1280 CpvInitialize(unsigned long, inittime);
1281 CpvAccess(clocktick) = 1.0 / ((double) __ppc_get_timebase_freq());
1283 /* try to synchronize calling barrier */
1289 CpvAccess(inittime) = PPC64_TimeBase ();
1292 double CmiWallTimer(void)
1294 uint64_t currenttime;
1295 currenttime = PPC64_TimeBase();
1296 return CpvAccess(clocktick)*(currenttime-CpvAccess(inittime));
1299 double CmiCpuTimer(void)
1301 return CmiWallTimer();
1304 double CmiTimer(void)
1306 return CmiWallTimer();
1312 #if CMK_TIMER_USE_WIN32API
1314 CpvStaticDeclare(double, inittime_wallclock);
1315 CpvStaticDeclare(double, inittime_virtual);
1317 double CmiStartTimer(void)
1322 int CmiTimerAbsolute(void)
1327 double CmiInitTime(void)
1329 return CpvAccess(inittime_wallclock);
1332 void CmiTimerInit(char **argv)
1337 CpvInitialize(double, inittime_wallclock);
1338 CpvInitialize(double, inittime_virtual);
1340 CpvAccess(inittime_wallclock) = tv.time*1.0 + tv.millitm*0.001;
1342 CpvAccess(inittime_virtual) = ((double) ru)/CLOCKS_PER_SEC;
1345 double CmiCpuTimer(void)
1351 currenttime = (double) ru/CLOCKS_PER_SEC;
1353 return currenttime - CpvAccess(inittime_virtual);
1356 double CmiWallTimer(void)
1362 currenttime = tv.time*1.0 + tv.millitm*0.001;
1364 return currenttime - CpvAccess(inittime_wallclock);
1368 double CmiTimer(void)
1370 return CmiCpuTimer();
1375 #if CMK_TIMER_USE_RTC
1377 static double clocktick;
1378 CpvStaticDeclare(long long, inittime_wallclock);
1380 double CmiStartTimer(void)
1385 double CmiInitTime(void)
1387 return CpvAccess(inittime_wallclock);
1390 void CmiTimerInit(char **argv)
1392 CpvInitialize(long long, inittime_wallclock);
1393 CpvAccess(inittime_wallclock) = _rtc();
1394 clocktick = 1.0 / (double)(sysconf(_SC_SV2_USER_TIME_RATE));
1397 int CmiTimerAbsolute(void)
1402 double CmiWallTimer(void)
1407 return (clocktick * (now - CpvAccess(inittime_wallclock)));
1410 double CmiCpuTimer(void)
1412 return CmiWallTimer();
1415 double CmiTimer(void)
1417 return CmiCpuTimer();
1422 #if CMK_TIMER_USE_AIX_READ_TIME
1424 #include <sys/time.h>
1426 static timebasestruct_t inittime_wallclock;
1427 static double clocktick;
1428 CpvStaticDeclare(double, inittime_virtual);
1430 double CmiStartTimer(void)
1435 double CmiInitTime(void)
1437 return inittime_wallclock;
1440 void CmiTimerInit(char **argv)
1444 if (CmiMyRank() == 0) {
1445 read_wall_time(&inittime_wallclock, TIMEBASE_SZ);
1446 time_base_to_time(&inittime_wallclock, TIMEBASE_SZ);
1449 CpvInitialize(double, inittime_virtual);
1451 CpvAccess(inittime_virtual) =
1452 (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1453 (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1456 int CmiTimerAbsolute(void)
1461 double CmiWallTimer(void)
1465 timebasestruct_t now;
1466 read_wall_time(&now, TIMEBASE_SZ);
1467 time_base_to_time(&now, TIMEBASE_SZ);
1469 secs = now.tb_high - inittime_wallclock.tb_high;
1470 n_secs = now.tb_low - inittime_wallclock.tb_low;
1473 n_secs += 1000000000;
1475 curt = secs*1.0 + n_secs*1e-9;
1479 double CmiCpuTimer(void)
1486 (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1487 (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1488 return currenttime - CpvAccess(inittime_virtual);
1491 double CmiTimer(void)
1493 return CmiWallTimer();
1498 #ifndef CMK_USE_SPECIAL_MESSAGE_QUEUE_CHECK
1499 /** Return 1 if our outgoing message queue
1500 for this node is longer than this many bytes. */
1501 int CmiLongSendQueue(int forNode,int longerThanBytes) {
1506 #if CMK_SIGNAL_USE_SIGACTION
1508 void CmiSignal(int sig1, int sig2, int sig3, void (*handler)(int))
1510 struct sigaction in, out ;
1511 in.sa_handler = handler;
1512 sigemptyset(&in.sa_mask);
1513 if (sig1) sigaddset(&in.sa_mask, sig1);
1514 if (sig2) sigaddset(&in.sa_mask, sig2);
1515 if (sig3) sigaddset(&in.sa_mask, sig3);
1517 if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1518 if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1519 if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1523 #if CMK_SIGNAL_USE_SIGACTION_WITH_RESTART
1525 void CmiSignal(int sig1, int sig2, int sig3, void (*handler)(int))
1527 struct sigaction in, out ;
1528 in.sa_handler = handler;
1529 sigemptyset(&in.sa_mask);
1530 if (sig1) sigaddset(&in.sa_mask, sig1);
1531 if (sig2) sigaddset(&in.sa_mask, sig2);
1532 if (sig3) sigaddset(&in.sa_mask, sig3);
1533 in.sa_flags = SA_RESTART;
1534 if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1535 if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1536 if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1541 * @addtogroup ConverseScheduler
1545 /*****************************************************************************
1547 * The following is the CsdScheduler function. A common
1548 * implementation is provided below. The machine layer can provide an
1549 * alternate implementation if it so desires.
1551 * void CmiDeliversInit()
1553 * - CmiInit promises to call this before calling CmiDeliverMsgs
1554 * or any of the other functions in this section.
1556 * int CmiDeliverMsgs(int maxmsgs)
1558 * - CmiDeliverMsgs will retrieve up to maxmsgs that were transmitted
1559 * with the Cmi, and will invoke their handlers. It does not wait
1560 * if no message is unavailable. Instead, it returns the quantity
1561 * (maxmsgs-delivered), where delivered is the number of messages it
1564 * void CmiDeliverSpecificMsg(int handlerno)
1566 * - Waits for a message with the specified handler to show up, then
1567 * invokes the message's handler. Note that unlike CmiDeliverMsgs,
1568 * This function _does_ wait.
1570 * For this common implementation to work, the machine layer must provide the
1573 * void *CmiGetNonLocal()
1575 * - returns a message just retrieved from some other PE, not from
1576 * local. If no such message exists, returns 0.
1578 * CpvExtern(CdsFifo, CmiLocalQueue);
1580 * - a FIFO queue containing all messages from the local processor.
1582 *****************************************************************************/
1584 void CsdBeginIdle(void)
1587 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1588 _LOG_E_PROC_IDLE(); /* projector */
1590 #if CMK_SMP && CMK_TASKQUEUE
1591 if (CpvAccess(cmiMyPeIdle) !=1) {
1592 CpvAccess(cmiMyPeIdle) = 1;
1593 CmiMemoryAtomicIncrement(CsvAccess(idleThreadsCnt), memory_order_relaxed);
1596 CpvAccess(cmiMyPeIdle) = 1;
1598 CcdRaiseCondition(CcdPROCESSOR_BEGIN_IDLE) ;
1601 void CsdStillIdle(void)
1603 CcdRaiseCondition(CcdPROCESSOR_STILL_IDLE);
1606 void CsdEndIdle(void)
1608 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1609 _LOG_E_PROC_BUSY(); /* projector */
1611 #if CMK_SMP && CMK_TASKQUEUE
1612 if (CpvAccess(cmiMyPeIdle) != 0){
1613 CpvAccess(cmiMyPeIdle) = 0;
1614 CmiMemoryAtomicDecrement(CsvAccess(idleThreadsCnt), memory_order_relaxed);
1617 CpvAccess(cmiMyPeIdle) = 0;
1619 CcdRaiseCondition(CcdPROCESSOR_BEGIN_BUSY) ;
1622 extern int _exitHandlerIdx;
1624 /** Takes a message and calls its corresponding handler. */
1625 void CmiHandleMessage(void *msg)
1627 /* this is wrong because it counts the Charm++ messages in sched queue
1628 CpvAccess(cQdState)->mProcessed++;
1631 CmiUInt2 handlerIdx=CmiGetHandler(msg); /* Save handler for use after msg is gone */
1632 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1633 _LOG_E_HANDLER_BEGIN(handlerIdx); /* projector */
1634 /* setMemoryStatus(1) */ /* charmdebug */
1640 /* if((!CpvAccess(_validProcessors)[CmiMyPe()]) && handler != _exitHandlerIdx){
1644 MESSAGE_PHASE_CHECK(msg)
1645 #if CMK_ERROR_CHECKING
1646 if (handlerIdx >= CpvAccess(CmiHandlerCount)) {
1647 CmiAbort("Msg handler does not exist, possible race condition during init\n");
1650 h=&CmiHandlerToInfo(handlerIdx);
1651 #if CMK_ERROR_CHECKING
1652 if (h->hdlr == NULL) {
1653 CmiAbort("Msg handler does not exist, possible race condition during init\n");
1656 (h->hdlr)(msg,h->userPtr);
1657 #if CMK_TRACE_ENABLED
1658 /* setMemoryStatus(0) */ /* charmdebug */
1659 //_LOG_E_HANDLER_END(handlerIdx); /* projector */
1663 #if CMK_CMIDELIVERS_USE_COMMON_CODE
1665 void CmiDeliversInit(void)
1669 int CmiDeliverMsgs(int maxmsgs)
1671 return CsdScheduler(maxmsgs);
1674 #if CMK_OBJECT_QUEUE_AVAILABLE
1675 CpvDeclare(void *, CsdObjQueue);
1678 void CsdSchedulerState_new(CsdSchedulerState_t *s)
1680 #if CMK_OBJECT_QUEUE_AVAILABLE
1681 s->objQ=CpvAccess(CsdObjQueue);
1683 s->localQ=CpvAccess(CmiLocalQueue);
1684 s->schedQ=CpvAccess(CsdSchedQueue);
1685 s->localCounter=&(CpvAccess(CsdLocalCounter));
1686 #if CMK_NODE_QUEUE_AVAILABLE
1687 s->nodeQ=CsvAccess(CsdNodeQueue);
1688 s->nodeLock=CsvAccess(CsdNodeQueueLock);
1690 #if CMK_GRID_QUEUE_AVAILABLE
1691 s->gridQ=CpvAccess(CsdGridQueue);
1693 #if CMK_SMP && CMK_TASKQUEUE
1694 s->taskQ = CpvAccess(CsdTaskQueue);
1695 s->suspendedTaskQ = CpvAccess(CmiSuspendedTaskQueue);
1700 /** Dequeue and return the next message from the unprocessed message queues.
1702 * This function encapsulates the multiple queues that exist for holding unprocessed
1703 * messages and the rules for the order in which to check them. There are five (5)
1704 * different Qs that converse uses to store and retrieve unprocessed messages. These
1706 * Q Purpose Type internal DeQ logic
1707 * -----------------------------------------------------------
1708 * - PE offnode pcQ FIFO
1709 * - PE onnode CkQ FIFO
1710 * - Node offnode pcQ FIFO
1711 * - Node onnode prioQ prio-based
1712 * - Scheduler prioQ prio-based
1714 * The PE queues hold messages that are destined for a specific PE. There is one such
1715 * queue for every PE within a charm node. The node queues hold messages that are
1716 * destined to that node. There is only one of each node queue within a charm node.
1717 * Finally there is also a charm++ message queue for each PE.
1719 * The offnode queues are meant for holding messages that arrive from outside the
1720 * node. The onnode queues hold messages that are generated within the same charm
1723 * The PE and node level offnode queues are accessed via functions CmiGetNonLocal()
1724 * and CmiGetNonLocalNodeQ(). These are implemented separately by each machine layer
1725 * and hide the implementation specifics for each layer.
1727 * The PE onnode queue is implemented as a FIFO CkQ and is initialized via a call to
1728 * CdsFifo_Create(). The node local queue and the scheduler queue are both priority
1729 * queues. They are initialized via calls to CqsCreate() which gives each of them
1730 * three separate internal queues for different priority ranges (-ve, 0 and +ve).
1731 * Access to these queues is via pointers stored in the struct CsdSchedulerState that
1732 * is passed into this function.
1734 * The order in which these queues are checked is described below. The function
1735 * proceeds to the next queue in the list only if it does not find any messages in
1736 * the current queue. The first message that is found is returned, terminating the
1738 * (1) offnode queue for this PE
1739 * (2) onnode queue for this PE
1740 * (3) offnode queue for this node
1741 * (4) highest priority msg from onnode queue or scheduler queue
1743 * @note: Across most (all?) machine layers, the two GetNonLocal functions simply
1744 * access (after observing adequate locking rigor) structs representing the scheduler
1745 * state, to dequeue from the queues stored within them. The structs (CmiStateStruct
1746 * and CmiNodeStateStruct) implement these queues as \ref Machine "pc (producer-consumer)
1747 * queues". The functions also perform other necessary actions like PumpMsgs() etc.
1750 void *CsdNextMessage(CsdSchedulerState_t *s) {
1752 if((*(s->localCounter))-- >0)
1754 /* This avoids a race condition with migration detected by megatest*/
1755 msg=CdsFifo_Dequeue(s->localQ);
1759 CpvAccess(cQdState)->mProcessed++;
1763 CqsDequeue(s->schedQ,(void **)&msg);
1764 if (msg!=NULL) return msg;
1767 *(s->localCounter)=CsdLocalMax;
1768 if ( NULL!=(msg=CmiGetNonLocal()) ||
1769 NULL!=(msg=CdsFifo_Dequeue(s->localQ)) ) {
1771 CpvAccess(cQdState)->mProcessed++;
1775 #if CMK_GRID_QUEUE_AVAILABLE
1776 /*#warning "CsdNextMessage: CMK_GRID_QUEUE_AVAILABLE" */
1777 CqsDequeue (s->gridQ, (void **) &msg);
1782 #if CMK_SMP && CMK_TASKQUEUE
1784 msg = CmiSuspendedTaskPop();
1789 msg = TaskQueuePop((TaskQueue)s->taskQ);
1794 #if CMK_NODE_QUEUE_AVAILABLE
1795 /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1796 if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;
1797 #if !CMK_NO_MSG_PRIOS
1798 if (!CqsEmpty(s->nodeQ)
1799 && CqsPrioGT(CqsGetPriority(s->schedQ),
1800 CqsGetPriority(s->nodeQ))) {
1801 if(CmiTryLock(s->nodeLock) == 0) {
1802 CqsDequeue(s->nodeQ,(void **)&msg);
1803 CmiUnlock(s->nodeLock);
1804 if (msg!=NULL) return msg;
1809 #if CMK_OBJECT_QUEUE_AVAILABLE
1810 /*#warning "CsdNextMessage: CMK_OBJECT_QUEUE_AVAILABLE" */
1811 if (NULL!=(msg=CdsFifo_Dequeue(s->objQ))) {
1816 CqsDequeue(s->schedQ,(void **)&msg);
1817 if (msg!=NULL) return msg;
1823 void *CsdNextLocalNodeMessage(CsdSchedulerState_t *s) {
1825 #if CMK_NODE_QUEUE_AVAILABLE
1826 /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1827 /*if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;*/
1828 if (!CqsEmpty(s->nodeQ))
1830 CmiLock(s->nodeLock);
1831 CqsDequeue(s->nodeQ,(void **)&msg);
1832 CmiUnlock(s->nodeLock);
1833 if (msg!=NULL) return msg;
1840 int CsdScheduler(int maxmsgs)
1842 if (maxmsgs<0) CsdScheduleForever();
1843 else if (maxmsgs==0)
1845 else /*(maxmsgs>0)*/
1846 return CsdScheduleCount(maxmsgs);
1850 /*Declare the standard scheduler housekeeping*/
1851 #define SCHEDULE_TOP \
1853 int *CsdStopFlag_ptr = &CpvAccess(CsdStopFlag); \
1854 int cycle = CpvAccess(CsdStopFlag); \
1855 CsdSchedulerState_t state;\
1856 CsdSchedulerState_new(&state);
1858 /*A message is available-- process it*/
1859 #define SCHEDULE_MESSAGE \
1860 CmiHandleMessage(msg);\
1861 if (*CsdStopFlag_ptr != cycle) break;
1863 /*No message available-- go (or remain) idle*/
1864 #if CSD_NO_IDLE_TRACING
1865 #define SCHEDULE_IDLE /* do nothing */
1867 #define SCHEDULE_IDLE \
1868 if (!isIdle) {isIdle=1;CsdBeginIdle();}\
1869 else CsdStillIdle();\
1870 if (*CsdStopFlag_ptr != cycle) {\
1881 extern void machine_OffloadAPIProgress(void);
1883 /** The main scheduler loop that repeatedly executes messages from a queue, forever. */
1884 void CsdScheduleForever(void)
1887 #define CMK_CELL_PROGRESS_FREQ 96 /* (MSG-Q Entries x1.5) */
1888 int progressCount = CMK_CELL_PROGRESS_FREQ;
1895 /* The interoperation will cost this little overhead in scheduling */
1896 if(CharmLibInterOperate) {
1897 if(CpvAccess(interopExitFlag)) {
1898 CpvAccess(interopExitFlag) = 0;
1904 // check if any GPU work needs to be processed
1905 if (CpvAccess(n_hapi_events) > 0) {
1909 msg = CsdNextMessage(&state);
1910 if (msg!=NULL) { /*A message is available-- process it*/
1911 #if !CSD_NO_IDLE_TRACING
1912 if (isIdle) {isIdle=0;CsdEndIdle();}
1917 if (progressCount <= 0) {
1918 /*OffloadAPIProgress();*/
1919 machine_OffloadAPIProgress();
1920 progressCount = CMK_CELL_PROGRESS_FREQ;
1924 } else { /*No message available-- go (or remain) idle*/
1928 /*OffloadAPIProgress();*/
1929 machine_OffloadAPIProgress();
1930 progressCount = CMK_CELL_PROGRESS_FREQ;
1933 #if !CSD_NO_PERIODIC
1938 int CsdScheduleCount(int maxmsgs)
1943 msg = CsdNextMessage(&state);
1944 if (msg!=NULL) { /*A message is available-- process it*/
1945 #if !CSD_NO_IDLE_TRACING
1946 if (isIdle) {isIdle=0;CsdEndIdle();}
1950 if (maxmsgs==0) break;
1951 } else { /*No message available-- go (or remain) idle*/
1954 #if !CSD_NO_PERIODIC
1961 void CsdSchedulePoll(void)
1966 #if !CSD_NO_PERIODIC
1969 /*CmiMachineProgressImpl(); ??? */
1970 if (NULL!=(msg = CsdNextMessage(&state)))
1978 void CsdScheduleNodePoll(void)
1984 /*CmiMachineProgressImpl(); ??? */
1985 if (NULL!=(msg = CsdNextLocalNodeMessage(&state)))
1993 void CmiDeliverSpecificMsg(int handler)
1996 void *localqueue = CpvAccess(CmiLocalQueue);
2000 #if !CSD_NO_PERIODIC
2004 if (side) msg = (int *)CmiGetNonLocal();
2005 else msg = (int *)CdsFifo_Dequeue(localqueue);
2007 if (CmiGetHandler(msg)==handler) {
2009 CpvAccess(cQdState)->mProcessed++;
2011 CmiHandleMessage(msg);
2014 CdsFifo_Enqueue(localqueue, msg);
2020 #endif /* CMK_CMIDELIVERS_USE_COMMON_CODE */
2022 /***************************************************************************
2024 * Standin Schedulers.
2026 * We use the following strategy to make sure somebody's always running
2027 * the scheduler (CsdScheduler). Initially, we assume the main thread
2028 * is responsible for this. If the main thread blocks, we create a
2029 * "standin scheduler" thread to replace it. If the standin scheduler
2030 * blocks, we create another standin scheduler to replace that one,
2031 * ad infinitum. Collectively, the main thread and all the standin
2032 * schedulers are called "scheduling threads".
2034 * Suppose the main thread is blocked waiting for data, and a standin
2035 * scheduler is running instead. Suppose, then, that the data shows
2036 * up and the main thread is CthAwakened. This causes a token to be
2037 * pushed into the queue. When the standin pulls the token from the
2038 * queue and handles it, the standin goes to sleep, and control shifts
2039 * back to the main thread. In this way, unnecessary standins are put
2040 * back to sleep. These sleeping standins are stored on the
2041 * CthSleepingStandins list.
2043 ***************************************************************************/
2045 CpvStaticDeclare(CthThread, CthMainThread);
2046 CpvStaticDeclare(CthThread, CthSchedulingThread);
2047 CpvStaticDeclare(CthThread, CthSleepingStandins);
2048 CpvDeclare(int , CthResumeNormalThreadIdx);
2049 CpvStaticDeclare(int , CthResumeSchedulingThreadIdx);
2052 CpvDeclare (int, CthResumeStealableThreadIdx);
2053 CpvDeclare (int, CthResumeSuspendedStealableThreadIdx);
2056 void CthStandinCode(void *arg)
2061 /* this fix the function pointer for thread migration and pup */
2062 static CthThread CthSuspendNormalThread(void)
2064 return CpvAccess(CthSchedulingThread);
2067 void CthEnqueueSchedulingThread(CthThreadToken *token, int, int, unsigned int*);
2068 CthThread CthSuspendSchedulingThread(void);
2070 CthThread CthSuspendSchedulingThread(void)
2072 CthThread succ = CpvAccess(CthSleepingStandins);
2075 CpvAccess(CthSleepingStandins) = CthGetNext(succ);
2077 succ = CthCreate(CthStandinCode, 0, 256000);
2078 CthSetStrategy(succ,
2079 CthEnqueueSchedulingThread,
2080 CthSuspendSchedulingThread);
2083 CpvAccess(CthSchedulingThread) = succ;
2087 /* Notice: For changes to the following function, make sure the function CthResumeNormalThreadDebug is also kept updated. */
2088 void CthResumeNormalThread(CthThreadToken* token)
2090 CthThread t = token->thread;
2092 /* BIGSIM_OOC DEBUGGING
2093 CmiPrintf("Resume normal thread with token[%p] ==> thread[%p]\n", token, t);
2100 #if CMK_TRACE_ENABLED
2101 #if ! CMK_TRACE_IN_CHARM
2102 if(CpvAccess(traceOn))
2104 /* if(CpvAccess(_traceCoreOn))
2105 resumeTraceCore();*/
2109 /* BIGSIM_OOC DEBUGGING
2110 CmiPrintf("In CthResumeNormalThread: ");
2111 CthPrintThdMagic(t);
2114 CthSetPrev(t, CthSelf());
2118 CthScheduledDecrement();
2119 CthSetPrev(CthSelf(), 0);
2123 void CthResumeSchedulingThread(CthThreadToken *token)
2125 CthThread t = token->thread;
2126 CthThread me = CthSelf();
2127 if (me == CpvAccess(CthMainThread)) {
2128 CthEnqueueSchedulingThread(CthGetToken(me),CQS_QUEUEING_FIFO, 0, 0);
2130 CthSetNext(me, CpvAccess(CthSleepingStandins));
2131 CpvAccess(CthSleepingStandins) = me;
2133 CpvAccess(CthSchedulingThread) = t;
2134 #if CMK_TRACE_ENABLED
2135 #if ! CMK_TRACE_IN_CHARM
2136 if(CpvAccess(traceOn))
2138 /* if(CpvAccess(_traceCoreOn))
2139 resumeTraceCore();*/
2143 CthSetPrev(t, CthSelf());
2147 CthScheduledDecrement();
2148 CthSetPrev(CthSelf(), 0);
2152 void CthEnqueueNormalThread(CthThreadToken* token, int s,
2153 int pb,unsigned int *prio)
2155 CmiSetHandler(token, CpvAccess(CthResumeNormalThreadIdx));
2156 CsdEnqueueGeneral(token, s, pb, prio);
2159 void CthEnqueueSchedulingThread(CthThreadToken* token, int s,
2160 int pb,unsigned int *prio)
2162 CmiSetHandler(token, CpvAccess(CthResumeSchedulingThreadIdx));
2163 CsdEnqueueGeneral(token, s, pb, prio);
2166 void CthSetStrategyDefault(CthThread t)
2169 CthEnqueueNormalThread,
2170 CthSuspendNormalThread);
2173 /* Use work-stealing queue for scheduling threads
2174 We use the previous scheduling handlers while we push the message into the work-stealing queue
2176 void CthResumeStealableThread(CthThreadToken *token)
2178 CthThread t = token->thread;
2179 CthSetNext(t, CthSelf());
2180 #if CMK_TRACE_ENABLED
2181 #if ! CMK_TRACE_IN_CHARM
2182 if(CpvAccess(traceOn))
2186 CthSetPrev(t, CthSelf());
2188 CthScheduledDecrement();
2189 CthSetPrev(CthSelf(), 0);
2192 void CthEnqueueStealableThread(CthThreadToken * token, int s, int pb, unsigned int *prio) {
2193 CmiSetHandler(token, CpvAccess(CthResumeStealableThreadIdx));
2194 CsdTaskEnqueue((void*)token);
2198 void CthEnqueueSuspendedStealableThread(CthThreadToken * token, int s, int pb, unsigned int *prio)
2200 CthThread t = token->thread;
2201 int targetRank = CthGetThreadID(t)->id[2];
2202 CthSetStrategyWorkStealing(t);
2203 if (targetRank == CmiMyRank()) {
2204 CthEnqueueStealableThread(token,s,pb,prio);
2207 CmiSetHandler(token, CpvAccess(CthResumeSuspendedStealableThreadIdx));
2208 CmiSuspendedTaskEnqueue(targetRank ,(void*)token);
2212 void CthResumeSuspendedStealableThread(CthThreadToken *token) {
2213 CthEnqueueStealableThread(token, 0, 0, NULL);
2216 CthThread CthSuspendStealableThread()
2218 CthThread succ = CthGetNext(CthSelf());
2219 #if CMK_ERROR_CHECKING
2221 CmiAbort("successor is invalid\n");
2226 void CthSetStrategyWorkStealing(CthThread t)
2228 CthSetStrategy(t, CthEnqueueStealableThread, CthSuspendStealableThread);
2231 void CthSetStrategySuspendedWorkStealing(CthThread t)
2233 CthSetStrategy(t, CthEnqueueSuspendedStealableThread, CthSuspendStealableThread);
2239 CpvInitialize(CthThread, CthMainThread);
2240 CpvInitialize(CthThread, CthSchedulingThread);
2241 CpvInitialize(CthThread, CthSleepingStandins);
2242 CpvInitialize(int , CthResumeNormalThreadIdx);
2243 CpvInitialize(int , CthResumeSchedulingThreadIdx);
2245 CpvInitialize(int , CthResumeStealableThreadIdx);
2246 CpvInitialize(int , CthResumeSuspendedStealableThreadIdx);
2248 CpvAccess(CthMainThread) = CthSelf();
2249 CpvAccess(CthSchedulingThread) = CthSelf();
2250 CpvAccess(CthSleepingStandins) = 0;
2251 CpvAccess(CthResumeNormalThreadIdx) =
2252 CmiRegisterHandler((CmiHandler)CthResumeNormalThread);
2253 CpvAccess(CthResumeSchedulingThreadIdx) =
2254 CmiRegisterHandler((CmiHandler)CthResumeSchedulingThread);
2255 CthSetStrategy(CthSelf(),
2256 CthEnqueueSchedulingThread,
2257 CthSuspendSchedulingThread);
2260 CpvAccess(CthResumeStealableThreadIdx) = CmiRegisterHandler((CmiHandler)CthResumeStealableThread);
2261 CpvAccess(CthResumeSuspendedStealableThreadIdx) = CmiRegisterHandler((CmiHandler)CthResumeSuspendedStealableThread);
2265 void CsdInit(char **argv)
2267 CpvInitialize(Queue, CsdSchedQueue);
2268 CpvInitialize(int, CsdStopFlag);
2269 CpvInitialize(int, CsdLocalCounter);
2270 int argCsdLocalMax=CSD_LOCAL_MAX_DEFAULT;
2271 int argmaxset = CmiGetArgIntDesc(argv,"+csdLocalMax",&argCsdLocalMax,"Set the max number of local messages to process before forcing a check for remote messages.");
2272 if (CmiMyRank() == 0 ) CsdLocalMax = argCsdLocalMax;
2273 CpvAccess(CsdLocalCounter) = argCsdLocalMax;
2274 CpvAccess(CsdSchedQueue) = CqsCreate();
2275 #if CMK_SMP && CMK_TASKQUEUE
2276 CsvInitialize(unsigned int, idleThreadsCnt);
2277 CsvAccess(idleThreadsCnt) = 0;
2279 #if CMK_USE_STL_MSGQ
2280 if (CmiMyPe() == 0) CmiPrintf("Charm++> Using STL-based msgQ:\n");
2282 #if CMK_RANDOMIZED_MSGQ
2283 if (CmiMyPe() == 0) CmiPrintf("Charm++> Using randomized msgQ. Priorities will not be respected!\n");
2284 #elif CMK_NO_MSG_PRIOS
2285 if (CmiMyPe() == 0) CmiPrintf("Charm++> Message priorities have been turned off and will not be respected.\n");
2288 #if CMK_OBJECT_QUEUE_AVAILABLE
2289 CpvInitialize(Queue, CsdObjQueue);
2290 CpvAccess(CsdObjQueue) = CdsFifo_Create();
2293 #if CMK_NODE_QUEUE_AVAILABLE
2294 CsvInitialize(CmiLock, CsdNodeQueueLock);
2295 CsvInitialize(Queue, CsdNodeQueue);
2296 if (CmiMyRank() ==0) {
2297 CsvAccess(CsdNodeQueueLock) = CmiCreateLock();
2298 CsvAccess(CsdNodeQueue) = CqsCreate();
2300 CmiNodeAllBarrier();
2303 #if CMK_GRID_QUEUE_AVAILABLE
2304 CsvInitialize(Queue, CsdGridQueue);
2305 CpvAccess(CsdGridQueue) = CqsCreate();
2308 #if CMK_SMP && CMK_TASKQUEUE
2309 CpvInitialize(Queue, CsdTaskQueue);
2310 CpvInitialize(void *, CmiSuspendedTaskQueue);
2311 CpvAccess(CsdTaskQueue) = (Queue)TaskQueueCreate();
2313 CpvAccess(CsdStopFlag) = 0;
2314 CpvInitialize(int, isHelperOn);
2315 CpvAccess(isHelperOn) = 1; // Turn on this bit by default for threads to be used for CkLoop and OpenMP integration
2316 CmiMemoryWriteFence();
2317 #if CMK_SMP && CMK_TASKQUEUE
2329 /*****************************************************************************
2333 * The last parameter "system" is by default at zero, in which case the normal
2334 * messages are sent. If it is set to 1, the CmiChunkHeader prepended to every
2335 * CmiAllocced message will also be sent (except for the first one). Useful for
2336 * AllToAll communication, and other system features. If system is 1, also all
2337 * the messages will be padded to 8 bytes. Thus, the caller must be aware of
2340 ****************************************************************************/
2342 #if CMK_VECTOR_SEND_USES_COMMON_CODE
2344 void CmiSyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2348 VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(infiCmiChunkHeader));
2350 VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(CmiChunkHeader));
2352 CmiSyncSendAndFree(destPE, total, mesg);
2355 CmiCommHandle CmiASyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2356 CmiSyncVectorSend(destPE, n, sizes, msgs);
2360 void CmiSyncVectorSendAndFree(int destPE, int n, int *sizes, char **msgs) {
2362 CmiSyncVectorSend(destPE, n, sizes, msgs);
2363 for(i=0;i<n;i++) CmiFree(msgs[i]);
2370 /*****************************************************************************
2372 * Reduction management
2374 * Only one reduction can be active at a single time in the program.
2375 * Moreover, since every call is supposed to pass in the same arguments,
2376 * having some static variables is not a problem for multithreading.
2378 * Except for "data" and "size", all the other parameters (which are all function
2379 * pointers) MUST be the same in every processor. Having different processors
2380 * pass in different function pointers results in an undefined behaviour.
2382 * The data passed in to CmiReduce and CmiNodeReduce is deleted by the system,
2383 * and MUST be allocated with CmiAlloc. The data passed in to the "Struct"
2384 * functions is deleted with the provided function, or it is left intact if no
2385 * function is specified.
2387 * The destination handler for the the first form MUST be embedded into the
2390 * The pup function is used to pup the input data structure into a message to
2391 * be sent to the parent processor. This pup routine is currently used only
2392 * for sizing and packing, NOT unpacking. It MUST be non-null.
2394 * The merge function receives as first parameter the input "data", being it
2395 * a message or a complex data structure (it is up to the user to interpret it
2396 * correctly), and a list of incoming (packed) messages from the children.
2397 * The merge function is responsible to delete "data" if this is no longer needed.
2398 * The system will be in charge of deleting the messages passed in as the second
2399 * argument, and the return value of the function (using the provided deleteFn in
2400 * the second version, or CmiFree in the first). The merge function can return
2401 * data if the merge can be performed in-place. It MUST be non-null.
2403 * At the destination, on processor zero, the final data returned by the last
2404 * merge call will not be deleted by the system, and the CmiHandler function
2405 * will be in charge of its deletion.
2407 * CmiReduce/CmiReduceStruct MUST be called once by every processor,
2408 * CmiNodeReduce/CmiNodeReduceStruct MUST be called once by every node, and in
2409 * particular by the rank zero in each node.
2410 ****************************************************************************/
2412 CpvStaticDeclare(int, CmiReductionMessageHandler);
2413 CpvStaticDeclare(int, CmiReductionDynamicRequestHandler);
2415 CpvStaticDeclare(CmiReduction**, _reduce_info);
2416 CpvStaticDeclare(int, _reduce_info_size); /* This is the log2 of the size of the array */
2417 CpvStaticDeclare(CmiUInt2, _reduce_seqID_global); /* This is used only by global reductions */
2418 CpvStaticDeclare(CmiUInt2, _reduce_seqID_request);
2419 CpvStaticDeclare(CmiUInt2, _reduce_seqID_dynamic);
2422 CmiReductionID_globalOffset = 0, /* Reductions that involve the whole set of processors */
2423 CmiReductionID_requestOffset = 1, /* Reductions IDs that are requested by all the processors (i.e during intialization) */
2424 CmiReductionID_dynamicOffset = 2, /* Reductions IDs that are requested by only one processor (typically at runtime) */
2425 CmiReductionID_multiplier = 3
2428 CmiReduction* CmiGetReductionCreate(int id, short int numChildren) {
2429 int index = id & ~((~0u)<<CpvAccess(_reduce_info_size));
2430 CmiReduction *red = CpvAccess(_reduce_info)[index];
2431 if (red != NULL && red->seqID != id) {
2432 /* The table needs to be expanded */
2433 CmiAbort("Too many simultaneous reductions");
2435 if (red == NULL || red->numChildren < numChildren) {
2436 CmiReduction *newred;
2437 CmiAssert(red == NULL || red->localContributed == 0);
2438 if (numChildren == 0) numChildren = 4;
2439 newred = (CmiReduction*)malloc(sizeof(CmiReduction)+numChildren*sizeof(void*));
2440 newred->numRemoteReceived = 0;
2441 newred->localContributed = 0;
2444 memcpy(newred, red, sizeof(CmiReduction)+red->numChildren*sizeof(void*));
2448 red->numChildren = numChildren;
2449 red->remoteData = (char**)(red+1);
2450 CpvAccess(_reduce_info)[index] = red;
2455 CmiReduction* CmiGetReduction(int id) {
2456 return CmiGetReductionCreate(id, 0);
2459 void CmiClearReduction(int id) {
2460 int index = id & ~((~0u)<<CpvAccess(_reduce_info_size));
2461 free(CpvAccess(_reduce_info)[index]);
2462 CpvAccess(_reduce_info)[index] = NULL;
2465 CmiReduction* CmiGetNextReduction(short int numChildren) {
2466 int id = CpvAccess(_reduce_seqID_global);
2467 CpvAccess(_reduce_seqID_global) += CmiReductionID_multiplier;
2468 if (id > 0xFFF0) CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2469 return CmiGetReductionCreate(id, numChildren);
2472 CmiReductionID CmiGetGlobalReduction(void) {
2473 return CpvAccess(_reduce_seqID_request)+=CmiReductionID_multiplier;
2476 CmiReductionID CmiGetDynamicReduction(void) {
2477 if (CmiMyPe() != 0) CmiAbort("Cannot call CmiGetDynamicReduction on processors other than zero!\n");
2478 return CpvAccess(_reduce_seqID_dynamic)+=CmiReductionID_multiplier;
2481 void CmiReductionHandleDynamicRequest(char *msg) {
2482 int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2484 int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+values[1];
2485 values[0] = CmiGetDynamicReduction();
2486 CmiSetHandler(msg, CmiGetXHandler(msg));
2488 CmiSyncSendAndFree(pe, size, msg);
2490 CmiSyncBroadcastAllAndFree(size, msg);
2494 void CmiGetDynamicReductionRemote(int handlerIdx, int pe, int dataSize, void *data) {
2495 int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+dataSize;
2496 char *msg = (char*)CmiAlloc(size);
2497 int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2499 values[1] = dataSize;
2500 CmiSetXHandler(msg, handlerIdx);
2501 if (dataSize) memcpy(msg+CmiMsgHeaderSizeBytes+2*sizeof(int), data, dataSize);
2502 if (CmiMyPe() == 0) {
2503 CmiReductionHandleDynamicRequest(msg);
2505 /* send the request to processor 0 */
2506 CmiSetHandler(msg, CpvAccess(CmiReductionDynamicRequestHandler));
2507 CmiSyncSendAndFree(0, size, msg);
2511 void CmiSendReduce(CmiReduction *red) {
2512 void *mergedData, *msg;
2514 if (!red->localContributed || red->numChildren != red->numRemoteReceived) return;
2515 mergedData = red->localData;
2516 msg_size = red->localSize;
2517 if (red->numChildren > 0) {
2519 if (red->ops.pupFn != NULL) {
2520 offset = CmiReservedHeaderSize;
2521 for (i=0; i<red->numChildren; ++i) red->remoteData[i] += offset;
2523 mergedData = (red->ops.mergeFn)(&msg_size, red->localData, (void **)red->remoteData, red->numChildren);
2524 for (i=0; i<red->numChildren; ++i) CmiFree(red->remoteData[i] - offset);
2526 /*CpvAccess(_reduce_num_children) = 0;*/
2527 /*CpvAccess(_reduce_received) = 0;*/
2529 if (red->parent != -1) {
2530 if (red->ops.pupFn != NULL) {
2531 pup_er p = pup_new_sizer();
2532 (red->ops.pupFn)(p, mergedData);
2533 msg_size = pup_size(p) + CmiReservedHeaderSize;
2535 msg = CmiAlloc(msg_size);
2536 p = pup_new_toMem((void*)(((char*)msg)+CmiReservedHeaderSize));
2537 (red->ops.pupFn)(p, mergedData);
2539 if (red->ops.deleteFn != NULL) (red->ops.deleteFn)(red->localData);
2541 CmiSetHandler(msg, CpvAccess(CmiReductionMessageHandler));
2542 CmiSetRedID(msg, red->seqID);
2543 /*CmiPrintf("CmiSendReduce(%d): sending %d bytes to %d\n",CmiMyPe(),msg_size,red->parent);*/
2544 CmiSyncSendAndFree(red->parent, msg_size, msg);
2546 (red->ops.destination)(msg);
2548 CmiClearReduction(red->seqID);
2551 void *CmiReduceMergeFn_random(int *size, void *data, void** remote, int n) {
2555 void CmiResetGlobalReduceSeqID(void) {
2556 CpvAccess(_reduce_seqID_global) = 0;
2559 static void CmiGlobalReduce(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReduction *red) {
2560 CmiAssert(red->localContributed == 0);
2561 red->localContributed = 1;
2562 red->localData = msg;
2563 red->localSize = size;
2564 red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2565 red->parent = CmiSpanTreeParent(CmiMyPe());
2566 red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2567 red->ops.mergeFn = mergeFn;
2568 red->ops.pupFn = NULL;
2569 /*CmiPrintf("[%d] CmiReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2573 static void CmiGlobalReduceStruct(void *data, CmiReducePupFn pupFn,
2574 CmiReduceMergeFn mergeFn, CmiHandler dest,
2575 CmiReduceDeleteFn deleteFn, CmiReduction *red) {
2576 CmiAssert(red->localContributed == 0);
2577 red->localContributed = 1;
2578 red->localData = data;
2580 red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2581 red->parent = CmiSpanTreeParent(CmiMyPe());
2582 red->ops.destination = dest;
2583 red->ops.mergeFn = mergeFn;
2584 red->ops.pupFn = pupFn;
2585 red->ops.deleteFn = deleteFn;
2586 /*CmiPrintf("[%d] CmiReduceStruct::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2590 void CmiReduce(void *msg, int size, CmiReduceMergeFn mergeFn) {
2591 CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2592 CmiGlobalReduce(msg, size, mergeFn, red);
2595 void CmiReduceStruct(void *data, CmiReducePupFn pupFn,
2596 CmiReduceMergeFn mergeFn, CmiHandler dest,
2597 CmiReduceDeleteFn deleteFn) {
2598 CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2599 CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2602 void CmiReduceID(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2603 CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2604 CmiGlobalReduce(msg, size, mergeFn, red);
2607 void CmiReduceStructID(void *data, CmiReducePupFn pupFn,
2608 CmiReduceMergeFn mergeFn, CmiHandler dest,
2609 CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2610 CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2611 CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2614 void CmiListReduce(int npes, int *pes, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2615 CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2617 CmiAssert(red->localContributed == 0);
2618 red->localContributed = 1;
2619 red->localData = msg;
2620 red->localSize = size;
2621 for (myPos=0; myPos<npes; ++myPos) {
2622 if (pes[myPos] == CmiMyPe()) break;
2624 CmiAssert(myPos < npes);
2625 red->numChildren = npes - (myPos << 2) - 1;
2626 if (red->numChildren > 4) red->numChildren = 4;
2627 if (red->numChildren < 0) red->numChildren = 0;
2628 if (myPos == 0) red->parent = -1;
2629 else red->parent = pes[(myPos - 1) >> 2];
2630 red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2631 red->ops.mergeFn = mergeFn;
2632 red->ops.pupFn = NULL;
2633 /*CmiPrintf("[%d] CmiListReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2637 void CmiListReduceStruct(int npes, int *pes,
2638 void *data, CmiReducePupFn pupFn,
2639 CmiReduceMergeFn mergeFn, CmiHandler dest,
2640 CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2641 CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2643 CmiAssert(red->localContributed == 0);
2644 red->localContributed = 1;
2645 red->localData = data;
2647 for (myPos=0; myPos<npes; ++myPos) {
2648 if (pes[myPos] == CmiMyPe()) break;
2650 CmiAssert(myPos < npes);
2651 red->numChildren = npes - (myPos << 2) - 1;
2652 if (red->numChildren > 4) red->numChildren = 4;
2653 if (red->numChildren < 0) red->numChildren = 0;
2654 red->parent = (myPos - 1) >> 2;
2655 if (myPos == 0) red->parent = -1;
2656 red->ops.destination = dest;
2657 red->ops.mergeFn = mergeFn;
2658 red->ops.pupFn = pupFn;
2659 red->ops.deleteFn = deleteFn;
2663 void CmiGroupReduce(CmiGroup grp, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2665 CmiLookupGroup(grp, &npes, &pes);
2666 CmiListReduce(npes, pes, msg, size, mergeFn, id);
2669 void CmiGroupReduceStruct(CmiGroup grp, void *data, CmiReducePupFn pupFn,
2670 CmiReduceMergeFn mergeFn, CmiHandler dest,
2671 CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2673 CmiLookupGroup(grp, &npes, &pes);
2674 CmiListReduceStruct(npes, pes, data, pupFn, mergeFn, dest, deleteFn, id);
2677 void CmiNodeReduce(void *data, int size, CmiReduceMergeFn mergeFn, int redID, int numChildren, int parent) {
2678 CmiAbort("Feel free to implement CmiNodeReduce...");
2680 CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2681 CpvAccess(_reduce_data) = data;
2682 CpvAccess(_reduce_data_size) = size;
2683 CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2684 _reduce_destination = (CmiHandler)CmiGetHandlerFunction(data);
2685 _reduce_pupFn = NULL;
2686 _reduce_mergeFn = mergeFn;
2687 CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2688 if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(size);
2692 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int redID) {
2693 CmiNodeReduce(data, size, mergeFn, redID, CmiNumNodeSpanTreeChildren(CmiMyNode()),
2694 CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2696 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int numChildren, int parent) {
2697 CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), numChildren, parent);
2699 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int)) {
2700 CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), CmiNumNodeSpanTreeChildren(CmiMyNode()),
2701 CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2705 void CmiNodeReduceStruct(void *data, CmiReducePupFn pupFn,
2706 CmiReduceMergeFn mergeFn, CmiHandler dest,
2707 CmiReduceDeleteFn deleteFn) {
2708 CmiAbort("Feel free to implement CmiNodeReduceStruct...");
2710 CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2711 CpvAccess(_reduce_data) = data;
2712 CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2713 _reduce_destination = dest;
2714 _reduce_pupFn = pupFn;
2715 _reduce_mergeFn = mergeFn;
2716 _reduce_deleteFn = deleteFn;
2717 CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2718 if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(0);
2722 void CmiHandleReductionMessage(void *msg) {
2723 CmiReduction *red = CmiGetReduction(CmiGetRedID(msg));
2724 if (red->numRemoteReceived == red->numChildren) red = CmiGetReductionCreate(CmiGetRedID(msg), red->numChildren+4);
2725 red->remoteData[red->numRemoteReceived++] = (char *)msg;
2726 /*CmiPrintf("[%d] CmiReduce::remote %hd\n",CmiMyPe(),red->seqID);*/
2729 CpvAccess(_reduce_msg_list)[CpvAccess(_reduce_received)++] = msg;
2730 if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce();
2731 / *else CmiPrintf("CmiHandleReductionMessage(%d): %d - %d\n",CmiMyPe(),CpvAccess(_reduce_received),CpvAccess(_reduce_num_children));*/
2734 void CmiReductionsInit(void) {
2736 CpvInitialize(int, CmiReductionMessageHandler);
2737 CpvAccess(CmiReductionMessageHandler) = CmiRegisterHandler((CmiHandler)CmiHandleReductionMessage);
2738 CpvInitialize(int, CmiReductionDynamicRequestHandler);
2739 CpvAccess(CmiReductionDynamicRequestHandler) = CmiRegisterHandler((CmiHandler)CmiReductionHandleDynamicRequest);
2740 CpvInitialize(CmiUInt2, _reduce_seqID_global);
2741 CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2742 CpvInitialize(CmiUInt2, _reduce_seqID_request);
2743 CpvAccess(_reduce_seqID_request) = CmiReductionID_requestOffset;
2744 CpvInitialize(CmiUInt2, _reduce_seqID_dynamic);
2745 CpvAccess(_reduce_seqID_dynamic) = CmiReductionID_dynamicOffset;
2746 CpvInitialize(int, _reduce_info_size);
2747 CpvAccess(_reduce_info_size) = 4;
2748 CpvInitialize(CmiReduction**, _reduce_info);
2749 CpvAccess(_reduce_info) = (CmiReduction **)malloc(16*sizeof(CmiReduction*));
2750 for (i=0; i<16; ++i) CpvAccess(_reduce_info)[i] = NULL;
2753 /*****************************************************************************
2757 ****************************************************************************/
2759 #if CMK_MULTICAST_DEF_USE_COMMON_CODE
2761 typedef struct GroupDef_s
2764 char core[CmiMsgHeaderSizeBytes];
2765 struct GroupDef_s *next;
2773 #define GROUPTAB_SIZE 101
2775 CpvStaticDeclare(int, CmiGroupHandlerIndex);
2776 CpvStaticDeclare(int, CmiGroupCounter);
2777 CpvStaticDeclare(GroupDef *, CmiGroupTable);
2779 void CmiGroupHandler(GroupDef def)
2781 /* receive group definition, insert into group table */
2782 GroupDef *table = CpvAccess(CmiGroupTable);
2783 unsigned int hashval, bucket;
2784 hashval = (def->group.id ^ def->group.pe);
2785 bucket = hashval % GROUPTAB_SIZE;
2786 def->core.next = table[bucket];
2787 table[bucket] = def;
2790 CmiGroup CmiEstablishGroup(int npes, int *pes)
2792 /* build new group definition, broadcast it */
2793 CmiGroup grp; GroupDef def; int len, i;
2794 grp.id = CpvAccess(CmiGroupCounter)++;
2796 len = sizeof(struct GroupDef_s)+(npes*sizeof(int));
2797 def = (GroupDef)CmiAlloc(len);
2800 for (i=0; i<npes; i++)
2801 def->pes[i] = pes[i];
2802 CmiSetHandler(def, CpvAccess(CmiGroupHandlerIndex));
2803 CmiSyncBroadcastAllAndFree(len, def);
2807 void CmiLookupGroup(CmiGroup grp, int *npes, int **pes)
2809 unsigned int hashval, bucket; GroupDef def;
2810 GroupDef *table = CpvAccess(CmiGroupTable);
2811 hashval = (grp.id ^ grp.pe);
2812 bucket = hashval % GROUPTAB_SIZE;
2813 for (def=table[bucket]; def; def=def->core.next) {
2814 if ((def->group.id == grp.id)&&(def->group.pe == grp.pe)) {
2820 *npes = 0; *pes = 0;
2823 void CmiGroupInit(void)
2825 CpvInitialize(int, CmiGroupHandlerIndex);
2826 CpvInitialize(int, CmiGroupCounter);
2827 CpvInitialize(GroupDef *, CmiGroupTable);
2828 CpvAccess(CmiGroupHandlerIndex) = CmiRegisterHandler((CmiHandler)CmiGroupHandler);
2829 CpvAccess(CmiGroupCounter) = 0;
2830 CpvAccess(CmiGroupTable) =
2831 (GroupDef*)calloc(GROUPTAB_SIZE, sizeof(GroupDef));
2832 if (CpvAccess(CmiGroupTable) == 0)
2833 CmiAbort("Memory Allocation Error");
2838 /*****************************************************************************
2840 * Common List-Cast and Multicast Code
2842 ****************************************************************************/
2844 #if CMK_MULTICAST_LIST_USE_COMMON_CODE
2846 void CmiSyncListSendFn(int npes, const int *pes, int len, char *msg)
2849 #if CMK_BROADCAST_USE_CMIREFERENCE
2850 for(i=0;i<npes;i++) {
2851 if (pes[i] == CmiMyPe())
2852 CmiSyncSend(pes[i], len, msg);
2855 CmiSyncSendAndFree(pes[i], len, msg);
2859 for(i=0;i<npes;i++) {
2860 CmiSyncSend(pes[i], len, msg);
2865 CmiCommHandle CmiAsyncListSendFn(int npes, const int *pes, int len, char *msg)
2867 /* A better asynchronous implementation may be wanted, but at least it works */
2868 CmiSyncListSendFn(npes, pes, len, msg);
2869 return (CmiCommHandle) 0;
2872 void CmiFreeListSendFn(int npes, const int *pes, int len, char *msg)
2874 #if CMK_BROADCAST_USE_CMIREFERENCE
2876 CmiSyncSendAndFree(pes[0], len, msg);
2879 CmiSyncListSendFn(npes, pes, len, msg);
2883 for(i=0;i<npes-1;i++) {
2884 CmiSyncSend(pes[i], len, msg);
2887 CmiSyncSendAndFree(pes[npes-1], len, msg);
2895 #if CMK_MULTICAST_GROUP_USE_COMMON_CODE
2897 typedef struct MultiMsg_s
2899 char core[CmiMsgHeaderSizeBytes];
2907 CpvDeclare(int, CmiMulticastHandlerIndex);
2909 void CmiMulticastDeliver(MultiMsg msg)
2911 int npes, *pes; int olen, nlen, pos, child1, child2;
2912 olen = msg->origlen;
2913 nlen = olen + sizeof(struct MultiMsg_s);
2914 CmiLookupGroup(msg->group, &npes, &pes);
2916 CmiSyncSendAndFree(CmiMyPe(), nlen, msg);
2923 if (msg->pos == -1) {
2925 CmiSyncSendAndFree(pes[0], nlen, msg);
2929 child1 = ((pos+1)<<1);
2931 if (child1 < npes) {
2933 CmiSyncSend(pes[child1], nlen, msg);
2935 if (child2 < npes) {
2937 CmiSyncSend(pes[child2], nlen, msg);
2939 if(olen < sizeof(struct MultiMsg_s)) {
2940 memcpy(msg, msg+1, olen);
2942 memcpy(msg, (((char*)msg)+olen), sizeof(struct MultiMsg_s));
2944 CmiSyncSendAndFree(CmiMyPe(), olen, msg);
2947 void CmiMulticastHandler(MultiMsg msg)
2949 CmiMulticastDeliver(msg);
2952 void CmiSyncMulticastFn(CmiGroup grp, int len, char *msg)
2954 int newlen; MultiMsg newmsg;
2955 newlen = len + sizeof(struct MultiMsg_s);
2956 newmsg = (MultiMsg)CmiAlloc(newlen);
2957 if(len < sizeof(struct MultiMsg_s)) {
2958 memcpy(newmsg+1, msg, len);
2960 memcpy(newmsg+1, msg+sizeof(struct MultiMsg_s), len-sizeof(struct MultiMsg_s));
2961 memcpy(((char *)newmsg+len), msg, sizeof(struct MultiMsg_s));
2963 newmsg->group = grp;
2964 newmsg->origlen = len;
2966 CmiSetHandler(newmsg, CpvAccess(CmiMulticastHandlerIndex));
2967 CmiMulticastDeliver(newmsg);
2970 void CmiFreeMulticastFn(CmiGroup grp, int len, char *msg)
2972 CmiSyncMulticastFn(grp, len, msg);
2976 CmiCommHandle CmiAsyncMulticastFn(CmiGroup grp, int len, char *msg)
2978 CmiError("Async Multicast not implemented.");
2979 return (CmiCommHandle) 0;
2982 void CmiMulticastInit(void)
2984 CpvInitialize(int, CmiMulticastHandlerIndex);
2985 CpvAccess(CmiMulticastHandlerIndex) =
2986 CmiRegisterHandler((CmiHandler)CmiMulticastHandler);
2990 extern void CmiMulticastInit(void);
2993 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
2994 extern void *arena_malloc(int size);
2995 extern void arena_free(void *blockPtr);
2998 /***************************************************************************
3000 * Memory Allocation routines
3002 * A block of memory can consist of multiple chunks. Each chunk has
3003 * a sizefield and a refcount. The first chunk's refcount is a reference
3004 * count. That's how many CmiFrees it takes to free the message.
3005 * Subsequent chunks have a refcount which is less than zero. This is
3006 * the offset back to the start of the first chunk.
3008 * Each chunk has a CmiChunkHeader before the user data, with the fields:
3010 * size: The user-allocated size of the chunk, in bytes.
3012 * ref: A magic reference count object. Ordinary blocks start with
3013 * reference count 1. When the reference count reaches zero,
3014 * the block is deleted. To support nested buffers, the
3015 * reference count can also be negative, which means it is
3016 * a byte offset to the enclosing buffer's reference count.
3018 ***************************************************************************/
3021 void *CmiAlloc(int size)
3026 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
3027 res = (char*) arena_malloc(size+sizeof(CmiChunkHeader));
3028 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
3029 res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
3030 #elif CMK_CONVERSE_UGNI || CMK_OFI
3031 res =(char *) LrtsAlloc(size, sizeof(CmiChunkHeader));
3033 res =(char *) CmiPoolAlloc(size+sizeof(CmiChunkHeader));
3034 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
3035 MPI_Alloc_mem(size+sizeof(CmiChunkHeader), MPI_INFO_NULL, &res);
3036 #elif CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
3037 res = (char *) CmiAlloc_bgq(size+sizeof(CmiChunkHeader));
3038 #elif CMK_SMP && CMK_PPC_ATOMIC_QUEUE
3039 res = (char *) CmiAlloc_ppcq(size+sizeof(CmiChunkHeader));
3041 res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
3047 CpvAccess(MemoryUsage) += size+sizeof(CmiChunkHeader);
3048 CpvAccess(AllocCount)++;
3049 CpvAccess(BlocksAllocated)++;
3050 if (CpvAccess(MemoryUsage) > CpvAccess(HiWaterMark)) {
3051 CpvAccess(HiWaterMark) = CpvAccess(MemoryUsage);
3053 if (CpvAccess(MemoryUsage) > 1.1 * CpvAccess(ReportedHiWaterMark)) {
3054 CmiPrintf("HIMEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
3055 CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
3056 CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
3057 CpvAccess(ReportedHiWaterMark) = CpvAccess(MemoryUsage);
3059 if ((CpvAccess(AllocCount) % 1000) == 0) {
3060 CmiPrintf("MEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
3061 CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
3062 CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
3066 res+=sizeof(CmiChunkHeader);
3067 CmiAssert((intptr_t)res % ALIGN_BYTES == 0);
3069 CmiInitMsgHeader(res, size);
3071 SIZEFIELD(res)=size;
3072 REFFIELDSET(res, 1);
3076 void *CmiRdmaAlloc(int size) {
3079 #if CMK_CONVERSE_UGNI
3080 res = (char *)LrtsRdmaAlloc(size, sizeof(CmiChunkHeader));
3081 #elif CMK_USE_IBVERBS || CMK_USE_IBUD
3082 res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
3084 res = (char *)LrtsAlloc(size, sizeof(CmiChunkHeader));
3086 res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
3090 res+=sizeof(CmiChunkHeader);
3091 CmiAssert((intptr_t)res % ALIGN_BYTES == 0);
3093 CmiInitMsgHeader(res, size);
3094 SIZEFIELD(res)=size;
3095 REFFIELDSET(res, 1);
3100 /** Follow the header links out to the most enclosing block */
3101 static void *CmiAllocFindEnclosing(void *blk) {
3102 int refCount = REFFIELD(blk);
3103 while (refCount < 0) {
3104 blk = (void *)((char*)blk+refCount); /* Jump to enclosing block */
3105 refCount = REFFIELD(blk);
3110 void CmiInitMsgHeader(void *msg, int size) {
3111 #if CMK_ONESIDED_IMPL
3112 // Set zcMsgType in the converse message header to CMK_REG_NO_ZC_MSG
3113 if(size >= CmiMsgHeaderSizeBytes)
3114 CMI_ZC_MSGTYPE(msg) = CMK_REG_NO_ZC_MSG;
3118 int CmiGetReference(void *blk)
3120 return REFFIELD(CmiAllocFindEnclosing(blk));
3123 /** Increment the reference count for this block's owner.
3124 This call must be matched by an equivalent CmiFree. */
3125 void CmiReference(void *blk)
3127 REFFIELDINC(CmiAllocFindEnclosing(blk));
3130 /** Return the size of the user portion of this block. */
3131 int CmiSize(void *blk)
3133 return SIZEFIELD(blk);
3136 /** Decrement the reference count for this block. */
3137 void CmiFree(void *blk)
3139 void *parentBlk=CmiAllocFindEnclosing(blk);
3140 int refCount=REFFIELDDEC(parentBlk);
3141 #if CMK_ERROR_CHECKING
3142 if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
3143 CmiAbort("CmiFree reference count was zero-- is this a duplicate free?");
3145 if(refCount==1) { /* This was the last reference to the block-- free it */
3147 int size=SIZEFIELD(parentBlk);
3148 if (size > 1000000000) /* Absurdly large size field-- warning */
3149 CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
3150 CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader));
3151 CpvAccess(BlocksAllocated)--;
3154 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
3155 arena_free(BLKSTART(parentBlk));
3156 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
3157 /* is this message the head of a MultipleSend that we received?
3158 Then the parts with INFIMULTIPOOL have metadata which must be
3159 unregistered and freed. */
3160 #ifdef CMK_IBVERS_CLEAN_MULTIPLESEND
3161 if(CmiGetHandler(parentBlk)==CpvAccess(CmiMainHandlerIDP))
3163 infi_freeMultipleSend(parentBlk);
3166 infi_CmiFree(BLKSTART(parentBlk));
3167 #elif CMK_CONVERSE_UGNI || CMK_OFI
3168 LrtsFree(BLKSTART(parentBlk));
3170 CmiPoolFree(BLKSTART(parentBlk));
3171 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
3172 MPI_Free_mem(parentBlk);
3173 #elif CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
3174 CmiFree_bgq(BLKSTART(parentBlk));
3175 #elif CMK_SMP && CMK_PPC_ATOMIC_QUEUE
3176 CmiFree_ppcq(BLKSTART(parentBlk));
3178 free_nomigrate(BLKSTART(parentBlk));
3183 void CmiRdmaFree(void *blk)
3185 void *parentBlk=CmiAllocFindEnclosing(blk);
3186 int refCount=REFFIELDDEC(parentBlk);
3187 #if CMK_ERROR_CHECKING
3188 if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
3189 CmiAbort("CmiRdmaFree reference count was zero-- is this a duplicate free?");
3191 if(refCount==1) { /* This was the last reference to the block-- free it */
3193 int size=SIZEFIELD(parentBlk);
3194 if (size > 1000000000) /* Absurdly large size field-- warning */
3195 CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
3196 CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader));
3197 CpvAccess(BlocksAllocated)--;
3200 #if CMK_CONVERSE_UGNI
3201 LrtsRdmaFree(BLKSTART(parentBlk));
3202 #elif CMK_USE_IBVERBS || CMK_USE_IBUD
3203 infi_CmiFree(BLKSTART(parentBlk));
3205 LrtsFree(BLKSTART(parentBlk));
3207 free_nomigrate(BLKSTART(parentBlk));
3213 /***************************************************************************
3215 * Temporary-memory Allocation routines
3217 * This buffer augments the storage available on the regular machine stack
3218 * for fairly large temporary buffers, which allows us to use smaller machine
3221 ***************************************************************************/
3223 #define CMI_TMP_BUF_MAX 16*1024 /* Allow this much temporary storage. */
3226 char *buf; /* Start of temporary buffer */
3227 int cur; /* First unused location in temporary buffer */
3228 int max; /* Length of temporary buffer */
3230 CpvDeclare(CmiTmpBuf_t,CmiTmpBuf); /* One temporary buffer per PE */
3232 static void CmiTmpSetup(CmiTmpBuf_t *b) {
3233 b->buf=(char *)malloc(CMI_TMP_BUF_MAX);
3235 b->max=CMI_TMP_BUF_MAX;
3238 void *CmiTmpAlloc(int size) {
3239 if (!CpvInitialized(CmiTmpBuf)) {
3240 return malloc(size);
3242 else { /* regular case */
3243 CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3245 if (b->cur+size>b->max) {
3246 if (b->max==0) /* We're just uninitialized */
3248 else /* We're really out of space! */
3249 return malloc(size);
3256 void CmiTmpFree(void *t) {
3257 if (!CpvInitialized(CmiTmpBuf)) {
3260 else { /* regular case */
3261 CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3262 /* t should point into our temporary buffer: figure out where */
3263 int cur=((const char *)t)-b->buf;
3264 if (cur<0 || cur>b->max) {
3272 void CmiTmpInit(char **argv) {
3273 CpvInitialize(CmiTmpBuf_t,CmiTmpBuf);
3274 /* Set up this processor's temporary buffer */
3275 CmiTmpSetup(&CpvAccess(CmiTmpBuf));
3278 /******************************************************************************
3280 Cross-platform directory creation
3282 ****************************************************************************/
3284 /* Windows directory creation: */
3285 #include <windows.h>
3287 void CmiMkdir(const char *dirName) {
3288 CreateDirectory(dirName,NULL);
3291 int CmiGetPageSize(void)
3293 SYSTEM_INFO system_info;
3294 GetSystemInfo(&system_info);
3295 return system_info.dwPageSize;
3298 /* UNIX directory creation */
3300 #include <sys/stat.h> /* from "mkdir" man page */
3301 #include <sys/types.h>
3303 void CmiMkdir(const char *dirName) {
3304 mkdir(dirName,0777);
3307 int CmiGetPageSize(void)
3309 #if CMK_HAS_GETPAGESIZE
3310 return getpagesize();
3312 return CMK_MEMORY_PAGESIZE;
3319 /******************************************************************************
3321 Multiple Send function
3323 ****************************************************************************/
3329 /****************************************************************************
3330 * DESCRIPTION : This function call allows the user to send multiple messages
3331 * from one processor to another, all intended for differnet
3336 * destPE, len, int sizes[0..len-1], char *messages[0..len-1]
3338 ****************************************************************************/
3339 /* Round up message size to the message granularity.
3340 Does this by adding, then truncating.
3342 static int roundUpSize(unsigned int s) {
3343 return (int)((s+sizeof(double)-1)&~(sizeof(double)-1));
3345 /* Return the amount of message padding required for a message
3346 with this many user bytes.
3348 static int paddingSize(unsigned int s) {
3349 return roundUpSize(s)-s;
3352 /* Message header for a bundle of multiple-sent messages */
3354 char convHeader[CmiMsgHeaderSizeBytes];
3355 int nMessages; /* Number of distinct messages bundled below. */
3356 double pad; /* To align the first message, which follows this header */
3357 } CmiMultipleSendHeader;
3359 #if CMK_USE_IBVERBS | CMK_USE_IBUD
3360 /* given a pointer to a multisend message clean up the metadata */
3362 void infi_freeMultipleSend(void *msgWhole)
3364 int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3365 double pad=((CmiMultipleSendHeader *)msgWhole)->pad;
3366 int offset=sizeof(CmiMultipleSendHeader);
3369 if (pad != 1234567.89) return;
3372 /*unreg meta, free meta, move the ptr */
3373 /* note these weird little things are not pooled */
3374 /* do NOT free the message here, we are only a part of this buffer*/
3375 infiCmiChunkHeader *ch = (infiCmiChunkHeader *)((char *)msgWhole + offset);
3376 char *msg = (char *)msgWhole + offset + sizeof(infiCmiChunkHeader);
3377 int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3378 infi_unregAndFreeMeta(ch->metaData);
3379 offset+= sizeof(infiCmiChunkHeader) + msgSize;
3385 static void _CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[], int immed)
3387 CmiMultipleSendHeader header;
3388 int m; /* Outgoing message */
3390 CmiInitMsgHeader(header.convHeader, sizeof(CmiMultipleSendHeader));
3392 infiCmiChunkHeader *msgHdr;
3394 CmiChunkHeader *msgHdr; /* Chunk headers for each message */
3397 double pad = 0; /* padding required */
3398 int vecLen; /* Number of pieces in outgoing message vector */
3399 int *vecSizes; /* Sizes of each piece we're sending out. */
3400 char **vecPtrs; /* Pointers to each piece we're sending out. */
3401 int vec; /* Entry we're currently filling out in above array */
3404 msgHdr = (infiCmiChunkHeader *)CmiTmpAlloc(len * sizeof(infiCmiChunkHeader));
3406 msgHdr = (CmiChunkHeader *)CmiTmpAlloc(len * sizeof(CmiChunkHeader));
3409 /* Allocate memory for the outgoing vector*/
3410 vecLen=1+3*len; /* Header and 3 parts per message */
3411 vecSizes = (int *)CmiTmpAlloc(vecLen * sizeof(int));
3412 vecPtrs = (char **)CmiTmpAlloc(vecLen * sizeof(char *));
3415 /* Build the header */
3416 header.nMessages=len;
3417 CmiSetHandler(&header, CpvAccess(CmiMainHandlerIDP));
3418 header.pad = 1234567.89;
3419 #if CMK_IMMEDIATE_MSG
3420 if (immed) CmiBecomeImmediate(&header);
3422 vecSizes[vec]=sizeof(header); vecPtrs[vec]=(char *)&header;
3425 /* Build an entry for each message:
3426 | CmiChunkHeader | Message data | Message padding | ...next message entry ...
3428 for (m=0;m<len;m++) {
3430 msgHdr[m].chunkHeader.size=roundUpSize(sizes[m]); /* Size of message and padding */
3431 msgHdr[m].chunkHeader.setRef(0); /* Reference count will be filled out on receive side */
3432 msgHdr[m].metaData=NULL;
3434 msgHdr[m].size=roundUpSize(sizes[m]); /* Size of message and padding */
3435 msgHdr[m].setRef(0); /* Reference count will be filled out on receive side */
3438 /* First send the message's CmiChunkHeader (for use on receive side) */
3440 vecSizes[vec]=sizeof(infiCmiChunkHeader);
3442 vecSizes[vec]=sizeof(CmiChunkHeader);
3444 vecPtrs[vec]=(char *)&msgHdr[m];
3447 /* Now send the actual message data */
3448 vecSizes[vec]=sizes[m]; vecPtrs[vec]=msgComps[m];
3451 /* Now send padding to align the next message on a double-boundary */
3452 vecSizes[vec]=paddingSize(sizes[m]); vecPtrs[vec]=(char *)&pad;
3455 CmiAssert(vec==vecLen);
3457 CmiSyncVectorSend(destPE, vecLen, vecSizes, vecPtrs);
3459 CmiTmpFree(vecPtrs); /* CmiTmp: Be sure to throw away in opposite order of allocation */
3460 CmiTmpFree(vecSizes);
3464 void CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3466 _CmiMultipleSend(destPE, len, sizes, msgComps, 0);
3469 void CmiMultipleIsend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3471 _CmiMultipleSend(destPE, len, sizes, msgComps, 1);
3474 /****************************************************************************
3475 * DESCRIPTION : This function initializes the main handler required for the
3476 * CmiMultipleSend() function to work.
3478 * This function should be called once in any Converse program
3479 * that uses CmiMultipleSend()
3481 ****************************************************************************/
3483 static void CmiMultiMsgHandler(char *msgWhole);
3485 void CmiInitMultipleSend(void)
3487 CpvInitialize(int,CmiMainHandlerIDP);
3488 CpvAccess(CmiMainHandlerIDP) =
3489 CmiRegisterHandler((CmiHandler)CmiMultiMsgHandler);
3492 /****************************************************************************
3493 * DESCRIPTION : This function is the main handler that splits up the messages
3494 * CmiMultipleSend() pastes together.
3496 ****************************************************************************/
3498 static void CmiMultiMsgHandler(char *msgWhole)
3500 int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3501 int offset=sizeof(CmiMultipleSendHeader);
3503 for (m=0;m<len;m++) {
3505 infiCmiChunkHeader *ch=(infiCmiChunkHeader *)(msgWhole+offset);
3506 char *msg=(msgWhole+offset+sizeof(infiCmiChunkHeader));
3507 int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3508 ch->chunkHeader.setRef(msgWhole-msg);
3509 ch->metaData = registerMultiSendMesg(msg,msgSize);
3511 CmiChunkHeader *ch=(CmiChunkHeader *)(msgWhole+offset);
3512 char *msg=(msgWhole+offset+sizeof(CmiChunkHeader));
3513 int msgSize=ch->size; /* Size of user portion of message (plus padding at end) */
3514 ch->setRef(msgWhole-msg);
3516 /* Link new message to owner via a negative ref pointer */
3517 CmiReference(msg); /* Follows link & increases reference count of *msgWhole* */
3518 CmiSyncSendAndFree(CmiMyPe(), msgSize, msg);
3520 offset+= sizeof(infiCmiChunkHeader) + msgSize;
3522 offset+= sizeof(CmiChunkHeader) + msgSize;
3525 /* Release our reference to the whole message. The message will
3526 only actually be deleted once all its sub-messages are free'd as well. */
3530 /****************************************************************************
3531 * Hypercube broadcast message passing.
3532 ****************************************************************************/
3534 int HypercubeGetBcastDestinations(int mype, int total_pes, int k, int *dest_pes) {
3536 for ( ; k>=0; --k) {
3537 /* add the processor destination at level k if it exist */
3538 dest_pes[num_pes] = mype ^ (1<<k);
3539 if (dest_pes[num_pes] >= total_pes) {
3540 /* find the first proc in the other part of the current dimention */
3541 dest_pes[num_pes] &= (~0u)<<k;
3542 /* if the first proc there is over CmiNumPes() then there is no other
3543 dimension, otherwise if it is valid compute my correspondent in such
3544 a way to minimize the load for every processor */
3545 if (total_pes>dest_pes[num_pes]) dest_pes[num_pes] += (mype - (mype & ((~0u)<<k))) % (total_pes - dest_pes[num_pes]);
3547 if (dest_pes[num_pes] < total_pes) {
3548 /* if the destination is in the acceptable range increment num_pes */
3556 /****************************************************************************
3557 * DESCRIPTION : This function initializes the main handler required for the
3560 * This function should be called once in any Converse program
3562 ****************************************************************************/
3564 int _immediateLock = 0; /* if locked, all immediate message handling will be delayed. */
3565 int _immediateFlag = 0; /* if set, there is delayed immediate message. */
3567 CpvDeclare(int, CmiImmediateMsgHandlerIdx); /* Main handler that is run on every node */
3569 /* xdl is the real handler */
3570 static void CmiImmediateMsgHandler(char *msg)
3572 CmiSetHandler(msg, CmiGetXHandler(msg));
3573 CmiHandleMessage(msg);
3576 void CmiInitImmediateMsg(void)
3578 CpvInitialize(int,CmiImmediateMsgHandlerIdx);
3579 CpvAccess(CmiImmediateMsgHandlerIdx) =
3580 CmiRegisterHandler((CmiHandler)CmiImmediateMsgHandler);
3583 /*#if !CMK_IMMEDIATE_MSG
3584 #if !CMK_MACHINE_PROGRESS_DEFINED
3585 void CmiProbeImmediateMsg()
3591 /******** Idle timeout module (+idletimeout=30) *********/
3594 int idle_timeout;/*Milliseconds to wait idle before aborting*/
3595 int is_idle;/*Boolean currently-idle flag*/
3596 int call_count;/*Number of timeout calls currently in flight*/
3599 static void on_timeout(cmi_cpu_idlerec *rec,double curWallTime)
3602 if(rec->call_count==0 && rec->is_idle==1) {
3603 CmiError("Idle time on PE %d exceeded specified timeout.\n", CmiMyPe());
3604 CmiAbort("Exiting.\n");
3607 static void on_idle(cmi_cpu_idlerec *rec,double curWallTime)
3609 CcdCallFnAfter((CcdVoidFn)on_timeout, rec, rec->idle_timeout);
3610 rec->call_count++; /*Keeps track of overlapping timeout calls.*/
3613 static void on_busy(cmi_cpu_idlerec *rec,double curWallTime)
3617 static void CIdleTimeoutInit(char **argv)
3619 int idle_timeout=0; /*Seconds to wait*/
3620 CmiGetArgIntDesc(argv,"+idle-timeout",&idle_timeout,"Abort if idle for this many seconds");
3621 if(idle_timeout != 0) {
3622 cmi_cpu_idlerec *rec=(cmi_cpu_idlerec *)malloc(sizeof(cmi_cpu_idlerec));
3624 rec->idle_timeout=idle_timeout*1000;
3627 CcdCallOnCondition(CcdPROCESSOR_BEGIN_IDLE, (CcdVoidFn)on_idle, rec);
3628 CcdCallOnCondition(CcdPROCESSOR_BEGIN_BUSY, (CcdVoidFn)on_busy, rec);
3632 /*****************************************************************************
3634 * Converse Initialization
3636 *****************************************************************************/
3639 void CmiIsomallocInit(char **argv);
3640 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3641 void CmiIOInit(char **argv);
3644 /* defined in cpuaffinity.C */
3645 void CmiInitCPUAffinityUtil(void);
3647 static void CmiProcessPriority(char **argv)
3649 int dummy, nicelevel=-100; /* process priority */
3650 CmiGetArgIntDesc(argv,"+nice",&nicelevel,"Set the process priority level");
3652 while (CmiGetArgIntDesc(argv,"+nice",&dummy,"Set the process priority level"));
3653 /* call setpriority once on each process to set process's priority */
3654 if (CmiMyRank() == 0 && nicelevel != -100) {
3656 if (0!=setpriority(PRIO_PROCESS, 0, nicelevel)) {
3657 CmiPrintf("[%d] setpriority failed with value %d. \n", CmiMyPe(), nicelevel);
3658 perror("setpriority");
3659 CmiAbort("setpriority failed.");
3662 CmiPrintf("[%d] Charm++: setpriority %d\n", CmiMyPe(), nicelevel);
3664 HANDLE hProcess = GetCurrentProcess();
3665 DWORD dwPriorityClass = NORMAL_PRIORITY_CLASS;
3666 const char *prio_str = "NORMAL_PRIORITY_CLASS";
3677 #ifdef BELOW_NORMAL_PRIORITY_CLASS
3678 else if (nicelevel<10 && nicelevel>0) {
3679 dwPriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
3680 prio_str = "BELOW_NORMAL_PRIORITY_CLASS";
3683 else if (nicelevel>0) {
3684 dwPriorityClass = IDLE_PRIORITY_CLASS;
3685 prio_str = "IDLE_PRIORITY_CLASS";
3687 else if (nicelevel<=-20) {
3688 dwPriorityClass = REALTIME_PRIORITY_CLASS;
3689 prio_str = "REALTIME_PRIORITY_CLASS";
3691 #ifdef ABOVE_NORMAL_PRIORITY_CLASS
3692 else if (nicelevel>-10 && nicelevel<0) {
3693 dwPriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
3694 prio_str = "ABOVE_NORMAL_PRIORITY_CLASS";
3697 else if (nicelevel<0) {
3698 dwPriorityClass = HIGH_PRIORITY_CLASS;
3699 prio_str = "HIGH_PRIORITY_CLASS";
3701 status = SetPriorityClass(hProcess, dwPriorityClass);
3703 int err=GetLastError();
3704 CmiPrintf("SetPriorityClass failed errno=%d, WSAerr=%d\n",errno, err);
3705 CmiAbort("SetPriorityClass failed.");
3708 CmiPrintf("[%d] Charm++: setpriority %s\n", CmiMyPe(), prio_str);
3713 void CommunicationServerInit(void)
3715 #if CMK_IMMEDIATE_MSG
3719 CpvInitialize(int,CmiImmediateMsgHandlerIdx);
3724 static int testEndian(void)
3727 unsigned char *c=(unsigned char *)&test;
3728 if (c[sizeof(int)-1]==0x1c)
3729 /* Macintosh and most workstations are big-endian */
3730 return 1; /* Big-endian machine */
3732 /* Intel x86 PC's, and DEC VAX are little-endian */
3733 return 0; /* Little-endian machine */
3734 return -2; /*Unknown integer type */
3737 int CmiEndianness(void)
3739 static int _cmi_endianness = -1;
3740 if (_cmi_endianness == -1) _cmi_endianness = testEndian();
3741 CmiAssert(_cmi_endianness != -2);
3742 return _cmi_endianness;
3746 /* This fixes bug #713, which is caused by tsan deadlocking inside
3747 * a 'write' syscall inside a mutex. */
3748 static void checkTSanOptions(void)
3750 char *env = getenv("TSAN_OPTIONS");
3753 !strstr(env, "log_path=") ||
3754 strstr(env, "log_path=stdout") ||
3755 strstr(env, "log_path=stderr")) {
3756 CmiAbort("TSAN output must be redirected to disk.\n"
3757 "Run this program with TSAN_OPTIONS=\"log_path=filename\"");
3762 #if CMK_CCS_AVAILABLE
3763 extern int ccsRunning;
3767 extern int quietModeRequested;
3768 int quietModeRequested; // user has requested quiet mode
3769 extern int quietMode;
3770 int quietMode; // quiet mode active (CmiPrintf's are disabled)
3771 CmiSpanningTreeInfo* _topoTree = NULL;
3774 Main Converse initialization routine. This routine is
3775 called by the machine file (machine.C) to set up Converse.
3776 It's "Common" because it's shared by all the machine.C files.
3778 The main task of this routine is to set up all the Cpv's
3779 (message queues, handler tables, etc.) used during main execution.
3781 On SMP versions, this initialization routine is called by
3782 *all* processors of a node simultaniously. It's *also* called
3783 by the communication thread, which is rather strange but needed
3784 for immediate messages. Each call to this routine expects a
3785 different copy of the argv arguments, so use CmiCopyArgs(argv).
3788 - A working network layer.
3789 - Working Cpv's and CmiNodeBarrier.
3790 - CthInit to already have been called. CthInit is called
3791 from the machine layer directly, because some machine layers
3792 (like uth) use Converse threads internally.
3794 Initialization is somewhat subtle, in that various modules
3795 won't work properly until they're initialized. For example,
3796 nobody can register handlers before calling CmiHandlerInit.
3798 void ConverseCommonInit(char **argv)
3800 CpvInitialize(int, _urgentSend);
3801 CpvAccess(_urgentSend) = 0;
3802 CpvInitialize(int,interopExitFlag);
3803 CpvAccess(interopExitFlag) = 0;
3805 CpvInitialize(int,_curRestartPhase);
3806 CpvAccess(_curRestartPhase)=1;
3808 CmiMemoryInit(argv);
3809 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3813 CmiPrintf("Converse/Charm++ Commit ID: %s\n", CmiCommitID);
3815 CpvInitialize(int, cmiMyPeIdle);
3816 CpvAccess(cmiMyPeIdle) = 0;
3819 CmiPoolAllocInit(30);
3824 CmiInitCPUAffinityUtil();
3826 CcdModuleInit(argv);
3828 CmiReductionsInit();
3829 CIdleTimeoutInit(argv);
3831 #if CMK_SHARED_VARS_POSIX_THREADS_SMP /*Used by the netlrts-*-smp and multicore versions*/
3832 if(CmiGetArgFlagDesc(argv, "+CmiSpinOnIdle", "Force the runtime system to spin on message reception when idle, rather than sleeping")) {
3833 if(CmiMyRank() == 0) _Cmi_forceSpinOnIdle = 1;
3835 if(CmiGetArgFlagDesc(argv, "+CmiSleepOnIdle", "Force the runtime system to sleep when idle, rather than spinning on message reception")) {
3836 if(CmiMyRank() == 0) _Cmi_sleepOnIdle = 1;
3838 if(CmiGetArgFlagDesc(argv,"+CmiNoProcForComThread","Is there an extra processor for the communication thread on each node(only for netlrts-smp-*) ?")){
3839 if (CmiMyPe() == 0) {
3840 CmiPrintf("Charm++> Note: The option +CmiNoProcForComThread has been superseded by +CmiSleepOnIdle\n");
3842 if(CmiMyRank() == 0) _Cmi_sleepOnIdle=1;
3844 if (_Cmi_sleepOnIdle && _Cmi_forceSpinOnIdle) {
3845 if(CmiMyRank() == 0) CmiAbort("The option +CmiSpinOnIdle is mutually exclusive with the options +CmiSleepOnIdle and +CmiNoProcForComThread");
3849 #if CMK_TRACE_ENABLED
3851 /*initTraceCore(argv);*/ /* projector */
3853 CmiProcessPriority(argv);
3859 CmiPersistentInit();
3860 CmiIsomallocInit(argv);
3861 // Initialize converse handlers for supporting generic Direct Nocopy API
3862 CmiOnesidedDirectInit();
3865 #if CMK_CCS_AVAILABLE
3873 CmiInitMultipleSend();
3879 CmiInitImmediateMsg();
3880 CldModuleInit(argv);
3887 /* main thread is suspendable */
3889 CthSetSuspendable(CthSelf(), 0);
3892 #if CMK_BIGSIM_CHARM
3893 /* have to initialize QD here instead of _initCharm */
3898 void ConverseCommonExit(void)
3902 #if CMK_TRACE_ENABLED
3904 /*closeTraceCore();*/ /* projector */
3907 #if CMI_IO_BUFFER_EXPLICIT
3908 CmiFlush(stdout); /* end of program, always flush */
3916 // ensure all PEs have finished GPU work before destructing
3917 if(CmiMyRank() < CmiMyNodeSize()) {
3920 if (CmiMyRank() == 0) {
3931 extern void register_accel_spe_funcs(void);
3933 void CmiInitCell(void)
3935 // Create a unique string for each PPE to use for the timing
3937 char fileNameBuf[64];
3938 sprintf(fileNameBuf, "speTiming.%d", CmiMyPe());
3940 InitOffloadAPI(offloadCallback, NULL, NULL, fileNameBuf);
3941 //CcdCallOnConditionKeep(CcdPERIODIC,
3942 // (CcdVoidFn) OffloadAPIProgress, NULL);
3943 CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,
3944 (CcdVoidFn) OffloadAPIProgress, NULL);
3946 // Register accelerated entry methods on the PPE
3947 register_accel_spe_funcs();
3950 #include "cell-api.c"
3955 * CW Lee - 9/14/2005
3956 * Added a mechanism to allow some control over machines with extremely
3957 * inefficient terminal IO mechanisms. Case in point: the XT3 has a
3958 * 20ms flush overhead along with about 25MB/s bandwidth for IO. This,
3959 * coupled with a default setup using unbuffered stdout introduced
3960 * severe overheads (and hence limiting scaling) for applications like
3963 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3964 void CmiIOInit(char **argv) {
3965 CpvInitialize(int, expIOFlushFlag);
3966 #if CMI_IO_BUFFER_EXPLICIT
3968 Support for an explicit buffer only makes sense if the machine
3969 layer does not wish to make its own implementation.
3971 Placing this after CmiMemoryInit() means that CmiMemoryInit()
3972 MUST NOT make use of stdout if an explicit buffer is requested.
3974 The setvbuf function may only be used after opening a stream and
3975 before any other operations have been performed on it
3977 CpvInitialize(char*, explicitIOBuffer);
3978 CpvInitialize(int, expIOBufferSize);
3979 if (!CmiGetArgIntDesc(argv,"+io_buffer_size", &CpvAccess(expIOBufferSize),
3980 "Explicit IO Buffer Size")) {
3981 CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3983 if (CpvAccess(expIOBufferSize) <= 0) {
3984 CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3986 CpvAccess(explicitIOBuffer) = (char*)CmiAlloc(CpvAccess(expIOBufferSize)*
3988 if (setvbuf(stdout, CpvAccess(explicitIOBuffer), _IOFBF,
3989 CpvAccess(expIOBufferSize))) {
3990 CmiAbort("Explicit IO Buffering failed\n");
3993 #if CMI_IO_FLUSH_USER
3994 /* system default to have user control flushing of IO */
3995 /* Now look for user override */
3996 CpvAccess(expIOFlushFlag) = !CmiGetArgFlagDesc(argv,"+io_flush_system",
3997 "System Controls IO Flush");
3999 /* system default to have system handle IO flushing */
4000 /* Now look for user override */
4001 CpvAccess(expIOFlushFlag) = CmiGetArgFlagDesc(argv,"+io_flush_user",
4002 "User Controls IO Flush");
4007 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
4009 void CmiPrintf(const char *format, ...)
4011 if (quietMode) return;
4015 va_start(args,format);
4016 vfprintf(stdout,format, args);
4017 if (CpvInitialized(expIOFlushFlag) && !CpvAccess(expIOFlushFlag)) {
4021 #if CMK_CCS_AVAILABLE && CMK_CMIPRINTF_IS_A_BUILTIN
4022 if (CpvAccess(cmiArgDebugFlag)) {
4023 va_start(args,format);
4024 print_node0(format, args);
4032 void CmiError(const char *format, ...)
4037 va_start(args,format);
4038 vfprintf(stderr,format, args);
4039 CmiFlush(stderr); /* stderr is always flushed */
4041 #if CMK_CCS_AVAILABLE && CMK_CMIPRINTF_IS_A_BUILTIN
4042 if (CpvAccess(cmiArgDebugFlag)) {
4043 va_start(args,format);
4044 print_node0(format, args);
4054 void __cmi_assert(const char *errmsg)
4056 CmiError("[%d] %s\n", CmiMyPe(), errmsg);
4060 char *CmiCopyMsg(char *msg, int len)
4062 char *copy = (char *)CmiAlloc(len);
4064 memcpy(copy, msg, len);
4068 unsigned char computeCheckSum(unsigned char *data, int len)
4071 unsigned char ret = 0;
4072 for (i=0; i<len; i++) ret ^= (unsigned char)data[i];
4076 /* Flag for bigsim's out-of-core emulation */
4077 int _BgOutOfCoreFlag=0; /*indicate the type of memory operation (in or out) */
4078 int _BgInOutOfCoreMode=0; /*indicate whether the emulation is in the out-of-core emulation mode */
4081 unsigned int CmiILog2(unsigned int val) {
4082 unsigned int log = 0u;
4084 while ( val > (1u<<log) ) { log++; }
4088 double CmiLog2(double x) {
4089 return log(x)/log(2);
4094 int CmiMyRank_(void)
4099 double CmiReadSize(const char *str)
4102 if (strpbrk(str,"Gg")) {
4103 //sscanf(str, "%llf", &val);
4104 //val = strtod(str, &p);
4106 val *= 1024ll*1024*1024;
4108 else if (strpbrk(str,"Mm")) {
4112 else if (strpbrk(str,"Kk")) {
4122 void CmiSetPeHelpsOtherThreads(int input) {
4123 CpvAccess(isHelperOn) = input;
4124 CmiMemoryWriteFence();