inorder: utilize cached skeds in pipeline

allow the pipeline and resources to use the cached instruction schedule and resource
sked iterator
This commit is contained in:
Korey Sewell 2011-02-12 10:14:45 -05:00
parent 516b611462
commit e26aee514d
17 changed files with 188 additions and 89 deletions

View file

@ -55,7 +55,7 @@ if 'InOrderCPU' in env['CPU_MODELS']:
TraceFlag('ThreadModel')
TraceFlag('RefCount')
TraceFlag('AddrDep')
TraceFlag('SkedCache')
CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU',
'InOrderMDU', 'InOrderAGEN', 'InOrderFetchSeq', 'InOrderTLB', 'InOrderBPred',

View file

@ -368,7 +368,7 @@ std::map<InOrderCPU::SkedID, ThePipeline::RSkedPtr> InOrderCPU::skedCache;
RSkedPtr
InOrderCPU::createFrontEndSked()
{
RSkedPtr res_sked = NULL;
RSkedPtr res_sked = new ResourceSked();
int stage_num = 0;
StageScheduler F(res_sked, stage_num++);
StageScheduler D(res_sked, stage_num++);
@ -383,6 +383,9 @@ InOrderCPU::createFrontEndSked()
D.needs(BPred, BranchPredictor::PredictBranch);
D.needs(FetchSeq, FetchSeqUnit::UpdateTargetPC);
DPRINTF(SkedCache, "Resource Sked created for instruction \"front_end\"\n");
return res_sked;
}
@ -391,7 +394,11 @@ InOrderCPU::createBackEndSked(DynInstPtr inst)
{
RSkedPtr res_sked = lookupSked(inst);
if (res_sked != NULL) {
DPRINTF(SkedCache, "Found %s in sked cache.\n",
inst->instName());
return res_sked;
} else {
res_sked = new ResourceSked();
}
int stage_num = ThePipeline::BackEndStartStage;
@ -402,7 +409,7 @@ InOrderCPU::createBackEndSked(DynInstPtr inst)
if (!inst->staticInst) {
warn_once("Static Instruction Object Not Set. Can't Create"
" Back End Schedule");
return false;
return NULL;
}
// EXECUTE
@ -458,6 +465,14 @@ InOrderCPU::createBackEndSked(DynInstPtr inst)
W.needs(Grad, GraduationUnit::GraduateInst);
// Insert Front Schedule into our cache of
// resource schedules
addToSkedCache(inst, res_sked);
DPRINTF(SkedCache, "Back End Sked Created for instruction: %s (%08p)\n",
inst->instName(), inst->getMachInst());
res_sked->print();
return res_sked;
}

View file

@ -181,7 +181,7 @@ FirstStage::processInsts(ThreadID tid)
inst->setInstListIt(cpu->addInst(inst));
// Create Front-End Resource Schedule For Instruction
ThePipeline::createFrontEndSchedule(inst);
inst->setFrontSked(cpu->frontEndSked);
}
int reqs_processed = 0;

View file

@ -51,7 +51,7 @@ InOrderDynInst::InOrderDynInst(TheISA::ExtMachInst machInst,
const TheISA::PCState &instPC,
const TheISA::PCState &_predPC,
InstSeqNum seq_num, InOrderCPU *cpu)
: staticInst(machInst, instPC.instAddr()), traceData(NULL), cpu(cpu)
: staticInst(machInst, instPC.instAddr()), traceData(NULL), cpu(cpu)
{
seqNum = seq_num;
@ -108,6 +108,8 @@ InOrderDynInst::setMachInst(ExtMachInst machInst)
void
InOrderDynInst::initVars()
{
inFrontEnd = true;
fetchMemReq = NULL;
dataMemReq = NULL;
splitMemData = NULL;

View file

@ -337,9 +337,10 @@ class InOrderDynInst : public FastAlloc, public RefCounted
////////////////////////////////////////////////////////////
std::string instName() { return staticInst->getName(); }
void setMachInst(ExtMachInst inst);
ExtMachInst getMachInst() { return staticInst->machInst; }
/** Sets the StaticInst. */
void setStaticInst(StaticInstPtr &static_inst);
@ -411,6 +412,39 @@ class InOrderDynInst : public FastAlloc, public RefCounted
// RESOURCE SCHEDULING
//
/////////////////////////////////////////////
typedef ThePipeline::RSkedPtr RSkedPtr;
bool inFrontEnd;
RSkedPtr frontSked;
RSkedIt frontSked_end;
RSkedPtr backSked;
RSkedIt backSked_end;
RSkedIt curSkedEntry;
void setFrontSked(RSkedPtr front_sked)
{
frontSked = front_sked;
frontSked_end.init(frontSked);
frontSked_end = frontSked->end();
//DPRINTF(InOrderDynInst, "Set FrontSked End to : %x \n" ,
// frontSked_end.getIt()/*, frontSked->end()*/);
//assert(frontSked_end == frontSked->end());
// This initializes instruction to be able
// to walk the resource schedule
curSkedEntry.init(frontSked);
curSkedEntry = frontSked->begin();
}
void setBackSked(RSkedPtr back_sked)
{
backSked = back_sked;
backSked_end.init(backSked);
backSked_end = backSked->end();
}
void setNextStage(int stage_num) { nextStage = stage_num; }
int getNextStage() { return nextStage; }
@ -426,53 +460,51 @@ class InOrderDynInst : public FastAlloc, public RefCounted
/** Print Resource Schedule */
/** @NOTE: DEBUG ONLY */
void printSched()
void printSked()
{
ThePipeline::ResSchedule tempSched;
std::cerr << "\tInst. Res. Schedule: ";
while (!resSched.empty()) {
std::cerr << '\t' << resSched.top()->stageNum << "-"
<< resSched.top()->resNum << ", ";
tempSched.push(resSched.top());
resSched.pop();
if (frontSked != NULL) {
frontSked->print();
}
std::cerr << std::endl;
resSched = tempSched;
if (backSked != NULL) {
backSked->print();
}
}
/** Return Next Resource Stage To Be Used */
int nextResStage()
{
if (resSched.empty())
return -1;
else
return resSched.top()->stageNum;
assert((inFrontEnd && curSkedEntry != frontSked_end) ||
(!inFrontEnd && curSkedEntry != backSked_end));
return curSkedEntry->stageNum;
}
/** Return Next Resource To Be Used */
int nextResource()
{
if (resSched.empty())
return -1;
else
return resSched.top()->resNum;
assert((inFrontEnd && curSkedEntry != frontSked_end) ||
(!inFrontEnd && curSkedEntry != backSked_end));
return curSkedEntry->resNum;
}
/** Remove & Deallocate a schedule entry */
void popSchedEntry()
/** Finish using a schedule entry, increment to next entry */
bool finishSkedEntry()
{
if (!resSched.empty()) {
ScheduleEntry* sked = resSched.top();
resSched.pop();
if (sked != 0) {
delete sked;
curSkedEntry++;
}
if (inFrontEnd && curSkedEntry == frontSked_end) {
assert(backSked != NULL);
curSkedEntry.init(backSked);
curSkedEntry = backSked->begin();
inFrontEnd = false;
} else if (!inFrontEnd && curSkedEntry == backSked_end) {
return true;
}
return false;
}
/** Release a Resource Request (Currently Unused) */

View file

@ -944,11 +944,16 @@ PipelineStage::processInstSchedule(DynInstPtr inst,int &reqs_processed)
"completed.\n", tid, inst->seqNum,
cpu->resPool->name(res_num));
inst->popSchedEntry();
reqs_processed++;
req->stagePasses++;
bool done_in_pipeline = inst->finishSkedEntry();
if (done_in_pipeline) {
DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] finished "
"in pipeline.\n", tid, inst->seqNum);
break;
}
} else {
DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s failed."
"\n", tid, inst->seqNum, cpu->resPool->name(res_num));

View file

@ -184,8 +184,8 @@ Resource::request(DynInstPtr inst)
if (slot_num != -1) {
// Get Stage # from Schedule Entry
stage_num = inst->resSched.top()->stageNum;
unsigned cmd = inst->resSched.top()->cmd;
stage_num = inst->curSkedEntry->stageNum;
unsigned cmd = inst->curSkedEntry->cmd;
// Generate Resource Request
inst_req = getRequest(inst, stage_num, id, slot_num, cmd);

View file

@ -91,6 +91,7 @@ ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params)
resources.push_back(new InstBuffer("Fetch-Buffer-T1", FetchBuff2, 4,
0, _cpu, params));
}
ResourcePool::~ResourcePool()
@ -122,6 +123,16 @@ ResourcePool::name()
return cpu->name() + ".ResourcePool";
}
void
ResourcePool::print()
{
for (int i=0; i < resources.size(); i++) {
DPRINTF(InOrderDynInst, "Res:%i %s\n",
i, resources[i]->name());
}
}
void
ResourcePool::regStats()

View file

@ -130,6 +130,8 @@ class ResourcePool {
void init();
void print();
/** Register Statistics in All Resources */
void regStats();

View file

@ -34,30 +34,30 @@
#include <vector>
#include <list>
#include <stdio.h>
#include <cstdio>
using namespace std;
using namespace ThePipeline;
ResourceSked::ResourceSked()
{
sked.resize(NumStages);
stages.resize(NumStages);
}
void
ResourceSked::init()
{
assert(!sked[0].empty());
assert(!stages[0].empty());
curSkedEntry = sked[0].begin();
curSkedEntry = stages[0].begin();
}
int
ResourceSked::size()
{
int total = 0;
for (int i = 0; i < sked.size(); i++) {
total += sked[i].size();
for (int i = 0; i < stages.size(); i++) {
total += stages[i].size();
}
return total;
@ -69,6 +69,26 @@ ResourceSked::empty()
return size() == 0;
}
ResourceSked::SkedIt
ResourceSked::begin()
{
int num_stages = stages.size();
for (int i = 0; i < num_stages; i++) {
if (stages[i].size() > 0)
return stages[i].begin();
}
return stages[num_stages - 1].end();
}
ResourceSked::SkedIt
ResourceSked::end()
{
int num_stages = stages.size();
return stages[num_stages - 1].end();
}
ScheduleEntry*
ResourceSked::top()
{
@ -82,18 +102,18 @@ ResourceSked::pop()
{
int stage_num = (*curSkedEntry)->stageNum;
sked[stage_num].erase(curSkedEntry);
stages[stage_num].erase(curSkedEntry);
if (!sked[stage_num].empty()) {
curSkedEntry = sked[stage_num].begin();
if (!stages[stage_num].empty()) {
curSkedEntry = stages[stage_num].begin();
} else {
int next_stage = stage_num + 1;
while (next_stage < NumStages) {
if (sked[next_stage].empty()) {
if (stages[next_stage].empty()) {
next_stage++;
} else {
curSkedEntry = sked[next_stage].begin();
curSkedEntry = stages[next_stage].begin();
break;
}
}
@ -108,7 +128,7 @@ ResourceSked::push(ScheduleEntry* sked_entry)
SkedIt pri_iter = findIterByPriority(sked_entry, stage_num);
sked[stage_num].insert(pri_iter, sked_entry);
stages[stage_num].insert(pri_iter, sked_entry);
}
void
@ -122,23 +142,23 @@ ResourceSked::pushBefore(ScheduleEntry* sked_entry, int sked_cmd,
SkedIt pri_iter = findIterByCommand(sked_entry, stage_num,
sked_cmd, sked_cmd_idx);
assert(pri_iter != sked[stage_num].end() &&
assert(pri_iter != stages[stage_num].end() &&
"Could not find command to insert in front of.");
sked[stage_num].insert(pri_iter, sked_entry);
stages[stage_num].insert(pri_iter, sked_entry);
}
ResourceSked::SkedIt
ResourceSked::findIterByPriority(ScheduleEntry* sked_entry, int stage_num)
{
if (sked[stage_num].empty()) {
return sked[stage_num].end();
if (stages[stage_num].empty()) {
return stages[stage_num].end();
}
int priority = sked_entry->priority;
SkedIt sked_it = sked[stage_num].begin();
SkedIt sked_end = sked[stage_num].end();
SkedIt sked_it = stages[stage_num].begin();
SkedIt sked_end = stages[stage_num].end();
while (sked_it != sked_end) {
if ((*sked_it)->priority > priority)
@ -154,12 +174,12 @@ ResourceSked::SkedIt
ResourceSked::findIterByCommand(ScheduleEntry* sked_entry, int stage_num,
int sked_cmd, int sked_cmd_idx)
{
if (sked[stage_num].empty()) {
return sked[stage_num].end();
if (stages[stage_num].empty()) {
return stages[stage_num].end();
}
SkedIt sked_it = sked[stage_num].begin();
SkedIt sked_end = sked[stage_num].end();
SkedIt sked_it = stages[stage_num].begin();
SkedIt sked_end = stages[stage_num].end();
while (sked_it != sked_end) {
if ((*sked_it)->cmd == sked_cmd &&
@ -175,12 +195,16 @@ ResourceSked::findIterByCommand(ScheduleEntry* sked_entry, int stage_num,
void
ResourceSked::print()
{
for (int i = 0; i < sked.size(); i++) {
cprintf("Stage %i\n====\n", i);
SkedIt sked_it = sked[i].begin();
SkedIt sked_end = sked[i].end();
for (int i = 0; i < stages.size(); i++) {
//ccprintf(cerr, "Stage %i\n====\n", i);
SkedIt sked_it = stages[i].begin();
SkedIt sked_end = stages[i].end();
while (sked_it != sked_end) {
cprintf("\t res:%i cmd:%i idx:%i\n", (*sked_it)->resNum, (*sked_it)->cmd, (*sked_it)->idx);
DPRINTF(SkedCache, "\t stage:%i res:%i cmd:%i idx:%i\n",
(*sked_it)->stageNum,
(*sked_it)->resNum,
(*sked_it)->cmd,
(*sked_it)->idx);
sked_it++;
}
}

View file

@ -260,7 +260,7 @@ CacheUnit::findRequest(DynInstPtr inst)
if (cache_req &&
cache_req->getInst() == inst &&
cache_req->instIdx == inst->resSched.top()->idx) {
cache_req->instIdx == inst->curSkedEntry->idx) {
return cache_req;
}
map_it++;
@ -296,7 +296,7 @@ ResReqPtr
CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
int slot_num, unsigned cmd)
{
ScheduleEntry* sched_entry = inst->resSched.top();
ScheduleEntry* sched_entry = *inst->curSkedEntry;
if (!inst->validMemAddr()) {
panic("Mem. Addr. must be set before requesting cache access\n");
@ -346,7 +346,7 @@ CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
return new CacheRequest(this, inst, stage_num, id, slot_num,
sched_entry->cmd, 0, pkt_cmd,
0/*flags*/, this->cpu->readCpuId(),
inst->resSched.top()->idx);
inst->curSkedEntry->idx);
}
void
@ -357,17 +357,17 @@ CacheUnit::requestAgain(DynInstPtr inst, bool &service_request)
// Check to see if this instruction is requesting the same command
// or a different one
if (cache_req->cmd != inst->resSched.top()->cmd &&
cache_req->instIdx == inst->resSched.top()->idx) {
if (cache_req->cmd != inst->curSkedEntry->cmd &&
cache_req->instIdx == inst->curSkedEntry->idx) {
// If different, then update command in the request
cache_req->cmd = inst->resSched.top()->cmd;
cache_req->cmd = inst->curSkedEntry->cmd;
DPRINTF(InOrderCachePort,
"[tid:%i]: [sn:%i]: Updating the command for this "
"instruction\n ", inst->readTid(), inst->seqNum);
service_request = true;
} else if (inst->resSched.top()->idx != CacheUnit::InitSecondSplitRead &&
inst->resSched.top()->idx != CacheUnit::InitSecondSplitWrite) {
} else if (inst->curSkedEntry->idx != CacheUnit::InitSecondSplitRead &&
inst->curSkedEntry->idx != CacheUnit::InitSecondSplitWrite) {
// If same command, just check to see if memory access was completed
// but dont try to re-execute
DPRINTF(InOrderCachePort,
@ -487,6 +487,8 @@ CacheUnit::read(DynInstPtr inst, Addr addr,
inst->splitMemData = new uint8_t[size];
if (!inst->splitInstSked) {
assert(0 && "Split Requests Not Supported for Now...");
// Schedule Split Read/Complete for Instruction
// ==============================
int stage_num = cache_req->getStageNum();
@ -590,6 +592,8 @@ CacheUnit::write(DynInstPtr inst, uint8_t *data, unsigned size,
inst->splitInst = true;
if (!inst->splitInstSked) {
assert(0 && "Split Requests Not Supported for Now...");
// Schedule Split Read/Complete for Instruction
// ==============================
int stage_num = cache_req->getStageNum();

View file

@ -57,13 +57,16 @@ DecodeUnit::execute(int slot_num)
{
case DecodeInst:
{
bool done_sked = ThePipeline::createBackEndSchedule(inst);
inst->setBackSked(cpu->createBackEndSked(inst));
if (done_sked) {
if (inst->backSked != NULL) {
DPRINTF(InOrderDecode,
"[tid:%i]: Setting Destination Register(s) for [sn:%i].\n",
tid, inst->seqNum);
regDepMap[tid]->insert(inst);
//inst->printSked();
decode_req->done();
} else {
DPRINTF(Resource,

View file

@ -118,7 +118,7 @@ ResReqPtr
FetchUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
int slot_num, unsigned cmd)
{
ScheduleEntry* sched_entry = inst->resSched.top();
ScheduleEntry* sched_entry = *inst->curSkedEntry;
if (!inst->validMemAddr()) {
panic("Mem. Addr. must be set before requesting cache access\n");
@ -144,7 +144,7 @@ FetchUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
return new CacheRequest(this, inst, stage_num, id, slot_num,
sched_entry->cmd, 0, pkt_cmd,
0/*flags*/, this->cpu->readCpuId(),
inst->resSched.top()->idx);
inst->curSkedEntry->idx);
}
void
@ -447,7 +447,7 @@ FetchUnit::processCacheCompletion(PacketPtr pkt)
short asid = cpu->asid[tid];
assert(!cache_req->isSquashed());
assert(inst->resSched.top()->cmd == CompleteFetch);
assert(inst->curSkedEntry->cmd == CompleteFetch);
DPRINTF(InOrderCachePort,
"[tid:%u]: [sn:%i]: Processing fetch access for block %#x\n",

View file

@ -52,14 +52,15 @@ GraduationUnit::execute(int slot_num)
ResourceRequest* grad_req = reqMap[slot_num];
DynInstPtr inst = reqMap[slot_num]->inst;
ThreadID tid = inst->readTid();
int stage_num = inst->resSched.top()->stageNum;
int stage_num = inst->curSkedEntry->stageNum;
switch (grad_req->cmd)
{
case GraduateInst:
{
// Make sure this is the last thing on the resource schedule
assert(inst->resSched.size() == 1);
// @todo: replace this check
// assert(inst->resSched.size() == 1);
// Handle Any Faults Before Graduating Instruction
if (inst->fault != NoFault) {

View file

@ -110,9 +110,9 @@ MultDivUnit::requestAgain(DynInstPtr inst, bool &service_request)
// Check to see if this instruction is requesting the same command
// or a different one
if (mult_div_req->cmd != inst->resSched.top()->cmd) {
if (mult_div_req->cmd != inst->curSkedEntry->cmd) {
// If different, then update command in the request
mult_div_req->cmd = inst->resSched.top()->cmd;
mult_div_req->cmd = inst->curSkedEntry->cmd;
DPRINTF(InOrderMDU,
"[tid:%i]: [sn:%i]: Updating the command for this "
"instruction\n", inst->readTid(), inst->seqNum);
@ -132,7 +132,7 @@ MultDivUnit::getSlot(DynInstPtr inst)
// If we have this instruction's request already then return
if (slot_num != -1 &&
inst->resSched.top()->cmd == reqMap[slot_num]->cmd)
inst->curSkedEntry->cmd == reqMap[slot_num]->cmd)
return slot_num;
unsigned repeat_rate = 0;

View file

@ -217,7 +217,7 @@ TLBUnitEvent::process()
// Effectively NOP the instruction but still allow it
// to commit
//while (!inst->resSched.empty() &&
// inst->resSched.top()->stageNum != ThePipeline::NumStages - 1) {
// inst->curSkedEntry->stageNum != ThePipeline::NumStages - 1) {
//inst->resSched.pop();
//}
}

View file

@ -93,7 +93,7 @@ UseDefUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
int slot_num, unsigned cmd)
{
return new UseDefRequest(this, inst, stage_num, id, slot_num, cmd,
inst->resSched.top()->idx);
inst->curSkedEntry->idx);
}
@ -110,8 +110,8 @@ UseDefUnit::findRequest(DynInstPtr inst)
if (ud_req &&
ud_req->getInst() == inst &&
ud_req->cmd == inst->resSched.top()->cmd &&
ud_req->useDefIdx == inst->resSched.top()->idx) {
ud_req->cmd == inst->curSkedEntry->cmd &&
ud_req->useDefIdx == inst->curSkedEntry->idx) {
return ud_req;
}
map_it++;