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 &params,
     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

Reply via email to