changeset 560d7fbbddd1 in /z/repo/gem5 details: http://repo.gem5.org/gem5?cmd=changeset;node=560d7fbbddd1 description: cpu: Add SMT support to MinorCPU
This patch adds SMT support to the MinorCPU. Currently RoundRobin or Random thread scheduling are supported. Change-Id: I91faf39ff881af5918cca05051829fc6261f20e3 diffstat: src/cpu/minor/MinorCPU.py | 4 + src/cpu/minor/cpu.cc | 59 +-- src/cpu/minor/cpu.hh | 23 + src/cpu/minor/decode.cc | 161 ++++++--- src/cpu/minor/decode.hh | 63 ++- src/cpu/minor/dyn_inst.cc | 6 + src/cpu/minor/exec_context.hh | 13 +- src/cpu/minor/execute.cc | 672 +++++++++++++++++++++++++----------------- src/cpu/minor/execute.hh | 118 ++++-- src/cpu/minor/fetch1.cc | 273 +++++++++++----- src/cpu/minor/fetch1.hh | 73 +++- src/cpu/minor/fetch2.cc | 251 +++++++++------ src/cpu/minor/fetch2.hh | 107 ++++-- src/cpu/minor/lsq.cc | 56 ++- src/cpu/minor/lsq.hh | 8 +- src/cpu/minor/pipe_data.cc | 9 +- src/cpu/minor/pipe_data.hh | 15 +- src/cpu/minor/pipeline.cc | 9 +- src/cpu/minor/pipeline.hh | 2 +- src/sim/pseudo_inst.cc | 2 +- util/minorview/minor.pic | 12 +- 21 files changed, 1245 insertions(+), 691 deletions(-) diffs (truncated from 3613 to 300 lines): diff -r b11410957c9e -r 560d7fbbddd1 src/cpu/minor/MinorCPU.py --- a/src/cpu/minor/MinorCPU.py Thu Jul 21 17:19:15 2016 +0100 +++ b/src/cpu/minor/MinorCPU.py Thu Jul 21 17:19:16 2016 +0100 @@ -169,6 +169,8 @@ MinorDefaultFloatSimdFU(), MinorDefaultMemFU(), MinorDefaultMiscFU()] +class ThreadPolicy(Enum): vals = ['SingleThreaded', 'RoundRobin', 'Random'] + class MinorCPU(BaseCPU): type = 'MinorCPU' cxx_header = "cpu/minor/cpu.hh" @@ -185,6 +187,8 @@ def support_take_over(cls): return True + threadPolicy = Param.ThreadPolicy('RoundRobin', + "Thread scheduling policy") fetch1FetchLimit = Param.Unsigned(1, "Number of line fetches allowable in flight at once") fetch1LineSnapWidth = Param.Unsigned(0, diff -r b11410957c9e -r 560d7fbbddd1 src/cpu/minor/cpu.cc --- a/src/cpu/minor/cpu.cc Thu Jul 21 17:19:15 2016 +0100 +++ b/src/cpu/minor/cpu.cc Thu Jul 21 17:19:16 2016 +0100 @@ -47,32 +47,33 @@ #include "debug/Quiesce.hh" MinorCPU::MinorCPU(MinorCPUParams *params) : - BaseCPU(params) + BaseCPU(params), + threadPolicy(params->threadPolicy) { /* This is only written for one thread at the moment */ Minor::MinorThread *thread; - if (FullSystem) { - thread = new Minor::MinorThread(this, 0, params->system, params->itb, - params->dtb, params->isa[0]); - } else { - /* thread_id 0 */ - thread = new Minor::MinorThread(this, 0, params->system, - params->workload[0], params->itb, params->dtb, params->isa[0]); + for (ThreadID i = 0; i < numThreads; i++) { + if (FullSystem) { + thread = new Minor::MinorThread(this, i, params->system, + params->itb, params->dtb, params->isa[i]); + thread->setStatus(ThreadContext::Halted); + } else { + thread = new Minor::MinorThread(this, i, params->system, + params->workload[i], params->itb, params->dtb, + params->isa[i]); + } + + threads.push_back(thread); + ThreadContext *tc = thread->getTC(); + threadContexts.push_back(tc); } - threads.push_back(thread); - - thread->setStatus(ThreadContext::Halted); - - ThreadContext *tc = thread->getTC(); if (params->checker) { fatal("The Minor model doesn't support checking (yet)\n"); } - threadContexts.push_back(tc); - Minor::MinorDynInst::init(); pipeline = new Minor::Pipeline(*this, *params); @@ -137,9 +138,6 @@ void MinorCPU::unserializeThread(CheckpointIn &cp, ThreadID thread_id) { - if (thread_id != 0) - fatal("Trying to load more than one thread into a MinorCPU\n"); - threads[thread_id]->unserialize(cp); } @@ -170,11 +168,11 @@ MinorCPU::wakeup(ThreadID tid) { DPRINTF(Drain, "[tid:%d] MinorCPU wakeup\n", tid); + assert(tid < numThreads); - if (threads[tid]->status() == ThreadContext::Suspended) + if (threads[tid]->status() == ThreadContext::Suspended) { threads[tid]->activate(); - - DPRINTF(Drain,"Suspended Processor awoke\n"); + } } void @@ -187,13 +185,10 @@ for (auto i = threads.begin(); i != threads.end(); i ++) (*i)->startup(); - /* Workaround cases in SE mode where a thread is activated with an - * incorrect PC that is updated after the call to activate. This - * causes problems for Minor since it instantiates a virtual - * branch instruction when activateContext() is called which ends - * up pointing to an illegal address. */ - if (threads[0]->status() == ThreadContext::Active) - activateContext(0); + for (ThreadID tid = 0; tid < numThreads; tid++) { + threads[tid]->startup(); + pipeline->wakeupFetch(tid); + } } DrainState @@ -246,6 +241,7 @@ for (ThreadID tid = 0; tid < numThreads; tid++) wakeup(tid); + pipeline->drainResume(); } @@ -278,7 +274,7 @@ void MinorCPU::activateContext(ThreadID thread_id) { - DPRINTF(MinorCPU, "ActivateContext thread: %d", thread_id); + DPRINTF(MinorCPU, "ActivateContext thread: %d\n", thread_id); /* Do some cycle accounting. lastStopped is reset to stop the * wakeup call on the pipeline from adding the quiesce period @@ -289,7 +285,7 @@ /* Wake up the thread, wakeup the pipeline tick */ threads[thread_id]->activate(); wakeupOnEvent(Minor::Pipeline::CPUStageId); - pipeline->wakeupFetch(); + pipeline->wakeupFetch(thread_id); BaseCPU::activateContext(thread_id); } @@ -317,9 +313,6 @@ MinorCPU * MinorCPUParams::create() { - numThreads = 1; - if (!FullSystem && workload.size() != 1) - panic("only one workload allowed"); return new MinorCPU(this); } diff -r b11410957c9e -r 560d7fbbddd1 src/cpu/minor/cpu.hh --- a/src/cpu/minor/cpu.hh Thu Jul 21 17:19:15 2016 +0100 +++ b/src/cpu/minor/cpu.hh Thu Jul 21 17:19:16 2016 +0100 @@ -50,6 +50,7 @@ #include "cpu/minor/stats.hh" #include "cpu/base.hh" #include "cpu/simple_thread.hh" +#include "enums/ThreadPolicy.hh" #include "params/MinorCPU.hh" namespace Minor @@ -109,6 +110,8 @@ }; + /** Thread Scheduling Policy (RoundRobin, Random, etc) */ + Enums::ThreadPolicy threadPolicy; protected: /** Return a reference to the data port. */ MasterPort &getDataPort() override; @@ -162,6 +165,26 @@ void activateContext(ThreadID thread_id) override; void suspendContext(ThreadID thread_id) override; + /** Thread scheduling utility functions */ + std::vector<ThreadID> roundRobinPriority(ThreadID priority) + { + std::vector<ThreadID> prio_list; + for (ThreadID i = 1; i <= numThreads; i++) { + prio_list.push_back((priority + i) % numThreads); + } + return prio_list; + } + + std::vector<ThreadID> randomPriority() + { + std::vector<ThreadID> prio_list; + for (ThreadID i = 0; i < numThreads; i++) { + prio_list.push_back(i); + } + std::random_shuffle(prio_list.begin(), prio_list.end()); + return prio_list; + } + /** Interface for stages to signal that they have become active after * a callback or eventq event where the pipeline itself may have * already been idled. The stage argument should be from the diff -r b11410957c9e -r 560d7fbbddd1 src/cpu/minor/decode.cc --- a/src/cpu/minor/decode.cc Thu Jul 21 17:19:15 2016 +0100 +++ b/src/cpu/minor/decode.cc Thu Jul 21 17:19:16 2016 +0100 @@ -49,7 +49,7 @@ MinorCPUParams ¶ms, Latch<ForwardInstData>::Output inp_, Latch<ForwardInstData>::Input out_, - Reservable &next_stage_input_buffer) : + std::vector<InputBuffer<ForwardInstData>> &next_stage_input_buffer) : Named(name), cpu(cpu_), inp(inp_), @@ -57,11 +57,8 @@ nextStageReserve(next_stage_input_buffer), outputWidth(params.executeInputWidth), processMoreThanOneInput(params.decodeCycleInput), - inputBuffer(name + ".inputBuffer", "insts", params.decodeInputBufferSize), - inputIndex(0), - inMacroop(false), - execSeqNum(InstId::firstExecSeqNum), - blocked(false) + decodeInfo(params.numThreads), + threadPriority(0) { if (outputWidth < 1) fatal("%s: executeInputWidth must be >= 1 (%d)\n", name, outputWidth); @@ -70,29 +67,37 @@ fatal("%s: decodeInputBufferSize must be >= 1 (%d)\n", name, params.decodeInputBufferSize); } + + /* Per-thread input buffers */ + for (ThreadID tid = 0; tid < params.numThreads; tid++) { + inputBuffer.push_back( + InputBuffer<ForwardInstData>( + name + ".inputBuffer" + std::to_string(tid), "insts", + params.decodeInputBufferSize)); + } } const ForwardInstData * -Decode::getInput() +Decode::getInput(ThreadID tid) { /* Get insts from the inputBuffer to work with */ - if (!inputBuffer.empty()) { - const ForwardInstData &head = inputBuffer.front(); + if (!inputBuffer[tid].empty()) { + const ForwardInstData &head = inputBuffer[tid].front(); - return (head.isBubble() ? NULL : &(inputBuffer.front())); + return (head.isBubble() ? NULL : &(inputBuffer[tid].front())); } else { return NULL; } } void -Decode::popInput() +Decode::popInput(ThreadID tid) { - if (!inputBuffer.empty()) - inputBuffer.pop(); + if (!inputBuffer[tid].empty()) + inputBuffer[tid].pop(); - inputIndex = 0; - inMacroop = false; + decodeInfo[tid].inputIndex = 0; + decodeInfo[tid].inMacroop = false; } #if TRACING_ON @@ -117,32 +122,37 @@ void Decode::evaluate() { - inputBuffer.setTail(*inp.outputWire); + /* Push input onto appropriate input buffer */ + if (!inp.outputWire->isBubble()) + inputBuffer[inp.outputWire->threadId].setTail(*inp.outputWire); + ForwardInstData &insts_out = *out.inputWire; assert(insts_out.isBubble()); - blocked = false; + for (ThreadID tid = 0; tid < cpu.numThreads; tid++) + decodeInfo[tid].blocked = !nextStageReserve[tid].canReserve(); - if (!nextStageReserve.canReserve()) { - blocked = true; - } else { - const ForwardInstData *insts_in = getInput(); + ThreadID tid = getScheduledThread(); + + if (tid != InvalidThreadID) { + DecodeThreadInfo &decode_info = decodeInfo[tid]; + const ForwardInstData *insts_in = getInput(tid); unsigned int output_index = 0; _______________________________________________ gem5-dev mailing list gem5-dev@gem5.org http://m5sim.org/mailman/listinfo/gem5-dev