void ZArray::initStats(AggregateStat* parentStat) {
    AggregateStat* objStats = new AggregateStat();
    objStats->init("array", "ZArray stats");
    statSwaps.init("swaps", "Block swaps in replacement process");
    objStats->append(&statSwaps);
    parentStat->append(objStats);
}
Exemple #2
0
void ProcStats::update() {
    if (likely(lastUpdatePhase == zinfo->numPhases)) return;
    assert(lastUpdatePhase < zinfo->numPhases);

    uint64_t* endBuf = DumpWalk(coreStats, buf);
    assert(buf + bufSize == endBuf);

    for (uint64_t i = 0; i < bufSize; i++) {
        lastBuf[i] = buf[i] - lastBuf[i];
    }
    std::swap(lastBuf, buf);

    // Now lastBuf has been updated and buf has the differences of all the counters
    uint64_t start = 0;
    for (uint32_t i = 0; i < coreStats->size(); i++) {
        AggregateStat* as = dynamic_cast<AggregateStat*>(coreStats->get(i));

        for (uint32_t c = 0; c < as->size(); c++) {
            AggregateStat* cs = dynamic_cast<AggregateStat*>(as->get(c));
            uint32_t p = zinfo->sched->getScheduledPid(c);
            if (p == (uint32_t)-1) p = zinfo->lineSize - 1;  // FIXME
            else p = zinfo->procArray[p]->getGroupIdx();
            Stat* ps = dynamic_cast<AggregateStat*>(procStats->get(p))->get(i);
            assert(StatSize(cs) == StatSize(ps));
            IncWalk(ps, buf + start);
            start += StatSize(cs);
        }
    }
    assert(start == bufSize);

    lastUpdatePhase = zinfo->numPhases;
}
Exemple #3
0
void DDRMemory::initStats(AggregateStat* parentStat) {
    AggregateStat* memStats = new AggregateStat();
    memStats->init(name.c_str(), "Memory controller stats");
    profReads.init("rd", "Read requests"); memStats->append(&profReads);
    profWrites.init("wr", "Write requests"); memStats->append(&profWrites);
    profTotalRdLat.init("rdlat", "Total latency experienced by read requests"); memStats->append(&profTotalRdLat);
    profTotalWrLat.init("wrlat", "Total latency experienced by write requests"); memStats->append(&profTotalWrLat);
    profReadHits.init("rdhits", "Read row hits"); memStats->append(&profReadHits);
    profWriteHits.init("wrhits", "Write row hits"); memStats->append(&profWriteHits);
    latencyHist.init("mlh", "latency histogram for memory requests", NUMBINS); memStats->append(&latencyHist);
    parentStat->append(memStats);
}
void NVMainMemory::initStats(AggregateStat* parentStat) {
    AggregateStat* memStats = new AggregateStat();
    memStats->init(name.c_str(), "Memory controller stats");
    profIssued.init("issued", "Issued requests"); memStats->append(&profIssued);
    profReads.init("rd", "Read requests"); memStats->append(&profReads);
    profWrites.init("wr", "Write requests"); memStats->append(&profWrites);
    profPUTS.init("PUTS", "Clean Evictions (from lower level)"); memStats->append(&profPUTS);
    profPUTX.init("PUTX", "Dirty Evictions (from lower level)"); memStats->append(&profPUTX);
    profTotalRdLat.init("rdlat", "Total latency experienced by read requests"); memStats->append(&profTotalRdLat);
    profTotalWrLat.init("wrlat", "Total latency experienced by write requests"); memStats->append(&profTotalWrLat);
    profMemoryFootprint.init("footprint", "Total memory footprint in bytes"); memStats->append(&profMemoryFootprint);
    profMemoryAddresses.init("addresses", "Total number of distinct memory addresses"); memStats->append(&profMemoryAddresses);
    latencyHist.init("mlh", "latency histogram for memory requests", NUMBINS); memStats->append(&latencyHist);
    addressReuseHist.init("addressReuse", "address reuse histogram for memory requests", NUMBINS); memStats->append(&addressReuseHist);
    parentStat->append(memStats);
}
Exemple #5
0
AggregateStat* FilterStatsLevel(const AggregateStat* src, const regex& filter, const char* prefix) {
    string base = prefix? (string(prefix) + src->name() + ".") : ""; //if NULL prefix, omit our name (we're root)
    vector<Stat*> children;
    for (uint32_t i = 0; i < src->size(); i++) {
        Stat* child = src->get(i);
        if (AggregateStat* as = dynamic_cast<AggregateStat*>(child)) {
            AggregateStat* fs = FilterStatsLevel(as, filter, base.c_str());
            if (fs) children.push_back(fs);
        } else {
            string name = base + child->name();
            if (regex_match(name, filter)) children.push_back(child);
        }
    }

    if (children.size()) {
        AggregateStat* res = new AggregateStat(src->isRegular());
        res->init(src->name(), src->desc());
        for (Stat* c : children) res->append(c);
        return res;
    } else {
        return NULL;
    }
}
Exemple #6
0
void DRAMSimMemory::initStats(AggregateStat* parentStat) {
    AggregateStat* memStats = new AggregateStat();
    memStats->init(name.c_str(), "Memory controller stats");
    profReads.init("rd", "Read requests"); memStats->append(&profReads);
    profWrites.init("wr", "Write requests"); memStats->append(&profWrites);
    profTotalRdLat.init("rdlat", "Total latency experienced by read requests"); memStats->append(&profTotalRdLat);
    profTotalWrLat.init("wrlat", "Total latency experienced by write requests"); memStats->append(&profTotalWrLat);
    parentStat->append(memStats);
}
Exemple #7
0
Stat* ProcStats::replStat(Stat* s, const char* name, const char* desc) {
    if (!name) name = s->name();
    if (!desc) desc = s->desc();
    if (AggregateStat* as = dynamic_cast<AggregateStat*>(s)) {
        AggregateStat* res = new AggregateStat(as->isRegular());
        res->init(name, desc);
        for (uint32_t i = 0; i < as->size(); i++) {
            res->append(replStat(as->get(i)));
        }
        return res;
    } else if (dynamic_cast<ScalarStat*>(s)) {
        Counter* res = new ProcessCounter(this);
        res->init(name, desc);
        return res;
    } else if (VectorStat* vs = dynamic_cast<VectorStat*>(s)) {
        VectorCounter* res = new ProcessVectorCounter(this);
        assert(!vs->hasCounterNames());  // FIXME: Implement counter name copying
        res->init(name, desc, vs->size());
        return res;
    } else {
        panic("Unrecognized stat type");
        return nullptr;
    }
}
void TimingCache::initStats(AggregateStat* parentStat) {
    AggregateStat* cacheStat = new AggregateStat();
    cacheStat->init(name.c_str(), "Timing cache stats");
    initCacheStats(cacheStat);

    //Stats specific to timing cache
    profOccHist.init("occHist", "Occupancy MSHR cycle histogram", numMSHRs+1);
    cacheStat->append(&profOccHist);

    profHitLat.init("latHit", "Cumulative latency accesses that hit (demand and non-demand)");
    profMissRespLat.init("latMissResp", "Cumulative latency for miss start to response");
    profMissLat.init("latMiss", "Cumulative latency for miss start to finish (free MSHR)");

    cacheStat->append(&profHitLat);
    cacheStat->append(&profMissRespLat);
    cacheStat->append(&profMissLat);

    parentStat->append(cacheStat);
}
Exemple #9
0
void Cache::initStats(AggregateStat* parentStat) {
    AggregateStat* cacheStat = new AggregateStat();
    cacheStat->init(name.c_str(), "Cache stats");
    initCacheStats(cacheStat);
    parentStat->append(cacheStat);
}
Exemple #10
0
ProcStats::ProcStats(AggregateStat* parentStat, AggregateStat* _coreStats) : coreStats(_coreStats) {
    uint32_t maxProcs = zinfo->lineSize;
    lastUpdatePhase = 0;

    // Check that coreStats are appropriate
    assert(coreStats);
    for (uint32_t i = 0; i < coreStats->size(); i++) {
        Stat* s = coreStats->get(i);
        AggregateStat* as = dynamic_cast<AggregateStat*>(s);
        auto err = [s](const char* reason) {
            panic("Stat %s is not per-core (%s)", s->name(), reason);
        };
        if (!as) err("not aggregate stat");
        if (!as->isRegular()) err("irregular aggregate");
        if (as->size() != zinfo->numCores) err("elems != cores");
    }

    // Initialize all the buffers
    bufSize = StatSize(coreStats);
    buf = gm_calloc<uint64_t>(bufSize);
    lastBuf = gm_calloc<uint64_t>(bufSize);

    // Create the procStats
    procStats = new AggregateStat(true);
    procStats->init("procStats", "Per-process stats");
    for (uint32_t p = 0; p < maxProcs; p++) {
        AggregateStat* ps = new AggregateStat(false);
        const char* name = gm_strdup(("procStats-" + Str(p)).c_str());
        ps->init(name, "Per-process stats");
        for (uint32_t i = 0; i < coreStats->size(); i++) {
            AggregateStat* as = dynamic_cast<AggregateStat*>(coreStats->get(i));
            assert(as && as->isRegular());
            ps->append(replStat(as->get(0), as->name(), as->desc()));
        }
        procStats->append(ps);
    }
    parentStat->append(procStats);
}
Exemple #11
0
void SimInit(const char* configFile, const char* outputDir, uint32_t shmid) {
    zinfo = gm_calloc<GlobSimInfo>();
    zinfo->outputDir = gm_strdup(outputDir);

    Config config(configFile);

    //Debugging
    //NOTE: This should be as early as possible, so that we can attach to the debugger before initialization.
    zinfo->attachDebugger = config.get<bool>("sim.attachDebugger", false);
    zinfo->harnessPid = getppid();
    getLibzsimAddrs(&zinfo->libzsimAddrs);

    if (zinfo->attachDebugger) {
        gm_set_secondary_ptr(&zinfo->libzsimAddrs);
        notifyHarnessForDebugger(zinfo->harnessPid);
    }

    PreInitStats();

    //Get the number of cores
    //TODO: There is some duplication with the core creation code. This should be fixed eventually.
    uint32_t numCores = 0;
    vector<const char*> groups;
    config.subgroups("sys.cores", groups);
    for (const char* group : groups) {
        uint32_t cores = config.get<uint32_t>(string("sys.cores.") + group + ".cores", 1);
        numCores += cores;
    }

    if (numCores == 0) panic("Config must define some core classes in sys.cores; sys.numCores is deprecated");
    zinfo->numCores = numCores;
    assert(numCores <= MAX_THREADS); //TODO: Is there any reason for this limit?

    zinfo->numDomains = config.get<uint32_t>("sim.domains", 1);
    uint32_t numSimThreads = config.get<uint32_t>("sim.contentionThreads", MAX((uint32_t)1, zinfo->numDomains/2)); //gives a bit of parallelism, TODO tune
    zinfo->contentionSim = new ContentionSim(zinfo->numDomains, numSimThreads);
    zinfo->contentionSim->initStats(zinfo->rootStat);
    zinfo->eventRecorders = gm_calloc<EventRecorder*>(numCores);

    // Global simulation values
    zinfo->numPhases = 0;

    zinfo->phaseLength = config.get<uint32_t>("sim.phaseLength", 10000);
    zinfo->statsPhaseInterval = config.get<uint32_t>("sim.statsPhaseInterval", 100);
    zinfo->freqMHz = config.get<uint32_t>("sys.frequency", 2000);

    //Maxima/termination conditions
    zinfo->maxPhases = config.get<uint64_t>("sim.maxPhases", 0);
    zinfo->maxMinInstrs = config.get<uint64_t>("sim.maxMinInstrs", 0);
    zinfo->maxTotalInstrs = config.get<uint64_t>("sim.maxTotalInstrs", 0);

    uint64_t maxSimTime = config.get<uint32_t>("sim.maxSimTime", 0);
    zinfo->maxSimTimeNs = maxSimTime*1000L*1000L*1000L;

    zinfo->maxProcEventualDumps = config.get<uint32_t>("sim.maxProcEventualDumps", 0);
    zinfo->procEventualDumps = 0;

    zinfo->skipStatsVectors = config.get<bool>("sim.skipStatsVectors", false);
    zinfo->compactPeriodicStats = config.get<bool>("sim.compactPeriodicStats", false);

    //Fast-forwarding and magic ops
    zinfo->ignoreHooks = config.get<bool>("sim.ignoreHooks", false);
    zinfo->ffReinstrument = config.get<bool>("sim.ffReinstrument", false);
    if (zinfo->ffReinstrument) warn("sim.ffReinstrument = true, switching fast-forwarding on a multi-threaded process may be unstable");

    zinfo->registerThreads = config.get<bool>("sim.registerThreads", false);
    zinfo->globalPauseFlag = config.get<bool>("sim.startInGlobalPause", false);

    zinfo->eventQueue = new EventQueue(); //must be instantiated before the memory hierarchy

    //Build the scheduler
    uint32_t parallelism = config.get<uint32_t>("sim.parallelism", 2*sysconf(_SC_NPROCESSORS_ONLN));
    if (parallelism < zinfo->numCores) info("Limiting concurrent threads to %d", parallelism);
    assert(parallelism > 0); //jeez...

    uint32_t schedQuantum = config.get<uint32_t>("sim.schedQuantum", 10000); //phases
    zinfo->sched = new Scheduler(EndOfPhaseActions, parallelism, zinfo->numCores, schedQuantum);

    zinfo->blockingSyscalls = config.get<bool>("sim.blockingSyscalls", false);

    if (zinfo->blockingSyscalls) {
        warn("sim.blockingSyscalls = True, will likely deadlock with multi-threaded apps!");
    }

    InitGlobalStats();

    //Core stats (initialized here for cosmetic reasons, to be above cache stats)
    AggregateStat* allCoreStats = new AggregateStat(false);
    allCoreStats->init("core", "Core stats");
    zinfo->rootStat->append(allCoreStats);

    //Process tree needs this initialized, even though it is part of the memory hierarchy
    zinfo->lineSize = config.get<uint32_t>("sys.lineSize", 64);
    assert(zinfo->lineSize > 0);

    //Address randomization
    zinfo->addressRandomization = config.get<bool>("sys.addressRandomization", false);

    //Port virtualization
    for (uint32_t i = 0; i < MAX_PORT_DOMAINS; i++) zinfo->portVirt[i] = new PortVirtualizer();

    //Process hierarchy
    //NOTE: Due to partitioning, must be done before initializing memory hierarchy
    CreateProcessTree(config);
    zinfo->procArray[0]->notifyStart(); //called here so that we can detect end-before-start races

    zinfo->pinCmd = new PinCmd(&config, NULL /*don't pass config file to children --- can go either way, it's optional*/, outputDir, shmid);

    //Caches, cores, memory controllers
    InitSystem(config);

    //Sched stats (deferred because of circular deps)
    zinfo->sched->initStats(zinfo->rootStat);

    zinfo->processStats = new ProcessStats(zinfo->rootStat);

    //It's a global stat, but I want it to be last...
    zinfo->profHeartbeats = new VectorCounter();
    zinfo->profHeartbeats->init("heartbeats", "Per-process heartbeats", zinfo->lineSize);
    zinfo->rootStat->append(zinfo->profHeartbeats);

    bool perProcessDir = config.get<bool>("sim.perProcessDir", false);
    PostInitStats(perProcessDir, config);

    zinfo->perProcessCpuEnum = config.get<bool>("sim.perProcessCpuEnum", false);

    //Odds and ends
    bool printMemoryStats = config.get<bool>("sim.printMemoryStats", false);
    if (printMemoryStats) {
        gm_stats();
    }

    //HACK: Read all variables that are read in the harness but not in init
    //This avoids warnings on those elements
    config.get<uint32_t>("sim.gmMBytes", (1 << 10));
    if (!zinfo->attachDebugger) config.get<bool>("sim.deadlockDetection", true);
    config.get<bool>("sim.aslr", false);

    //Write config out
    bool strictConfig = config.get<bool>("sim.strictConfig", true); //if true, panic on unused variables
    config.writeAndClose((string(zinfo->outputDir) + "/out.cfg").c_str(), strictConfig);

    zinfo->contentionSim->postInit();

    info("Initialization complete");

    //Causes every other process to wake up
    gm_set_glob_ptr(zinfo);
}
Exemple #12
0
static void InitSystem(Config& config) {
    unordered_map<string, string> parentMap; //child -> parent
    unordered_map<string, vector<string>> childMap; //parent -> children (a parent may have multiple children, they are ordered by appearance in the file)

    //If a network file is specificied, build a Network
    string networkFile = config.get<const char*>("sys.networkFile", "");
    Network* network = (networkFile != "")? new Network(networkFile.c_str()) : NULL;

    //Build the caches
    vector<const char*> cacheGroupNames;
    config.subgroups("sys.caches", cacheGroupNames);
    string prefix = "sys.caches.";

    for (const char* grp : cacheGroupNames) {
        string group(grp);
        if (group == "mem") panic("'mem' is an invalid cache group name");
        if (parentMap.count(group)) panic("Duplicate cache group %s", (prefix + group).c_str());
        string parent = config.get<const char*>(prefix + group + ".parent");
        parentMap[group] = parent;
        if (!childMap.count(parent)) childMap[parent] = vector<string>();
        childMap[parent].push_back(group);
    }

    //Check that all parents are valid: Either another cache, or "mem"
    for (const char* grp : cacheGroupNames) {
        string group(grp);
        string parent = parentMap[group];
        if (parent != "mem" && !parentMap.count(parent)) panic("%s has invalid parent %s", (prefix + group).c_str(), parent.c_str());
    }

    //Get the (single) LLC
    if (!childMap.count("mem")) panic("One cache must have mem as parent, none found");
    if (childMap["mem"].size() != 1) panic("One cache must have mem as parent, multiple found");
    string llc = childMap["mem"][0];

    //Build each of the groups, starting with the LLC
    unordered_map<string, CacheGroup*> cMap;
    list<string> fringe; //FIFO
    fringe.push_back(llc);
    while (!fringe.empty()) {
        string group = fringe.front();
        fringe.pop_front();

        bool isTerminal = (childMap.count(group) == 0); //if no children, connected to cores
        if (cMap.count(group)) panic("The cache 'tree' has a loop at %s", group.c_str());
        cMap[group] = BuildCacheGroup(config, group, isTerminal);
        if (!isTerminal) for (string child : childMap[group]) fringe.push_back(child);
    }

    //Check single LLC
    if (cMap[llc]->size() != 1) panic("Last-level cache %s must have caches = 1, but %ld were specified", llc.c_str(), cMap[llc]->size());

    /* Since we have checked for no loops, parent is mandatory, and all parents are checked valid,
     * it follows that we have a fully connected tree finishing at the LLC.
     */

    //Build the memory controllers
    uint32_t memControllers = config.get<uint32_t>("sys.mem.controllers", 1);
    assert(memControllers > 0);

    g_vector<MemObject*> mems;
    mems.resize(memControllers);
    zinfo->numMemoryControllers = memControllers;
    zinfo->hasNVMain = (config.get<const char*>("sys.mem.type", "Simple") == string("NVMain")) ? true : false;
    zinfo->hasDRAMCache = config.get<bool>("sys.mem.hasDRAMCache", false);

    for (uint32_t i = 0; i < memControllers; i++) {
        stringstream ss;
        ss << "mem-" << i;
        g_string name(ss.str().c_str());
        //uint32_t domain = nextDomain(); //i*zinfo->numDomains/memControllers;
        uint32_t domain = i*zinfo->numDomains/memControllers;
        mems[i] = BuildMemoryController(config, zinfo->lineSize, zinfo->freqMHz, domain, name);
    }

    zinfo->memoryControllers = mems;

    if (memControllers > 1) {
        bool splitAddrs = config.get<bool>("sys.mem.splitAddrs", true);
        if (splitAddrs) {
            MemObject* splitter = new SplitAddrMemory(mems, "mem-splitter");
            mems.resize(1);
            mems[0] = splitter;
        }
    }

    //Connect everything

    // mem to llc is a bit special, only one llc
    uint32_t childId = 0;
    for (BaseCache* llcBank : (*cMap[llc])[0]) {
        llcBank->setParents(childId++, mems, network);
    }

    // Rest of caches
    for (const char* grp : cacheGroupNames) {
        if (childMap.count(grp) == 0) continue; //skip terminal caches

        CacheGroup& parentCaches = *cMap[grp];
        uint32_t parents = parentCaches.size();
        assert(parents);

        //Concatenation of all child caches
        CacheGroup childCaches;
        for (string child : childMap[grp]) childCaches.insert(childCaches.end(), cMap[child]->begin(), cMap[child]->end());

        uint32_t children = childCaches.size();
        assert(children);

        uint32_t childrenPerParent = children/parents;
        if (children % parents != 0) {
            panic("%s has %d caches and %d children, they are non-divisible. "
                    "Use multiple groups for non-homogeneous children per parent!", grp, parents, children);
        }

        //HACK FIXME: This solves the L1I+D-L2 connection bug, but it's not very clear.
        //A long-term solution is to specify whether the children should be interleaved or concatenated.
        bool terminalChildren = true;
        for (string child : childMap[grp]) terminalChildren &= (childMap.count(child) == 0 || config.get<bool>("sys.caches." + child + ".isPrefetcher", false));
        if (terminalChildren) {
            info("%s's children are all terminal OR PREFETCHERS, interleaving them", grp);
            CacheGroup tmp(childCaches);
            uint32_t stride = children/childrenPerParent;
            for (uint32_t i = 0; i < children; i++) childCaches[i] = tmp[(i % childrenPerParent)*stride + i/childrenPerParent];
        }

        for (uint32_t p = 0; p < parents; p++) {
            g_vector<MemObject*> parentsVec;
            parentsVec.insert(parentsVec.end(), parentCaches[p].begin(), parentCaches[p].end()); //BaseCache* to MemObject* is a safe cast

            uint32_t childId = 0;
            g_vector<BaseCache*> childrenVec;
            for (uint32_t c = p*childrenPerParent; c < (p+1)*childrenPerParent; c++) {
                for (BaseCache* bank : childCaches[c]) {
                    bank->setParents(childId++, parentsVec, network);
                    childrenVec.push_back(bank);
                }
            }

            for (BaseCache* bank : parentCaches[p]) {
                bank->setChildren(childrenVec, network);
            }
        }
    }

    //Check that all the terminal caches have a single bank
    for (const char* grp : cacheGroupNames) {
        if (childMap.count(grp) == 0) {
            uint32_t banks = (*cMap[grp])[0].size();
            if (banks != 1) panic("Terminal cache group %s needs to have a single bank, has %d", grp, banks);
        }
    }

    //Tracks how many terminal caches have been allocated to cores
    unordered_map<string, uint32_t> assignedCaches;
    for (const char* grp : cacheGroupNames) if (childMap.count(grp) == 0) assignedCaches[grp] = 0;

    //Instantiate the cores
    vector<const char*> coreGroupNames;
    unordered_map <string, vector<Core*>> coreMap;

    config.subgroups("sys.cores", coreGroupNames);

    uint32_t coreIdx = 0;
    for (const char* group : coreGroupNames) {
        if (parentMap.count(group)) panic("Core group name %s is invalid, a cache group already has that name", group);

        coreMap[group] = vector<Core*>();

        string prefix = string("sys.cores.") + group + ".";
        uint32_t cores = config.get<uint32_t>(prefix + "cores", 1);
        string type = config.get<const char*>(prefix + "type", "Simple");

        //Build the core group
        union {
            SimpleCore* simpleCores;
            TimingCore* timingCores;
            OOOCore* oooCores;
            NullCore* nullCores;
        };
        if (type == "Simple") {
            simpleCores = gm_memalign<SimpleCore>(CACHE_LINE_BYTES, cores);
        } else if (type == "Timing") {
            timingCores = gm_memalign<TimingCore>(CACHE_LINE_BYTES, cores);
        } else if (type == "OOO") {
            oooCores = gm_memalign<OOOCore>(CACHE_LINE_BYTES, cores);
            zinfo->oooDecode = true; //enable uop decoding, this is false by default, must be true if even one OOO cpu is in the system
        } else if (type == "Null") {
            nullCores = gm_memalign<NullCore>(CACHE_LINE_BYTES, cores);
        } else {
            panic("%s: Invalid core type %s", group, type.c_str());
        }

        if (type != "Null") {
            string icache = config.get<const char*>(prefix + "icache");
            string dcache = config.get<const char*>(prefix + "dcache");

            if (!assignedCaches.count(icache)) panic("%s: Invalid icache parameter %s", group, icache.c_str());
            if (!assignedCaches.count(dcache)) panic("%s: Invalid dcache parameter %s", group, dcache.c_str());

            for (uint32_t j = 0; j < cores; j++) {
                stringstream ss;
                ss << group << "-" << j;
                g_string name(ss.str().c_str());
                Core* core;

                //Get the caches
                CacheGroup& igroup = *cMap[icache];
                CacheGroup& dgroup = *cMap[dcache];

                if (assignedCaches[icache] >= igroup.size()) {
                    panic("%s: icache group %s (%ld caches) is fully used, can't connect more cores to it", name.c_str(), icache.c_str(), igroup.size());
                }
                FilterCache* ic = dynamic_cast<FilterCache*>(igroup[assignedCaches[icache]][0]);
                assert(ic);
                ic->setSourceId(coreIdx);
                ic->setFlags(MemReq::IFETCH | MemReq::NOEXCL);
                assignedCaches[icache]++;

                if (assignedCaches[dcache] >= dgroup.size()) {
                    panic("%s: dcache group %s (%ld caches) is fully used, can't connect more cores to it", name.c_str(), dcache.c_str(), dgroup.size());
                }
                FilterCache* dc = dynamic_cast<FilterCache*>(dgroup[assignedCaches[dcache]][0]);
                assert(dc);
                dc->setSourceId(coreIdx);
                assignedCaches[dcache]++;

                //Build the core
                if (type == "Simple") {
                    core = new (&simpleCores[j]) SimpleCore(ic, dc, name);
                } else if (type == "Timing") {
                    uint32_t domain = j*zinfo->numDomains/cores;
                    TimingCore* tcore = new (&timingCores[j]) TimingCore(ic, dc, domain, name);
                    zinfo->eventRecorders[coreIdx] = tcore->getEventRecorder();
                    zinfo->eventRecorders[coreIdx]->setSourceId(coreIdx);
                    core = tcore;
                } else {
                    assert(type == "OOO");
                    OOOCore* ocore = new (&oooCores[j]) OOOCore(ic, dc, name, j);
                    zinfo->eventRecorders[coreIdx] = ocore->getEventRecorder();
                    zinfo->eventRecorders[coreIdx]->setSourceId(coreIdx);
                    core = ocore;
                }
                coreMap[group].push_back(core);
                coreIdx++;
            }
        } else {
            assert(type == "Null");
            for (uint32_t j = 0; j < cores; j++) {
                stringstream ss;
                ss << group << "-" << j;
                g_string name(ss.str().c_str());
                Core* core = new (&nullCores[j]) NullCore(name);
                coreMap[group].push_back(core);
                coreIdx++;
            }
        }
    }

    //Check that all the terminal caches are fully connected
    for (const char* grp : cacheGroupNames) {
        if (childMap.count(grp) == 0 && assignedCaches[grp] != cMap[grp]->size()) {
            panic("%s: Terminal cache group not fully connected, %ld caches, %d assigned", grp, cMap[grp]->size(), assignedCaches[grp]);
        }
    }

    //Populate global core info
    assert(zinfo->numCores == coreIdx);
    zinfo->cores = gm_memalign<Core*>(CACHE_LINE_BYTES, zinfo->numCores);
    coreIdx = 0;
    for (const char* group : coreGroupNames) for (Core* core : coreMap[group]) zinfo->cores[coreIdx++] = core;

    //Init stats: cores, caches, mem
    for (const char* group : coreGroupNames) {
        AggregateStat* groupStat = new AggregateStat(true);
        groupStat->init(gm_strdup(group), "Core stats");
        for (Core* core : coreMap[group]) core->initStats(groupStat);
        zinfo->rootStat->append(groupStat);
    }

    for (const char* group : cacheGroupNames) {
        AggregateStat* groupStat = new AggregateStat(true);
        groupStat->init(gm_strdup(group), "Cache stats");
        for (vector<BaseCache*>& banks : *cMap[group]) for (BaseCache* bank : banks) bank->initStats(groupStat);
        zinfo->rootStat->append(groupStat);
    }

    //Initialize event recorders
    //for (uint32_t i = 0; i < zinfo->numCores; i++) eventRecorders[i] = new EventRecorder();

    AggregateStat* memStat = new AggregateStat(true);
    memStat->init("mem", "Memory controller stats");
    for (auto mem : mems) mem->initStats(memStat);
    zinfo->rootStat->append(memStat);

    //Odds and ends: BuildCacheGroup new'd the cache groups, we need to delete them
    for (pair<string, CacheGroup*> kv : cMap) delete kv.second;
    cMap.clear();

    info("Initialized system");
}
Exemple #13
0
AggregateStat* FilterStats(const AggregateStat* rootStat, const char* regexStr) {
    regex filter(regexStr);
    AggregateStat* res = FilterStatsLevel(rootStat, filter, NULL /*root*/);
    if (res) res->makeImmutable();
    return res;
}