/** * Obtain the number of nodes, my node id, and consuming machine layer * specific arguments */ static void MachineInitForLAPI(int *argc, char ***argv, int *numNodes, int *myNodeID) { lapi_info_t info; char **largv = *argv; memset(&info,0,sizeof(info)); /* Register error handler (redundant?) -- added by Chao Mei*/ info.err_hndlr = (LAPI_err_hndlr *)lapi_err_hndlr; /* Indicates the number of completion handler threads to create */ /* The number of completion hndlr thds will affect the atomic PCQueue operations!! */ /* NOTE: num_compl_hndlr_thr is obsolete now! --Chao Mei */ /* info.num_compl_hndlr_thr = 1; */ check_lapi(LAPI_Init,(&lapiContext, &info)); /* It's a good idea to start with a fence, because packets recv'd before a LAPI_Init are just dropped. */ check_lapi(LAPI_Gfence,(lapiContext)); check_lapi(LAPI_Qenv,(lapiContext, TASK_ID, myNodeID)); check_lapi(LAPI_Qenv,(lapiContext, NUM_TASKS, numNodes)); /* Make polling as the default mode as real apps have better perf */ CsvAccess(lapiInterruptMode) = 0; if (CmiGetArgFlag(largv,"+poll")) CsvAccess(lapiInterruptMode) = 0; if (CmiGetArgFlag(largv,"+nopoll")) CsvAccess(lapiInterruptMode) = 1; check_lapi(LAPI_Senv,(lapiContext, ERROR_CHK, lapiDebugMode)); check_lapi(LAPI_Senv,(lapiContext, INTERRUPT_SET, CsvAccess(lapiInterruptMode))); if (*myNodeID == 0) { printf("Running lapi in interrupt mode: %d\n", CsvAccess(lapiInterruptMode)); printf("Running lapi with %d completion handler threads.\n", info.num_compl_hndlr_thr); } /** * Associate PumpMsgsBegin with var "lapiHeaderHandler". Then inside Xfer calls, * lapiHeaderHandler could be used to indicate the callback * instead of PumpMsgsBegin --Chao Mei */ check_lapi(LAPI_Addr_set,(lapiContext,(void *)PumpMsgsBegin,lapiHeaderHandler)); if (CmiGetArgFlag(largv,"++debug")) { /*Pause so user has a chance to start and attach debugger*/ printf("CHARMDEBUG> Processor %d has PID %d\n",*myNodeID,getpid()); if (!CmiGetArgFlag(largv,"++debug-no-pause")) sleep(30); } #if ENSURE_MSG_PAIRORDER cmplHdlrThdLock = CmiCreateLock(); #endif }
CpmInvokable vars_set_cpv_and_csv(vars_chare c) { CpvAccess(cpv1) = CmiMyPe(); if (CmiMyRank() == 0) CsvAccess(csv1) = 0x12345678; Cpm_vars_ack(CpmSend(0), c); }
static void MachinePostCommonInitForLAPI(int everReturn) { /** * In SMP, the machine layer usually has one comm thd, and it is * designed to be responsible for all network communication. So * if there's no dedicated processor for the comm thread, it has * to share a proc with a worker thread. In this scenario, * the worker thread needs to yield for some time to give CPU * time to comm thread. However, in current configuration, we * will always dedicate one proc for the comm thd, therefore, * such yielding scheme is not necessary. Besides, avoiding * this yielding scheme improves performance because worker * thread doesn't need to yield and will be more responsive to * incoming messages. So, we will always use CmiNotifyIdle * instead. * * --Chao Mei */ /* Not registering any Idle-state related functions right now!! */ #if 0 && CMK_SMP s=CmiNotifyGetState(); CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)CmiNotifyBeginIdle,(void *)s); CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,(CcdVoidFn)CmiNotifyStillIdle,(void *)s); #else CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,(CcdVoidFn)CmiNotifyIdle,NULL); #if !CMK_SMP || CMK_SMP_NO_COMMTHD /* If there's comm thread, then comm thd is responsible for advancing comm */ if (!CsvAccess(lapiInterruptMode)) { CcdCallOnConditionKeep(CcdPERIODIC_10ms, (CcdVoidFn)AdvanceCommunicationForLAPI, NULL); } #endif #endif }
static void handleOneBcastMsg(int size, char *msg) { CmiAssert(CMI_BROADCAST_ROOT(msg)!=0); #if CMK_OFFLOAD_BCAST_PROCESS if (CMI_BROADCAST_ROOT(msg)>0) { CMIQueuePush(CsvAccess(procBcastQ), msg); } else { #if CMK_NODE_QUEUE_AVAILABLE CMIQueuePush(CsvAccess(nodeBcastQ), msg); #endif } #else if (CMI_BROADCAST_ROOT(msg)>0) { processProcBcastMsg(size, msg); } else { #if CMK_NODE_QUEUE_AVAILABLE processNodeBcastMsg(size, msg); #endif } #endif }
CpmInvokable vars_check_cpv_and_csv(vars_chare c) { if (CpvAccess(cpv1) != CmiMyPe()) { CmiPrintf("cpv privacy test failed.\n"); exit(1); } if (CsvAccess(csv1) != 0x12345678) { CmiPrintf("csv sharing test failed.\n"); exit(1); } Cpm_vars_ack(CpmSend(0), c); }
static void processBcastQs() { #if CMK_OFFLOAD_BCAST_PROCESS char *msg; do { msg = CMIQueuePop(CsvAccess(procBcastQ)); if (!msg) break; MACHSTATE2(4, "[%d]: process a proc-level bcast msg %p begin{", CmiMyNode(), msg); processProcBcastMsg(CMI_MSG_SIZE(msg), msg); MACHSTATE2(4, "[%d]: process a proc-level bcast msg %p end}", CmiMyNode(), msg); } while (1); #if CMK_NODE_QUEUE_AVAILABLE do { msg = CMIQueuePop(CsvAccess(nodeBcastQ)); if (!msg) break; MACHSTATE2(4, "[%d]: process a node-level bcast msg %p begin{", CmiMyNode(), msg); processNodeBcastMsg(CMI_MSG_SIZE(msg), msg); MACHSTATE2(4, "[%d]: process a node-level bcast msg %p end}", CmiMyNode(), msg); } while (1); #endif #endif }
void CmiMachineProgressImpl() { if (!CsvAccess(lapiInterruptMode)) check_lapi(LAPI_Probe,(lapiContext)); #if CMK_IMMEDIATE_MSG MACHSTATE1(2, "[%d] Handling Immediate Message begin {",CmiMyNode()); CmiHandleImmediate(); MACHSTATE1(2, "[%d] Handling Immediate Message end }",CmiMyNode()); #endif #if CMK_SMP && !CMK_SMP_NO_COMMTHD && CMK_OFFLOAD_BCAST_PROCESS if (CmiMyRank()==CmiMyNodeSize()) processBcastQs(); /* FIXME ????????????????*/ #endif }
static INLINE_KEYWORD void AdvanceCommunicationForLAPI(int idle) { /* What about CMK_SMP_NO_COMMTHD in the original implementation?? */ /* It does nothing but sleep */ if (!CsvAccess(lapiInterruptMode)) check_lapi(LAPI_Probe,(lapiContext)); }
/** * Returns 1 if this "msg" is an out-of-order message, or * this "msg" is a late message which triggers the process * of all buffered ooo msgs. * --Chao Mei */ static int checkMsgInOrder(char *msg, MsgOrderInfo *info) { int srcpe, destrank; int incomingSeqNo, expectedSeqNo; int curOffset, maxOffset; int i, curWinSize; void **destMsgBuffer = NULL; /* numMsg is the number of msgs to be processed in this buffer*/ /* Reason to have this extra copy of msgs to be processed: Reduce the atomic granularity */ void **toProcessMsgBuffer; int numMsgs = 0; srcpe = CMI_MSG_SRCPE(msg); destrank = CMI_DEST_RANK(msg); incomingSeqNo = CMI_MSG_SEQNO(msg); CmiLock(cmplHdlrThdLock); expectedSeqNo = getNextExpectedMsgSeqNo(info->expectedMsgSeqNo, srcpe); if (expectedSeqNo == incomingSeqNo) { /* Two cases: has ooo msg buffered or not */ maxOffset = (info->oooMaxOffset)[srcpe]; if (maxOffset>0) { MACHSTATE1(4, "Processing all buffered ooo msgs (maxOffset=%d) including the just recved begin {", maxOffset); curWinSize = info->CUR_WINDOW_SIZE[srcpe]; toProcessMsgBuffer = malloc((curWinSize+1)*sizeof(void *)); /* process the msg just recved */ toProcessMsgBuffer[numMsgs++] = msg; /* process the buffered ooo msg until the first empty slot in the window */ destMsgBuffer = (info->oooMsgBuffer)[srcpe]; for (curOffset=0; curOffset<maxOffset; curOffset++) { char *curMsg = destMsgBuffer[curOffset]; if (curMsg == NULL) { CmiAssert(curOffset!=(maxOffset-1)); break; } toProcessMsgBuffer[numMsgs++] = curMsg; destMsgBuffer[curOffset] = NULL; } /* Update expected seqno, maxOffset and slide the window */ if (curOffset < maxOffset) { int i; /** * now, the seqno of the next to-be-recved msg should be * "expectedSeqNo+curOffset+1" as the seqno of the just * processed msg is "expectedSeqNo+curOffset. We need to slide * the msg buffer window from "curOffset+1" because the first * element of the buffer window should always points to the ooo * msg that's 1 in terms of seqno ahead of the next to-be-recved * msg. --Chao Mei */ /* moving [curOffset+1, maxOffset) to [0, maxOffset-curOffset-1) in the window */ /* The following two loops could be combined --Chao Mei */ for (i=0; i<maxOffset-curOffset-1; i++) { destMsgBuffer[i] = destMsgBuffer[curOffset+i+1]; } for (i=maxOffset-curOffset-1; i<maxOffset; i++) { destMsgBuffer[i] = NULL; } (info->oooMaxOffset)[srcpe] = maxOffset-curOffset-1; setNextExpectedMsgSeqNo(info->expectedMsgSeqNo, srcpe, expectedSeqNo+curOffset); } else { /* there's no remaining buffered ooo msgs */ (info->oooMaxOffset)[srcpe] = 0; setNextExpectedMsgSeqNo(info->expectedMsgSeqNo, srcpe, expectedSeqNo+maxOffset); } CmiUnlock(cmplHdlrThdLock); /* Process the msgs */ for (i=0; i<numMsgs; i++) { char *curMsg = toProcessMsgBuffer[i]; if (CMI_BROADCAST_ROOT(curMsg)>0) { #if CMK_OFFLOAD_BCAST_PROCESS PCQueuePush(CsvAccess(procBcastQ), curMsg); #else processProcBcastMsg(CMI_MSG_SIZE(curMsg), curMsg); #endif } else { CmiPushPE(CMI_DEST_RANK(curMsg), curMsg); } } free(toProcessMsgBuffer); MACHSTATE1(4, "Processing all buffered ooo msgs (actually processed %d) end }", curOffset); /** * Since we have processed all buffered ooo msgs including * this just recved one, 1 should be returned so that this * msg no longer needs processing */ return 1; } else { /* An expected msg recved without any ooo msg buffered */ MACHSTATE1(4, "Receiving an expected msg with seqno=%d\n", incomingSeqNo); setNextExpectedMsgSeqNo(info->expectedMsgSeqNo, srcpe, expectedSeqNo); CmiUnlock(cmplHdlrThdLock); return 0; } } MACHSTATE2(4, "Receiving an out-of-order msg with seqno=%d, but expect seqno=%d", incomingSeqNo, expectedSeqNo); curWinSize = info->CUR_WINDOW_SIZE[srcpe]; if ((info->oooMsgBuffer)[srcpe]==NULL) { (info->oooMsgBuffer)[srcpe] = malloc(curWinSize*sizeof(void *)); memset((info->oooMsgBuffer)[srcpe], 0, curWinSize*sizeof(void *)); } destMsgBuffer = (info->oooMsgBuffer)[srcpe]; curOffset = incomingSeqNo - expectedSeqNo; maxOffset = (info->oooMaxOffset)[srcpe]; if (curOffset<0) { /* It's possible that the seqNo starts with another round (exceeding MAX_MSG_SEQNO) with 1 */ curOffset += MAX_MSG_SEQNO; } if (curOffset > curWinSize) { int newWinSize; if (curOffset > MAX_WINDOW_SIZE) { CmiAbort("Exceeding the MAX_WINDOW_SIZE!\n"); } newWinSize = ((curOffset/curWinSize)+1)*curWinSize; /*CmiPrintf("[%d]: WARNING: INCREASING WINDOW SIZE FROM %d TO %d\n", CmiMyPe(), curWinSize, newWinSize);*/ (info->oooMsgBuffer)[srcpe] = malloc(newWinSize*sizeof(void *)); memset((info->oooMsgBuffer)[srcpe], 0, newWinSize*sizeof(void *)); memcpy((info->oooMsgBuffer)[srcpe], destMsgBuffer, curWinSize*sizeof(void *)); info->CUR_WINDOW_SIZE[srcpe] = newWinSize; free(destMsgBuffer); destMsgBuffer = (info->oooMsgBuffer)[srcpe]; } CmiAssert(destMsgBuffer[curOffset-1] == NULL); destMsgBuffer[curOffset-1] = msg; if (curOffset > maxOffset) (info->oooMaxOffset)[srcpe] = curOffset; CmiUnlock(cmplHdlrThdLock); return 1; }