📄 numa.c
字号:
if( mreq->cmd & MEMSYS_DMAFLAVOR ) { data = (byte*)DATA_ADDR(mreq->machnum, mreq->reqAddr); } else { data = (byte*)DATA_ADDR(mreq->machnum, mreq->addr); } hist = &(mState->stats.reqtime); StatsIncHist(hist, difftime); hist = &(globalStats[isLocal].reqtime); StatsIncHist(hist, difftime); if (mreq->memnum != mreq->localMemNum) { mreq->result |= MEMSYS_RESULT_REMOTE_HOME; } if (mreq->mode == MEMSYS_UNCACHED) { if ((mreq->cmd & MEMSYS_CMDMASK) == MEMSYS_UNCREAD) { void *from = (void*)DATA_ADDR(mreq->machnum, (uint)mreq->reqAddr); bcopy(from, mreq->data, mreq->len); /* Unstall the processor */ ASSERT(CPUVec.ReissueUncachedOp); CPUVec.ReissueUncachedOp(mreq->cpunum); } else { void *to = (void*)DATA_ADDR(mreq->machnum, (uint)mreq->reqAddr); bcopy(mreq->data, to, mreq->len); } } else { CacheCmdDone(mreq->cpunum, mreq->transId, mreq->mode, mreq->status, mreq->result, data); } mreq->state = ALL_DONE; List_Insert(MREQ_TO_LIST(mreq), LIST_ATREAR(&freeMemReqList));}/* Update the stats on a new request */static voidUpdateRequestStats(MemRequest *mreq){ switch (mreq->cmd & MEMSYS_CMDMASK) { case MEMSYS_GET: if (mreq->cmd & MEMSYS_DMAFLAVOR) { StatsInc(COUNT_DMAGETS, mreq, 1); } else { if (mreq->cmd & MEMSYS_IFFLAVOR) { StatsInc(COUNT_IGETS, mreq, 1); } else if (mreq->cmd & MEMSYS_LLFLAVOR) { StatsInc(COUNT_LLGETS, mreq, 1); } else { StatsInc(COUNT_DGETS, mreq, 1); } if (mreq->replacedPaddr != MEMSYS_NOADDR) { if (mreq->replaceWasDirty) { StatsInc(COUNT_WRITEBACKS, mreq, 1); } else { StatsInc(COUNT_REPLHINTS, mreq, 1); } } } break; case MEMSYS_GETX: if (mreq->cmd & MEMSYS_DMAFLAVOR) { StatsInc(COUNT_DMAGETXS, mreq, 1); } else { StatsInc(COUNT_GETXS, mreq, 1); if (mreq->replacedPaddr != MEMSYS_NOADDR) { if (mreq->replaceWasDirty) { StatsInc(COUNT_WRITEBACKS, mreq, 1); } else { StatsInc(COUNT_REPLHINTS, mreq, 1); } } } break; case MEMSYS_UPGRADE: if (mreq->cmd & MEMSYS_SCFLAVOR) { StatsInc(COUNT_SCUPGRADES, mreq, 1); } else { StatsInc(COUNT_UPGRADES, mreq, 1); } break; case MEMSYS_UNCWRITE: StatsInc(COUNT_UNCACHEDWRITES, mreq, 1); break; case MEMSYS_UNCWRITE_ACCELERATED: StatsInc(COUNT_UNCACHEDACCWRITES, mreq, 1); break; case MEMSYS_UNCREAD: StatsInc(COUNT_UNCACHEDREADS, mreq, 1); break; case MEMSYS_REPLACEMENT_HINT: StatsInc(COUNT_REPLHINTS, mreq, 1); break; case MEMSYS_WRITEBACK: StatsInc(COUNT_WRITEBACKS, mreq, 1); break; default: CPUError("Unknown memsys command (0x%x) in UmaCmd\n", mreq->cmd); }}/***************************************************************** * MemsysInit *****************************************************************/void NumaInit(void){ int i; u_long lines_per_mem, size; /* * Initialize the pointers to functions and delay parameters */ memsysVec.type = NUMA; memsysVec.NoMemoryDelay = 0; memsysVec.MemsysCmd = NumaCmd; memsysVec.MemsysDumpStats = NumaDumpStats; memsysVec.MemsysDone = NumaDone; memsysVec.MemsysStatus = NumaStatus;#ifndef SOLO memsysVec.MemsysDrain = NumaDrain; memsysVec.MemsysSetRemap = NumaSetRemap; memsysVec.MemsysControlRemap = NumaControlRemap; memsysVec.MemsysGetNodeAddress = NumaGetNodeAddress;#endif CPUPrint("MEM num igets llgets dmagets dgets dmagetxs getxs scupgrades upgrades writebacks replhints uncachedwrites uncachedaccwrites uncachedreads invalordngradesent naks remotedirty exclusiveonshared memoryaccess misscount totlatency\n"); /* * Initialize the list of request structures */ List_Init(&freeMemReqList); for (i = 0; i < MAX_OUTSTANDING; i++) { MemRequest *mreq = MemRequestStorage + i; bzero((char *) (mreq), sizeof(MemRequestStorage[0])); List_InitElement(MREQ_TO_LIST(mreq)); List_Insert(MREQ_TO_LIST(mreq), LIST_ATREAR(&freeMemReqList)); } /* * Initialize the list of Invalidate structures */ List_Init(&freeInvalReqList); for (i = 0; i < MAX_INVALS; i++) { InvalRequest *lreq = InvalRequestStorage + i; bzero((char *) (lreq), sizeof(InvalRequestStorage[0])); List_InitElement(INVAL_TO_LIST(lreq)); List_Insert(INVAL_TO_LIST(lreq), LIST_ATREAR(&freeInvalReqList)); } /* * Allocate and initialize the directory state for each memory, * the stats per memory and the overall stats. */ lines_per_mem = MEM_SIZE(0) / SCACHE_LINE_SIZE; size = sizeof(MemState)+ (sizeof(DirState)*lines_per_mem); for (i = 0; i < NUM_MEMORIES(0); i++) { if (!numaDoneInit) { memState[i] = (MemState *) ZMALLOC(size, "memState"); } ASSERT(memState[i]); List_Init(&memState[i]->memoryQueue); List_Init(&memState[i]->localQueue); bzero((char *) &memState[i]->dirState, sizeof(DirState)*lines_per_mem); bzero((char *) &memState[i]->stats, sizeof(NumaStats)); } bzero((char *) globalStats, 2*sizeof(NumaStats));#ifndef SOLO NumaInitRemap(); if (NUMA_STRIPE_SIZE < 0) { numaStripeSizePages = MEM_SIZE(0)/PAGE_SIZE/NUM_MEMORIES(0); } else { numaStripeSizePages = NUMA_STRIPE_SIZE; } numaStripeSizeBytes = numaStripeSizePages*PAGE_SIZE; numaStripeSizeLines = numaStripeSizeBytes/SCACHE_LINE_SIZE; numaStripeChunk = numaStripeSizeBytes*NUM_MEMORIES(0); ASSERT(NUMA_STRIPE_SIZE < 0); if (ENABLE_COUNT) MigRepNumaInit();#endif numaDoneInit = 1;}/***************************************************************** * MemsysCmd * * Main interface from secondary cache into here * For DMA opeartions, the writeback parameter holds the * length of the DMA transfer and is NOT a boolean. *****************************************************************/ResultNumaCmd(int cpuNum, int cmd, PA addr, int transId, PA replacedPaddr, int writeback, byte *data){ MemState *mState; MemRequest *mreq = NULL; List_Links *itemPtr; int memnum; int stall = 1; #ifndef SOLO addr = REMAP_PADDR(addr, cpuNum); replacedPaddr = REMAP_PADDR(replacedPaddr, cpuNum);#endif if (cmd == MEMSYS_SYNC) { return SUCCESS; } if ((cmd == MEMSYS_GET) && (transId == -1)) { /* * Ugly hack for Cache instructions. Note the DMAFLAVOR also * uses negative transids too. However it sets MEMSYS_DMAFLAVOR * Should be fixed by having MIPSY use the cmds MEMSYS_WRITEBACK/REPLHINT * Original comment attached: * Handle special case: a GET with transId -1 indicates * a writeback or repl hint without the associated GET (due * to a CACHE instruction executed in the processor) */ if (writeback) { cmd = MEMSYS_WRITEBACK; } else { cmd = MEMSYS_REPLACEMENT_HINT; } } /* A number of cases do not need an mreq allocated */ switch (cmd & MEMSYS_CMDMASK) { case MEMSYS_GET: case MEMSYS_GETX: case MEMSYS_UPGRADE: memnum = NumaAddrToMemnum(addr); mState = memState[memnum]; /* * Got a request. Allocate and fill in a memrequest */ itemPtr = List_First(&freeMemReqList); ASSERT(itemPtr != &freeMemReqList); List_Remove(itemPtr); mreq = LIST_TO_MREQ(itemPtr); mreq->cmd = cmd; mreq->transId = transId; mreq->reqAddr = addr; mreq->addr = addr & ~(SCACHE_LINE_SIZE-1); mreq->data = data; mreq->len = writeback; if( cmd & MEMSYS_DMAFLAVOR ) { ASSERT( transId < 0 ); ASSERT( data ); mreq->replaceWasDirty = 0; } else { mreq->replaceWasDirty = writeback; } mreq->replacedPaddr = replacedPaddr; mreq->status = MEMSYS_STATUS_SUCCESS; mreq->memnum = memnum; mreq->machnum = M_FROM_CPU(cpuNum); mreq->cpunum = cpuNum; mreq->localMemNum = NumaLocalMem(cpuNum); mreq->dirState = &mState->dirState[NumaAddrToMemline(addr)]; mreq->result = MEMSYS_RESULT_MEMORY|MEMSYS_RESULT_NOTRANSITION; UpdateRequestStats(mreq); break; default: break; } switch (cmd & MEMSYS_CMDMASK) { case MEMSYS_GET: mreq->mode = MEMSYS_SHARED; break; case MEMSYS_GETX: mreq->mode = MEMSYS_EXCLUSIVE; break; case MEMSYS_UPGRADE: mreq->mode = MEMSYS_EXCLUSIVE; break; case MEMSYS_UNCWRITE: case MEMSYS_UNCWRITE_ACCELERATED: /* Currently uncached write return with no delay, */ globalStats[1].counts[MEMSYS_UNCWRITE]++;#ifndef SOLO { Result ret; ASSERT(CPUVec.UncachedPIO); ret = CPUVec.UncachedPIO(cpuNum, addr, 0, writeback, data); ASSERT(ret == SUCCESS); return SUCCESS; } #else stall = 0; break;#endif case MEMSYS_UNCREAD: /* Data handling is done in SendReplyToCPU for non-KSEG1 */ globalStats[1].counts[MEMSYS_UNCREAD]++;#ifndef SOLO { Result ret; ASSERT(CPUVec.UncachedPIO); ret = CPUVec.UncachedPIO(cpuNum, addr, 1, writeback, data); ASSERT(ret == SUCCESS); return SUCCESS; }#else break;#endif case MEMSYS_WRITEBACK: case MEMSYS_REPLACEMENT_HINT: stall = 0; break; default: CPUError("Unknown memsys command (0x%x) for memsys Numa\n", cmd); } /* * Handle replacement hints and writebacks here. */ if (replacedPaddr != MEMSYS_NOADDR) { int rmemnum = NumaAddrToMemnum(replacedPaddr); DirState *dir = &memState[rmemnum]->dirState[NumaAddrToMemline(replacedPaddr)]; MemRequest *wreq; /* * Allocate and fill in a memrequest for the writeback */ itemPtr = List_First(&freeMemReqList); ASSERT(itemPtr != &freeMemReqList); List_Remove(itemPtr); wreq = LIST_TO_MREQ(itemPtr); wreq->data = 0; if (writeback) { wreq->cmd = MEMSYS_WRITEBACK; if (data) { wreq->data = malloc(SCACHE_LINE_SIZE); bcopy(data, wreq->data, SCACHE_LINE_SIZE); } } else { wreq->cmd = MEMSYS_REPLACEMENT_HINT; } wreq->transId = transId; wreq->reqAddr = 0; wreq->addr = 0; wreq->len = 0; wreq->replaceWasDirty = writeback; wreq->replacedPaddr = replacedPaddr; wreq->status = MEMSYS_STATUS_SUCCESS; wreq->memnum = rmemnum; wreq->machnum = M_FROM_CPU(cpuNum); wreq->cpunum = cpuNum; wreq->localMemNum = NumaLocalMem(cpuNum); wreq->dirState = dir; wreq->result = MEMSYS_RESULT_MEMORY|MEMSYS_RESULT_NOTRANSITION; wreq->drainNeeded = 1; UpdateRequestStats(wreq); /* * add 1 cycle to this to ensure that it does not get ahead of the original * request through the DC queue */ EventDoCallback(wreq->cpunum, RequestLocal, (EventCallbackHdr *) wreq, 0, NUMA_BUS_TIME + 1); } if (stall) { /* * Queue us for the Local delay */ mreq->starttime = CPUVec.CycleCount(mreq->cpunum); mreq->hdr.rout = RequestLocal; mreq->state = REQ_LOCAL_WAIT; EventDoCallback(mreq->cpunum, RequestLocal, (EventCallbackHdr *) mreq, 0, NUMA_BUS_TIME); return STALL; } else { return SUCCESS; }}void NumaDone(void){ CPUPrint("Exiting the NUMA memory system\n");}/* Dump stats about the memory system */void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -