inst_queue_impl.hh
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· HH 代码 · 共 1,409 行 · 第 1/3 页
HH
1,409 行
/* * Copyright (c) 2004, 2005, 2006 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. * * Authors: Kevin T. Lim * Korey L. Sewell */#include <limits>#include <vector>#include "cpu/o3/fu_pool.hh"#include "cpu/o3/inst_queue.hh"#include "enums/OpClass.hh"#include "sim/core.hh"template <class Impl>InstructionQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst, int fu_idx, InstructionQueue<Impl> *iq_ptr) : Event(&mainEventQueue, Stat_Event_Pri), inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), freeFU(false){ this->setFlags(Event::AutoDelete);}template <class Impl>voidInstructionQueue<Impl>::FUCompletion::process(){ iqPtr->processFUCompletion(inst, freeFU ? fuIdx : -1); inst = NULL;}template <class Impl>const char *InstructionQueue<Impl>::FUCompletion::description() const{ return "Functional unit completion";}template <class Impl>InstructionQueue<Impl>::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params) : cpu(cpu_ptr), iewStage(iew_ptr), fuPool(params->fuPool), numEntries(params->numIQEntries), totalWidth(params->issueWidth), numPhysIntRegs(params->numPhysIntRegs), numPhysFloatRegs(params->numPhysFloatRegs), commitToIEWDelay(params->commitToIEWDelay){ assert(fuPool); switchedOut = false; numThreads = params->numberOfThreads; // Set the number of physical registers as the number of int + float numPhysRegs = numPhysIntRegs + numPhysFloatRegs; //Create an entry for each physical register within the //dependency graph. dependGraph.resize(numPhysRegs); // Resize the register scoreboard. regScoreboard.resize(numPhysRegs); //Initialize Mem Dependence Units for (int i = 0; i < numThreads; i++) { memDepUnit[i].init(params,i); memDepUnit[i].setIQ(this); } resetState(); std::string policy = params->smtIQPolicy; //Convert string to lowercase std::transform(policy.begin(), policy.end(), policy.begin(), (int(*)(int)) tolower); //Figure out resource sharing policy if (policy == "dynamic") { iqPolicy = Dynamic; //Set Max Entries to Total ROB Capacity for (int i = 0; i < numThreads; i++) { maxEntries[i] = numEntries; } } else if (policy == "partitioned") { iqPolicy = Partitioned; //@todo:make work if part_amt doesnt divide evenly. int part_amt = numEntries / numThreads; //Divide ROB up evenly for (int i = 0; i < numThreads; i++) { maxEntries[i] = part_amt; } DPRINTF(IQ, "IQ sharing policy set to Partitioned:" "%i entries per thread.\n",part_amt); } else if (policy == "threshold") { iqPolicy = Threshold; double threshold = (double)params->smtIQThreshold / 100; int thresholdIQ = (int)((double)threshold * numEntries); //Divide up by threshold amount for (int i = 0; i < numThreads; i++) { maxEntries[i] = thresholdIQ; } DPRINTF(IQ, "IQ sharing policy set to Threshold:" "%i entries per thread.\n",thresholdIQ); } else { assert(0 && "Invalid IQ Sharing Policy.Options Are:{Dynamic," "Partitioned, Threshold}"); }}template <class Impl>InstructionQueue<Impl>::~InstructionQueue(){ dependGraph.reset();#ifdef DEBUG cprintf("Nodes traversed: %i, removed: %i\n", dependGraph.nodesTraversed, dependGraph.nodesRemoved);#endif}template <class Impl>std::stringInstructionQueue<Impl>::name() const{ return cpu->name() + ".iq";}template <class Impl>voidInstructionQueue<Impl>::regStats(){ using namespace Stats; iqInstsAdded .name(name() + ".iqInstsAdded") .desc("Number of instructions added to the IQ (excludes non-spec)") .prereq(iqInstsAdded); iqNonSpecInstsAdded .name(name() + ".iqNonSpecInstsAdded") .desc("Number of non-speculative instructions added to the IQ") .prereq(iqNonSpecInstsAdded); iqInstsIssued .name(name() + ".iqInstsIssued") .desc("Number of instructions issued") .prereq(iqInstsIssued); iqIntInstsIssued .name(name() + ".iqIntInstsIssued") .desc("Number of integer instructions issued") .prereq(iqIntInstsIssued); iqFloatInstsIssued .name(name() + ".iqFloatInstsIssued") .desc("Number of float instructions issued") .prereq(iqFloatInstsIssued); iqBranchInstsIssued .name(name() + ".iqBranchInstsIssued") .desc("Number of branch instructions issued") .prereq(iqBranchInstsIssued); iqMemInstsIssued .name(name() + ".iqMemInstsIssued") .desc("Number of memory instructions issued") .prereq(iqMemInstsIssued); iqMiscInstsIssued .name(name() + ".iqMiscInstsIssued") .desc("Number of miscellaneous instructions issued") .prereq(iqMiscInstsIssued); iqSquashedInstsIssued .name(name() + ".iqSquashedInstsIssued") .desc("Number of squashed instructions issued") .prereq(iqSquashedInstsIssued); iqSquashedInstsExamined .name(name() + ".iqSquashedInstsExamined") .desc("Number of squashed instructions iterated over during squash;" " mainly for profiling") .prereq(iqSquashedInstsExamined); iqSquashedOperandsExamined .name(name() + ".iqSquashedOperandsExamined") .desc("Number of squashed operands that are examined and possibly " "removed from graph") .prereq(iqSquashedOperandsExamined); iqSquashedNonSpecRemoved .name(name() + ".iqSquashedNonSpecRemoved") .desc("Number of squashed non-spec instructions that were removed") .prereq(iqSquashedNonSpecRemoved);/* queueResDist .init(Num_OpClasses, 0, 99, 2) .name(name() + ".IQ:residence:") .desc("cycles from dispatch to issue") .flags(total | pdf | cdf ) ; for (int i = 0; i < Num_OpClasses; ++i) { queueResDist.subname(i, opClassStrings[i]); }*/ numIssuedDist .init(0,totalWidth,1) .name(name() + ".ISSUE:issued_per_cycle") .desc("Number of insts issued each cycle") .flags(pdf) ;/* dist_unissued .init(Num_OpClasses+2) .name(name() + ".ISSUE:unissued_cause") .desc("Reason ready instruction not issued") .flags(pdf | dist) ; for (int i=0; i < (Num_OpClasses + 2); ++i) { dist_unissued.subname(i, unissued_names[i]); }*/ statIssuedInstType .init(numThreads,Enums::Num_OpClass) .name(name() + ".ISSUE:FU_type") .desc("Type of FU issued") .flags(total | pdf | dist) ; statIssuedInstType.ysubnames(Enums::OpClassStrings); // // How long did instructions for a particular FU type wait prior to issue ///* issueDelayDist .init(Num_OpClasses,0,99,2) .name(name() + ".ISSUE:") .desc("cycles from operands ready to issue") .flags(pdf | cdf) ; for (int i=0; i<Num_OpClasses; ++i) { std::stringstream subname; subname << opClassStrings[i] << "_delay"; issueDelayDist.subname(i, subname.str()); }*/ issueRate .name(name() + ".ISSUE:rate") .desc("Inst issue rate") .flags(total) ; issueRate = iqInstsIssued / cpu->numCycles; statFuBusy .init(Num_OpClasses) .name(name() + ".ISSUE:fu_full") .desc("attempts to use FU when none available") .flags(pdf | dist) ; for (int i=0; i < Num_OpClasses; ++i) { statFuBusy.subname(i, Enums::OpClassStrings[i]); } fuBusy .init(numThreads) .name(name() + ".ISSUE:fu_busy_cnt") .desc("FU busy when requested") .flags(total) ; fuBusyRate .name(name() + ".ISSUE:fu_busy_rate") .desc("FU busy rate (busy events/executed inst)") .flags(total) ; fuBusyRate = fuBusy / iqInstsIssued; for ( int i=0; i < numThreads; i++) { // Tell mem dependence unit to reg stats as well. memDepUnit[i].regStats(); }}template <class Impl>voidInstructionQueue<Impl>::resetState(){ //Initialize thread IQ counts for (int i = 0; i <numThreads; i++) { count[i] = 0; instList[i].clear(); } // Initialize the number of free IQ entries. freeEntries = numEntries; // Note that in actuality, the registers corresponding to the logical // registers start off as ready. However this doesn't matter for the // IQ as the instruction should have been correctly told if those // registers are ready in rename. Thus it can all be initialized as // unready. for (int i = 0; i < numPhysRegs; ++i) { regScoreboard[i] = false; } for (int i = 0; i < numThreads; ++i) { squashedSeqNum[i] = 0; } for (int i = 0; i < Num_OpClasses; ++i) { while (!readyInsts[i].empty()) readyInsts[i].pop(); queueOnList[i] = false; readyIt[i] = listOrder.end(); } nonSpecInsts.clear(); listOrder.clear();}template <class Impl>voidInstructionQueue<Impl>::setActiveThreads(std::list<unsigned> *at_ptr){ activeThreads = at_ptr;}template <class Impl>voidInstructionQueue<Impl>::setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2e_ptr){ issueToExecuteQueue = i2e_ptr;}template <class Impl>voidInstructionQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr){ timeBuffer = tb_ptr; fromCommit = timeBuffer->getWire(-commitToIEWDelay);}template <class Impl>voidInstructionQueue<Impl>::switchOut(){/* if (!instList[0].empty() || (numEntries != freeEntries) || !readyInsts[0].empty() || !nonSpecInsts.empty() || !listOrder.empty()) { dumpInsts();// assert(0); }*/ resetState(); dependGraph.reset(); instsToExecute.clear(); switchedOut = true; for (int i = 0; i < numThreads; ++i) { memDepUnit[i].switchOut(); }}template <class Impl>voidInstructionQueue<Impl>::takeOverFrom(){ switchedOut = false;}template <class Impl>intInstructionQueue<Impl>::entryAmount(int num_threads){ if (iqPolicy == Partitioned) { return numEntries / num_threads; } else { return 0; }}template <class Impl>voidInstructionQueue<Impl>::resetEntries(){ if (iqPolicy != Dynamic || numThreads > 1) { int active_threads = activeThreads->size(); std::list<unsigned>::iterator threads = activeThreads->begin(); std::list<unsigned>::iterator end = activeThreads->end(); while (threads != end) { unsigned tid = *threads++; if (iqPolicy == Partitioned) { maxEntries[tid] = numEntries / active_threads; } else if(iqPolicy == Threshold && active_threads == 1) { maxEntries[tid] = numEntries; } } }}template <class Impl>unsignedInstructionQueue<Impl>::numFreeEntries(){ return freeEntries;}template <class Impl>unsignedInstructionQueue<Impl>::numFreeEntries(unsigned tid){ return maxEntries[tid] - count[tid];}// Might want to do something more complex if it knows how many instructions// will be issued this cycle.template <class Impl>boolInstructionQueue<Impl>::isFull(){ if (freeEntries == 0) { return(true); } else { return(false); }}template <class Impl>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?