📄 numa.c
字号:
/* * Copyright (C) 1996-1998 by the Board of Trustees * of Leland Stanford Junior University. * * This file is part of the SimOS distribution. * See LICENSE file for terms of the license. * *//***************************************************************** * File: numa.c * * NUMA memory system. * * Parameters are: * NUMA_BUS_TIME: fixed delay for bus/interconnect between CPU and DC * NUMA_PILOCAL_DC_TIME * NUMA_PIREMOTE_DC_TIME * NUMA_NILOCAL_DC_TIME * NUMA_NIREMOTE_DC_TIME * NUMA_NET_TIME: fixed delay for network transit * NUMA_MEM_TIME: contention based delay for access to DRAM * Minimum local miss time is 2*(NUMA_BUS_TIME) + (NUMA_PILOCAL_DC_TIME) + (NUMA_MEM_TIME) * Minimum remote miss time is 2*(NUMA_BUS_TIME) * + NUMA_PIREMOTE_DC_TIME * + NUMA_NILOCAL_DC_TIME * + NUMA_NIREMOTE_DC_TIME * + (NUMA_MEM_TIME) + 2*(NUMA_NET_TIME) * * Author: $Author: bosch $ * Date: $Date: 1998/02/10 00:37:20 $ *****************************************************************/#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include "syslimits.h"#include "scache.h"#include "memsys.h"#include "sim_error.h"#include "simutil.h"#include "eventcallback.h"#include "list.h"#include "cpu_interface.h"#include "registry.h"/* * Flag for memory system init to prevent repeated mallocs when switching */static uint numaDoneInit = 0; #define NUMA_MAX_MEMORIES 64#define PAGE_NUM(x) (x)/PAGE_SIZEstatic uint numaStripeSizePages;static uint numaStripeSizeBytes;static uint numaStripeSizeLines;static uint numaStripeChunk;/* * Numa memsystem version of the counting code in flashlite * Counts, at the home, cache misses/CPU (countdown from Trigger) and write misses. * Things are done to mirror the flashlite counting implementation closely * Count misses in DirContDone for Get and GetX * Mark writes in DirContDone for Writeback and InvalCollectAcks for sharing writebacks * *//* # of hot pages pending */#define MIGREP_PEND 10/* # of hot pages before interrupt */#define MIGREP_PEND_INTR migRepPendIntrint migRepPendIntr = 2;/* value returned when no pages are left */#define MIGREP_NULLPAGE 0xfffffffftypedef struct { unsigned long sampleCounter; /* sample count frequency */ unsigned long pendingPages[MIGREP_PEND]; /* hot pages pending */ unsigned long pendingPagesCount; /* number of hot pending pages */ unsigned char *cmissCounter; /* cache-miss counter, a byte perc CPU per page */ unsigned char *writeCounter; /* write counter, a bit per page */} MigRepNodeInfo;MigRepNodeInfo migRepInfo[NUMA_MAX_MEMORIES]; /* One per memory *//* All variables for resetting counters */unsigned long counterResetInterval; /* Cycles between invocations of the reset routine */unsigned long cmissResetIndex = 0; /* Next cache-miss counter to reset */unsigned long writeResetIndex = 0; /* Next write counter to reset */unsigned long resetWriteCounters; /* countdown for resetting write counters */EventCallbackHdr resetCounterCB; /* periodic call back for resetting counters *//* Policy parameters. Will be eventually set through tcl *//* Sample 1:N */#define SAMPLE_COUNT migRepSampleCountint migRepSampleCount = 10;/* Assuming sampling 1:10 */int migRepTriggerThreshold = 9;#define TRIGGER_THRESHOLD migRepTriggerThreshold/* Reset interval in ms */int migRepResetInterval = 500;#define RESET_INTERVAL migRepResetInterval/* enable counting */int migRepEnableCounting = 0;#define ENABLE_COUNT migRepEnableCounting/* static kern size in pages */int migRepMaxKern = 0;#define MAX_KERN migRepMaxKern/* which node to interrupt */int migRepIntrHot = 0;#define INTR_HOT migRepIntrHotint migRepZeroOnWrite = 0;#define ZERO_ON_WRITE migRepZeroOnWriteint migRep4BitCounters = 0;#define FOUR_BIT_COUNTERS migRep4BitCounters#ifdef SOLO#define NumaAddrToMemnum(_addr) SOLO_PA_NODE(SoloDecompressAddr(0,_addr))#define NumaAddrToMemline(_addr) (SOLO_PA_OFFSET(SoloDecompressAddr(0,_addr))/SCACHE_LINE_SIZE)#else#define NumaAddrToMemnum(_addr) ((_addr/numaStripeSizeBytes)%NUM_MEMORIES(0))#define NumaAddrToMemline(_addr) (((_addr/numaStripeChunk)*numaStripeSizeLines) \ + ((_addr/SCACHE_LINE_SIZE)%numaStripeSizeLines))#endif/* * Memory number that is local to this CPU * This is the same as the CPU, except if clustering (a la DASH)is used */#define NumaLocalMem(c) ((c)*NUM_MEMORIES(0)/NUM_CPUS(0))/* Test if cpu c is local to memory m */#define NumaIsLocal(c, m) ((m) == NumaLocalMem(c))#define NumaMemFirstCPU(m) ((m)*NUM_CPUS(0)/NUM_MEMORIES(0)); /* States for memory and invalidation requests. Helps debugging */enum MemReqState { REQ_LOCAL_WAIT, /* Waiting for the local bus */ REQ_LOCAL_DC_WAIT, /* Waiting for the local DC */ REQ_NET_WAIT, /* Sending to the remote DC */ REQ_REMOTE_DC_WAIT, /* Waiting for the remote DC */ IN_MEM_DC, /* In the DC (not really a wait) */ INVAL_WAIT, /* Waiting for invalidates to be done */ MEM_WAIT, /* Waiting to write to DRAM */ INVAL_LOCAL_WAIT, /* Invalidate: waiting for local bus */ INVAL_NET_WAIT, /* Invalidate: Sending to remote DC */ INVAL_REMOTE_DC_WAIT, /* Invalidate: waiting for remote DC */ INVAL_REMOTE_LOCAL_WAIT, /* Invalidate: waiting for remote bus */ INVAL_ACK_NET_WAIT, /* Invalidate: Sending Ack to home */ INVAL_HOME_DC_WAIT, /* Invalidate: waiting for home DC */ WB_MEM_WAIT, /* Sharing writeback going to memory */ REPLY_NET_WAIT, /* Sending reply to requesting DC */ REPLY_LOCAL_WAIT, /* Sending reply on bus to requesting processor */ REPLY_LOCAL_DC_WAIT, /* Reply waiting for requesting DC */ ALL_DONE };/* A memory request structure */#define MAX_OUTSTANDING (SIM_MAXCPUS*MEMSYS_MAX_OUTSTANDING)typedef struct MemRequest { EventCallbackHdr hdr; /* Must be first!! */ List_Links link; /* Must be second (after EventCallbackhdr */#define MREQ_TO_LIST(_m) (&((_m)->link))#define LIST_TO_MREQ(_l) ((MemRequest *) (((char *)(_l)) - sizeof(EventCallbackHdr))) enum MemReqState state; uint dc_delay_time; /* Fields till here are common with the InvalRequest and should be kept that way */ int cmd; int transId; uint reqAddr; uint addr; /* Address scache aligned */ unsigned int mode; PA replacedPaddr; int replaceWasDirty; int status; int result; int memnum; int machnum; int cpunum; int localMemNum; struct DirState *dirState; uint starttime; byte *data; /* data handling - dma */ int len; int drainNeeded;} MemRequest;static MemRequest MemRequestStorage[MAX_OUTSTANDING];static List_Links freeMemReqList; /* List of available mreq structures *//* * The inval structure must resemble the request structure * for the first few fields, as they are mixed in DC and memory queues */#define MAX_INVALS (MAX_OUTSTANDING*5)typedef struct InvalRequest { EventCallbackHdr hdr; /* Must be first!! */ List_Links link; /* Must be second (after EventCallbackhdr */#define INVAL_TO_LIST(_m) (&((_m)->link))#define LIST_TO_INVAL(_l) ((InvalRequest *) (((char *)(_l)) - sizeof(EventCallbackHdr))) enum MemReqState state; uint dc_delay_time; /* Fields till here are common with the MemRequest and should be kept that way */ int cpu; /* CPU to be invalidated */ MemRequest *mreq; /* The memory request for this invalidate */} InvalRequest;static InvalRequest InvalRequestStorage[MAX_INVALS];static List_Links freeInvalReqList; /* List of available inval structures *//* * Directory state for a memory line. */typedef struct DirState { unsigned char numsharers; /* Number of cpus with line cached. */ unsigned char pending:1; /* 1 if invalidates are pending. */ unsigned char dirty:1; /* Someone has it exclusive */ unsigned char bitmap[(SIM_MAXCPUS+7)/8]; unsigned char acks; /* inval acks pending for this directory line */} DirState;#define STAT_HIST_BUCKETS 100#define DEFAULT_HIST_BUCKET_SCALE 30typedef struct StatsHist { unsigned int scaledivisor; SimCounter sum; SimCounter count; SimCounter counts[STAT_HIST_BUCKETS];} StatsHist;/* * Stats collected per memory system. */typedef struct NumaMemStats { SimCounter counts[COUNT_TOTAL]; StatsHist reqtime; /* latency */} NumaStats;/* Global Info about misses, local and remote home */static NumaStats globalStats[2];/* * State associated with a memory in the system. */typedef struct MemState { List_Links localQueue; /* Queue for the Directory Controller */ List_Links memoryQueue; /* Queue to memory */ NumaStats stats; DirState dirState[1]; /* really NUMA_MAX_BYTES_PER_MEMORY/SCACHE_LINE_SIZE */} MemState;static MemState *memState[NUMA_MAX_MEMORIES];#ifdef SOLO#include "solo_page.h"#define DATA_ADDR(_m, _pa) SoloGetMemoryAddr(SoloDecompressAddr(0,_pa))#else#define DATA_ADDR(_m, _pa) PHYS_TO_MEMADDR(_m, _pa)#endifstatic void DoDCDelay(int num, MemRequest *mreq) ;static void RequestLocal(int cpuNum, EventCallbackHdr *hdr, void *v);static void RequestLocalDC(int num, EventCallbackHdr *hdr, void *v) ;static void RequestNet(int cpuNum, EventCallbackHdr *hdr, void *v) ;static void RequestRemoteDC(int num, EventCallbackHdr *hdr, void *v) ;static void DirContEnter(int num, MemRequest *mreq) ;static void MemContDelay(int num, MemRequest *mreq) ;static void MemContDone(int num, EventCallbackHdr *hdr, void *v) ;static void SharingWBDelay(int num, InvalRequest *lreq);static void SharingWBDone(int num, EventCallbackHdr *hdr, void *v); static void DoInvalidates(MemRequest *mreq) ;static void InvalRequestNet(int num, EventCallbackHdr *hdr, void *v) ;static void InvalRemoteDC(int num, EventCallbackHdr *hdr, void *v) ;static void InvalAckNet(int num, EventCallbackHdr *hdr, void *v) ;static void InvalHomeDC(int num, EventCallbackHdr *hdr, void *v) ;static void InvalCollectAcks(int num, EventCallbackHdr *hdr, void *v) ;static void InvalRemoteAckDone(int num, EventCallbackHdr *hdr, void *v); static void DirContDone(int num, MemRequest *mreq) ;static void ReplyNet(int num, EventCallbackHdr *hdr, void *v);static void ReplyDC(int num, EventCallbackHdr *hdr, void *v);static void SendReplyToCPU(int cpuNum, EventCallbackHdr *hdr, void *v);static void MigRepNumaInit(void);static void MigRepDoWriteCounter(unsigned long addr, int memnum);static void MigRepDoCmissCounter(MemRequest *mreq);static void migRepHotPage(unsigned long localPageNum, int cpunum, int memnum, int localmemnum);uint64 MigRepGetHotPage(int memnum);uint64 MigRepGetInfo(unsigned long addr, int memnum, unsigned long countType, unsigned long countAddr );void MigRepSetInfo(unsigned long addr, int memnum, uint64 val, unsigned long countType, unsigned long countAddr );static void MigRepPeriodic(int cpuNum, EventCallbackHdr *hdr, void *v);void NumaInit(void);Result NumaCmd(int cpuNum, int cmd, PA addr, int transId, PA replacedPaddr, int writeback, byte *data);void NumaDone(void);void NumaDumpStats(void);void NumaStatus(void);void NumaDrain(void);/* Increment a histogram structure */static void StatsIncHist(StatsHist *s, uint value){ uint bucket; if (s->scaledivisor == 0) { bucket = value / DEFAULT_HIST_BUCKET_SCALE; } else { bucket = value / s->scaledivisor; } if (bucket > STAT_HIST_BUCKETS-1) { bucket = STAT_HIST_BUCKETS-1; } s->counts[bucket]++; s->sum += value; s->count++;}/* increment a stat bucket in the memory and local/remote home structures */static voidStatsInc(int bucket, MemRequest *mreq, int i){ MemState *mState = memState[mreq->memnum]; int isLocal = NumaIsLocal(mreq->cpunum, mreq->memnum) ? 1 : 0; mState->stats.counts[bucket] += i; globalStats[isLocal].counts[bucket] += i;}#ifndef SOLO/***************************************************************** * remap region support *****************************************************************/static PA backmapMask;static PA nodeaddrMask;static voidNumaUpdateBackmapMask(void){ /* the backmapMask is an optimization that summarizes all the enabled * remap masks; it has ones in any bit position which, if set, means * this physical address could not be the target of a remap on any * CPU. * * nodeaddrMask masks out the node id bits. */ int i; backmapMask = nodeaddrMask; for (i=0; i<TOTAL_CPUS; i++) { if (remapVec->RemapEnable[i]) { backmapMask &= remapVec->RemapMask[i]; } }}static voidNumaInitRemap(void){ int i; /* We initialize backmapMask to all ones except for the * bits that might be set in the node id field */ nodeaddrMask = ~0; for (i=0; i<TOTAL_CPUS; i++) { if (!remapVec->NodeAddrInitialized) { int m = M_FROM_CPU(i);#ifdef TORNADO remapVec->NodeAddr[i] = (i*NUM_MEMORIES(m)/NUM_CPUS(m)) * (MEM_SIZE(m) / NUM_CPUS(m)); CPUWarning("numa: nodeaddr for %d is %lx\n", i, (unsigned long)(remapVec->NodeAddr[i]));#elif defined(SIM_ORIGIN) remapVec->NodeAddr[i] = MEMADDR_TO_PHYS(m, SIM_MEM_ADDR(m) + (MCPU_FROM_CPU(i)/2) * 2 * (MEM_SIZE(m) / NUM_CPUS(m)));#else remapVec->NodeAddr[i] = MEMADDR_TO_PHYS(m, SIM_MEM_ADDR(m) + i * (MEM_SIZE(m) / NUM_CPUS(m)));#endif } nodeaddrMask &= ~remapVec->NodeAddr[i]; } remapVec->NodeAddrInitialized = 1; /* now zero out the low bits of the backmapmask */ NumaUpdateBackmapMask();}static voidNumaSetRemap(int cpunum, PA mask){ remapVec->RemapMask[cpunum] = mask; NumaUpdateBackmapMask();}static voidNumaControlRemap(int cpunum, int isEnabled){ remapVec->RemapEnable[cpunum] = isEnabled; NumaUpdateBackmapMask();}static PANumaGetNodeAddress(int cpunum){ return remapVec->NodeAddr[cpunum];}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -