diff options
author | Steve Reinhardt <stever@eecs.umich.edu> | 2003-10-23 19:07:52 -0700 |
---|---|---|
committer | Steve Reinhardt <stever@eecs.umich.edu> | 2003-10-23 19:07:52 -0700 |
commit | f5da73b6881991a28844ed59e8dcc1d154ddae7e (patch) | |
tree | bc89728af5db24ef0bf1580045c3bcd26a206e85 /cpu | |
parent | 73b050a541b1778596f9ebffa8a9f780446365c3 (diff) | |
download | gem5-f5da73b6881991a28844ed59e8dcc1d154ddae7e.tar.xz |
Initial support for CPU switching. New SamplingCPU object encompasses a set
of CPUs that get switched round-robin (though currently we're only shooting for
two CPUs and one switch event, and even that doesn't quite work yet). Registration
of ExecContexts with System/Process object factored out so we can create two CPUs
but only register one of them at a time. Also worked at making behavior and naming
in System and Process objects more consistent.
arch/alpha/ev5.cc:
Rename ipr_init to initIPRs and get rid of unused mem arg.
arch/alpha/fake_syscall.cc:
Process:numCpus is now a function (not a data member).
base/remote_gdb.hh:
Support for ExecContext switching.
cpu/base_cpu.cc:
cpu/base_cpu.hh:
cpu/exec_context.cc:
cpu/exec_context.hh:
cpu/simple_cpu/simple_cpu.hh:
Support for ExecContext switching.
Renamed contexts array to execContexts to be consistent with Process.
CPU ID now auto-assigned by system object.
cpu/simple_cpu/simple_cpu.cc:
Support for ExecContext switching.
Renamed contexts array to execContexts to be consistent with Process.
CPU ID now auto-assigned by system object.
Cleaned up MP full-system initialization a bit.
dev/alpha_console.cc:
Renamed xcvec array to execContexts to be consistent with Process.
kern/tru64/tru64_system.cc:
kern/tru64/tru64_system.hh:
Support for ExecContext switching.
CPU ID now auto-assigned by system object.
sim/prog.cc:
sim/prog.hh:
Support for ExecContext switching.
Process:numCpus is now a function (not a data member).
sim/system.cc:
sim/system.hh:
Support for ExecContext switching.
Renamed xcvec array to execContexts to be consistent with Process.
--HG--
extra : convert_revision : 79649cffad5bf3e83de8df44236941907926d791
Diffstat (limited to 'cpu')
-rw-r--r-- | cpu/base_cpu.cc | 64 | ||||
-rw-r--r-- | cpu/base_cpu.hh | 16 | ||||
-rw-r--r-- | cpu/exec_context.cc | 58 | ||||
-rw-r--r-- | cpu/exec_context.hh | 20 | ||||
-rw-r--r-- | cpu/simple_cpu/simple_cpu.cc | 152 | ||||
-rw-r--r-- | cpu/simple_cpu/simple_cpu.hh | 15 |
6 files changed, 224 insertions, 101 deletions
diff --git a/cpu/base_cpu.cc b/cpu/base_cpu.cc index 90e090d5e..74d2ceada 100644 --- a/cpu/base_cpu.cc +++ b/cpu/base_cpu.cc @@ -52,8 +52,8 @@ BaseCPU::BaseCPU(const string &_name, int _number_of_threads, Counter max_insts_all_threads, Counter max_loads_any_thread, Counter max_loads_all_threads, - System *_system, int num, Tick freq) - : SimObject(_name), number(num), frequency(freq), + System *_system, Tick freq) + : SimObject(_name), frequency(freq), number_of_threads(_number_of_threads), system(_system) #else BaseCPU::BaseCPU(const string &_name, int _number_of_threads, @@ -120,27 +120,73 @@ BaseCPU::BaseCPU(const string &_name, int _number_of_threads, max_loads_all_threads, *counter); } - #ifdef FULL_SYSTEM memset(interrupts, 0, sizeof(interrupts)); intstatus = 0; #endif } + void BaseCPU::regStats() { - int size = contexts.size(); + int size = execContexts.size(); if (size > 1) { for (int i = 0; i < size; ++i) { stringstream namestr; ccprintf(namestr, "%s.ctx%d", name(), i); - contexts[i]->regStats(namestr.str()); + execContexts[i]->regStats(namestr.str()); } } else if (size == 1) - contexts[0]->regStats(name()); + execContexts[0]->regStats(name()); +} + + +void +BaseCPU::registerExecContexts() +{ + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + int cpu_id; + +#ifdef FULL_SYSTEM + cpu_id = system->registerExecContext(xc); +#else + cpu_id = xc->process->registerExecContext(xc); +#endif + + xc->cpu_id = cpu_id; + } +} + + +void +BaseCPU::switchOut() +{ + // default: do nothing } +void +BaseCPU::takeOverFrom(BaseCPU *oldCPU) +{ + assert(execContexts.size() == oldCPU->execContexts.size()); + + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *newXC = execContexts[i]; + ExecContext *oldXC = oldCPU->execContexts[i]; + + newXC->takeOverFrom(oldXC); + assert(newXC->cpu_id == oldXC->cpu_id); +#ifdef FULL_SYSTEM + system->replaceExecContext(newXC->cpu_id, newXC); +#else + assert(newXC->process == oldXC->process); + newXC->process->replaceExecContext(newXC->cpu_id, newXC); +#endif + } +} + + #ifdef FULL_SYSTEM void BaseCPU::post_interrupt(int int_num, int index) @@ -185,4 +231,10 @@ BaseCPU::clear_interrupts() #endif // FULL_SYSTEM +// +// This declaration is not needed now that SamplingCPU provides a +// BaseCPUBuilder object. +// +#if 0 DEFINE_SIM_OBJECT_CLASS_NAME("BaseCPU", BaseCPU) +#endif diff --git a/cpu/base_cpu.hh b/cpu/base_cpu.hh index e5d9df6de..5a20aaa54 100644 --- a/cpu/base_cpu.hh +++ b/cpu/base_cpu.hh @@ -47,7 +47,6 @@ class BaseCPU : public SimObject { #ifdef FULL_SYSTEM protected: - int number; Tick frequency; uint8_t interrupts[NumInterruptLevels]; uint64_t intstatus; @@ -71,7 +70,7 @@ class BaseCPU : public SimObject #endif protected: - std::vector<ExecContext *> contexts; + std::vector<ExecContext *> execContexts; public: virtual void execCtxStatusChg() {} @@ -82,8 +81,7 @@ class BaseCPU : public SimObject BaseCPU(const std::string &_name, int _number_of_threads, Counter max_insts_any_thread, Counter max_insts_all_threads, Counter max_loads_any_thread, Counter max_loads_all_threads, - System *_system, - int num, Tick freq); + System *_system, Tick freq); #else BaseCPU(const std::string &_name, int _number_of_threads, Counter max_insts_any_thread = 0, @@ -96,6 +94,16 @@ class BaseCPU : public SimObject virtual void regStats(); + virtual void registerExecContexts(); + + /// Prepare for another CPU to take over execution. Called by + /// takeOverFrom() on its argument. + virtual void switchOut(); + + /// Take over execution from the given CPU. Used for warm-up and + /// sampling. + virtual void takeOverFrom(BaseCPU *); + /** * Number of threads we're actually simulating (<= SMT_MAX_THREADS). * This is a constant for the duration of the simulation. diff --git a/cpu/exec_context.cc b/cpu/exec_context.cc index 87f7283aa..6c24500cc 100644 --- a/cpu/exec_context.cc +++ b/cpu/exec_context.cc @@ -43,42 +43,62 @@ using namespace std; #ifdef FULL_SYSTEM ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, System *_sys, AlphaItb *_itb, AlphaDtb *_dtb, - FunctionalMemory *_mem, int _cpu_id) - : kernelStats(this, _cpu), cpu(_cpu), thread_num(_thread_num), mem(_mem), - itb(_itb), dtb(_dtb), cpu_id(_cpu_id), system(_sys), - memCtrl(_sys->memCtrl), physmem(_sys->physmem) + FunctionalMemory *_mem) + : kernelStats(this, _cpu), cpu(_cpu), thread_num(_thread_num), + cpu_id(-1), mem(_mem), itb(_itb), dtb(_dtb), system(_sys), + memCtrl(_sys->memCtrl), physmem(_sys->physmem), + func_exe_insn(0), storeCondFailures(0) { memset(®s, 0, sizeof(RegFile)); - _status = Active; - func_exe_insn = 0; - storeCondFailures = 0; - system->registerExecContext(this); + setStatus(ExecContext::Unallocated); } #else ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid) - : cpu(_cpu), thread_num(_thread_num), process(_process), asid (_asid) + : cpu(_cpu), thread_num(_thread_num), cpu_id(-1), + process(_process), asid (_asid), + func_exe_insn(0), storeCondFailures(0) { - - // Register with process object. Our 'active' will be set by the - // process iff we're the initial context. Others are reserved for - // dynamically created threads. - process->registerExecContext(this); + setStatus(ExecContext::Unallocated); mem = process->getMemory(); - - func_exe_insn = 0; - storeCondFailures = 0; } ExecContext::ExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem, int _asid) - : cpu(_cpu), thread_num(_thread_num), process(NULL), mem(_mem), - asid(_asid) + : cpu(_cpu), thread_num(_thread_num), process(0), mem(_mem), asid(_asid), + func_exe_insn(0), storeCondFailures(0) { } #endif + +void +ExecContext::takeOverFrom(ExecContext *oldContext) +{ + // some things should already be set up + assert(mem == oldContext->mem); +#ifdef FULL_SYSTEM + assert(system == oldContext->system); +#else + assert(process == oldContext->process); +#endif + + // copy over functional state + _status = oldContext->_status; +#ifdef FULL_SYSTEM + kernelStats = oldContext->kernelStats; +#endif + regs = oldContext->regs; + cpu_id = oldContext->cpu_id; + func_exe_insn = oldContext->func_exe_insn; + + storeCondFailures = 0; + + oldContext->_status = ExecContext::Unallocated; +} + + void ExecContext::setStatus(Status new_status) { diff --git a/cpu/exec_context.hh b/cpu/exec_context.hh index 4a2688f1c..817c72b3b 100644 --- a/cpu/exec_context.hh +++ b/cpu/exec_context.hh @@ -67,6 +67,11 @@ class ExecContext public: Status status() const { return _status; } + + // Unlike setStatus(), initStatus() has no side effects other than + // setting the _status variable. + void initStatus(Status init_status) { _status = init_status; } + void setStatus(Status new_status); #ifdef FULL_SYSTEM @@ -83,12 +88,15 @@ class ExecContext // Index of hardware thread context on the CPU that this represents. int thread_num; + // ID of this context w.r.t. the System or Process object to which + // it belongs. For full-system mode, this is the system CPU ID. + int cpu_id; + #ifdef FULL_SYSTEM FunctionalMemory *mem; AlphaItb *itb; AlphaDtb *dtb; - int cpu_id; System *system; // the following two fields are redundant, since we can always @@ -124,8 +132,7 @@ class ExecContext // constructor: initialize context from given process structure #ifdef FULL_SYSTEM ExecContext(BaseCPU *_cpu, int _thread_num, System *_system, - AlphaItb *_itb, AlphaDtb *_dtb, FunctionalMemory *_dem, - int _cpu_id); + AlphaItb *_itb, AlphaDtb *_dtb, FunctionalMemory *_dem); #else ExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid); ExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem, @@ -133,6 +140,8 @@ class ExecContext #endif virtual ~ExecContext() {} + virtual void takeOverFrom(ExecContext *oldContext); + void regStats(const std::string &name); #ifdef FULL_SYSTEM @@ -156,7 +165,6 @@ class ExecContext return dtb->translate(req, true); } - #else bool validInstAddr(Addr addr) { return process->validInstAddr(addr); } @@ -244,8 +252,8 @@ class ExecContext // and all other stores (WH64?). Unsuccessful Store // Conditionals would have returned above, and wouldn't fall // through. - for (int i = 0; i < system->xcvec.size(); i++){ - cregs = &system->xcvec[i]->regs.miscRegs; + for (int i = 0; i < system->execContexts.size(); i++){ + cregs = &system->execContexts[i]->regs.miscRegs; if ((cregs->lock_addr & ~0xf) == (req->paddr & ~0xf)) { cregs->lock_flag = false; } diff --git a/cpu/simple_cpu/simple_cpu.cc b/cpu/simple_cpu/simple_cpu.cc index 3c9be172f..c96e31cb0 100644 --- a/cpu/simple_cpu/simple_cpu.cc +++ b/cpu/simple_cpu/simple_cpu.cc @@ -103,11 +103,11 @@ SimpleCPU::SimpleCPU(const string &_name, FunctionalMemory *mem, MemInterface *icache_interface, MemInterface *dcache_interface, - int cpu_id, Tick freq) + Tick freq) : BaseCPU(_name, /* number_of_threads */ 1, max_insts_any_thread, max_insts_all_threads, max_loads_any_thread, max_loads_all_threads, - _system, cpu_id, freq), + _system, freq), #else SimpleCPU::SimpleCPU(const string &_name, Process *_process, Counter max_insts_any_thread, @@ -122,61 +122,23 @@ SimpleCPU::SimpleCPU(const string &_name, Process *_process, #endif tickEvent(this), xc(NULL), cacheCompletionEvent(this) { + _status = Idle; #ifdef FULL_SYSTEM - xc = new ExecContext(this, 0, system, itb, dtb, mem, cpu_id); + xc = new ExecContext(this, 0, system, itb, dtb, mem); - _status = Running; - if (cpu_id != 0) { + TheISA::initCPU(&xc->regs); - xc->setStatus(ExecContext::Unallocated); + IntReg *ipr = xc->regs.ipr; + ipr[TheISA::IPR_MCSR] = 0x6; - //Open a GDB debug session on port (7000 + the cpu_id) - (new GDBListener(new RemoteGDB(system, xc), 7000 + cpu_id))->listen(); - - AlphaISA::init(system->physmem, &xc->regs); - - fault = Reset_Fault; - - IntReg *ipr = xc->regs.ipr; - ipr[TheISA::IPR_MCSR] = 0x6; - - AlphaISA::swap_palshadow(&xc->regs, true); - - xc->regs.pc = - ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault]; - xc->regs.npc = xc->regs.pc + sizeof(MachInst); - - _status = Idle; - } - else { - system->init(xc); - - // Reset the system - // - AlphaISA::init(system->physmem, &xc->regs); - - fault = Reset_Fault; - - IntReg *ipr = xc->regs.ipr; - ipr[TheISA::IPR_MCSR] = 0x6; - - AlphaISA::swap_palshadow(&xc->regs, true); - - xc->regs.pc = ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault]; - xc->regs.npc = xc->regs.pc + sizeof(MachInst); - - _status = Running; - tickEvent.schedule(0); - } + AlphaISA::swap_palshadow(&xc->regs, true); + fault = Reset_Fault; + xc->regs.pc = ipr[TheISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault]; + xc->regs.npc = xc->regs.pc + sizeof(MachInst); #else xc = new ExecContext(this, /* thread_num */ 0, _process, /* asid */ 0); fault = No_Fault; - if (xc->status() == ExecContext::Active) { - _status = Running; - tickEvent.schedule(0); - } else - _status = Idle; #endif // !FULL_SYSTEM icacheInterface = icache_interface; @@ -193,13 +155,61 @@ SimpleCPU::SimpleCPU(const string &_name, Process *_process, lastIcacheStall = 0; lastDcacheStall = 0; - contexts.push_back(xc); + execContexts.push_back(xc); } SimpleCPU::~SimpleCPU() { } + +void +SimpleCPU::registerExecContexts() +{ + BaseCPU::registerExecContexts(); + + // if any of this CPU's ExecContexts are active, mark the CPU as + // running and schedule its tick event. + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + if (xc->status() == ExecContext::Active && _status != Running) { + _status = Running; + // this should only happen at initialization time + assert(curTick == 0); + tickEvent.schedule(0); + } + } +} + + +void +SimpleCPU::switchOut() +{ + _status = SwitchedOut; + if (tickEvent.scheduled()) + tickEvent.squash(); +} + + +void +SimpleCPU::takeOverFrom(BaseCPU *oldCPU) +{ + BaseCPU::takeOverFrom(oldCPU); + + assert(!tickEvent.scheduled()); + + // if any of this CPU's ExecContexts are active, mark the CPU as + // running and schedule its tick event. + for (int i = 0; i < execContexts.size(); ++i) { + ExecContext *xc = execContexts[i]; + if (xc->status() == ExecContext::Active && _status != Running) { + _status = Running; + tickEvent.schedule(curTick + 1); + } + } +} + + void SimpleCPU::regStats() { @@ -488,6 +498,11 @@ SimpleCPU::processCacheCompletion() dcacheStallCycles += curTick - lastDcacheStall; setStatus(Running); break; + case SwitchedOut: + // If this CPU has been switched out due to sampling/warm-up, + // ignore any further status changes (e.g., due to cache + // misses outstanding at the time of the switch). + return; default: panic("SimpleCPU::processCacheCompletion: bad state"); break; @@ -693,7 +708,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) SimObjectParam<AlphaDtb *> dtb; SimObjectParam<FunctionalMemory *> mem; SimObjectParam<System *> system; - Param<int> cpu_id; Param<int> mult; #else SimObjectParam<Process *> workload; @@ -702,6 +716,8 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) SimObjectParam<BaseMem *> icache; SimObjectParam<BaseMem *> dcache; + Param<bool> defer_registration; + END_DECLARE_SIM_OBJECT_PARAMS(SimpleCPU) BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) @@ -724,39 +740,47 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleCPU) INIT_PARAM(dtb, "Data TLB"), INIT_PARAM(mem, "memory"), INIT_PARAM(system, "system object"), - INIT_PARAM_DFLT(cpu_id, "CPU identification number", 0), INIT_PARAM_DFLT(mult, "system clock multiplier", 1), #else INIT_PARAM(workload, "processes to run"), #endif // FULL_SYSTEM INIT_PARAM_DFLT(icache, "L1 instruction cache object", NULL), - INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL) + INIT_PARAM_DFLT(dcache, "L1 data cache object", NULL), + INIT_PARAM_DFLT(defer_registration, "defer registration with system " + "(for sampling)", false) END_INIT_SIM_OBJECT_PARAMS(SimpleCPU) CREATE_SIM_OBJECT(SimpleCPU) { + SimpleCPU *cpu; #ifdef FULL_SYSTEM if (mult != 1) panic("processor clock multiplier must be 1\n"); - return new SimpleCPU(getInstanceName(), system, - max_insts_any_thread, max_insts_all_threads, - max_loads_any_thread, max_loads_all_threads, - itb, dtb, mem, - (icache) ? icache->getInterface() : NULL, - (dcache) ? dcache->getInterface() : NULL, - cpu_id, ticksPerSecond * mult); + cpu = new SimpleCPU(getInstanceName(), system, + max_insts_any_thread, max_insts_all_threads, + max_loads_any_thread, max_loads_all_threads, + itb, dtb, mem, + (icache) ? icache->getInterface() : NULL, + (dcache) ? dcache->getInterface() : NULL, + ticksPerSecond * mult); #else - return new SimpleCPU(getInstanceName(), workload, - max_insts_any_thread, max_insts_all_threads, - max_loads_any_thread, max_loads_all_threads, - icache->getInterface(), dcache->getInterface()); + cpu = new SimpleCPU(getInstanceName(), workload, + max_insts_any_thread, max_insts_all_threads, + max_loads_any_thread, max_loads_all_threads, + icache->getInterface(), dcache->getInterface()); #endif // FULL_SYSTEM + + if (!defer_registration) { + cpu->registerExecContexts(); + } + + return cpu; } REGISTER_SIM_OBJECT("SimpleCPU", SimpleCPU) diff --git a/cpu/simple_cpu/simple_cpu.hh b/cpu/simple_cpu/simple_cpu.hh index fd50acfe1..e1b351cab 100644 --- a/cpu/simple_cpu/simple_cpu.hh +++ b/cpu/simple_cpu/simple_cpu.hh @@ -92,7 +92,8 @@ class SimpleCPU : public BaseCPU Idle, IcacheMissStall, IcacheMissComplete, - DcacheMissStall + DcacheMissStall, + SwitchedOut }; private: @@ -117,7 +118,7 @@ class SimpleCPU : public BaseCPU Counter max_loads_any_thread, Counter max_loads_all_threads, AlphaItb *itb, AlphaDtb *dtb, FunctionalMemory *mem, MemInterface *icache_interface, MemInterface *dcache_interface, - int cpu_id, Tick freq); + Tick freq); #else @@ -135,6 +136,11 @@ class SimpleCPU : public BaseCPU // execution context ExecContext *xc; + void registerExecContexts(); + + void switchOut(); + void takeOverFrom(BaseCPU *oldCPU); + #ifdef FULL_SYSTEM Addr dbg_vtophys(Addr addr); @@ -171,6 +177,7 @@ class SimpleCPU : public BaseCPU CacheCompletionEvent cacheCompletionEvent; Status status() const { return _status; } + virtual void execCtxStatusChg() { if (xc) { if (xc->status() == ExecContext::Active) @@ -182,6 +189,10 @@ class SimpleCPU : public BaseCPU void setStatus(Status new_status) { Status old_status = status(); + + // We should never even get here if the CPU has been switched out. + assert(old_status != SwitchedOut); + _status = new_status; switch (status()) { |