summaryrefslogtreecommitdiff
path: root/src/systemc/core/scheduler.hh
diff options
context:
space:
mode:
authorGabe Black <gabeblack@google.com>2018-07-04 22:41:29 -0700
committerGabe Black <gabeblack@google.com>2018-09-05 06:04:19 +0000
commit7088d69ab5fc70fca4890e0d0169fadd2b19bab8 (patch)
treec74b56e47f903c7fb8e722393e86a28410ae2c21 /src/systemc/core/scheduler.hh
parent0aec777bf2fff0ac61cd36b7c0358dbe9350c784 (diff)
downloadgem5-7088d69ab5fc70fca4890e0d0169fadd2b19bab8.tar.xz
systemc: Implement channel updates and rework the scheduler.
This change implements channel updates, and also reworks the scheduler to delegate more to the gem5 event queue by taking advantage of event priorities to ensure things happen in the right order. There's a lengthy comment in scheduler.hh describes how that all works. Change-Id: I5dee71b86b2e612bb720a4429f3a72e4b7c6d01f Reviewed-on: https://gem5-review.googlesource.com/11710 Reviewed-by: Gabe Black <gabeblack@google.com> Maintainer: Gabe Black <gabeblack@google.com>
Diffstat (limited to 'src/systemc/core/scheduler.hh')
-rw-r--r--src/systemc/core/scheduler.hh108
1 files changed, 91 insertions, 17 deletions
diff --git a/src/systemc/core/scheduler.hh b/src/systemc/core/scheduler.hh
index a7216231a..e1ad21a57 100644
--- a/src/systemc/core/scheduler.hh
+++ b/src/systemc/core/scheduler.hh
@@ -30,6 +30,8 @@
#ifndef __SYSTEMC_CORE_SCHEDULER_HH__
#define __SYSTEMC_CORE_SCHEDULER_HH__
+#include "sim/eventq.hh"
+#include "systemc/core/channel.hh"
#include "systemc/core/list.hh"
#include "systemc/core/process.hh"
@@ -37,20 +39,84 @@ namespace sc_gem5
{
typedef NodeList<Process> ProcessList;
+typedef NodeList<Channel> ChannelList;
+
+/*
+ * The scheduler supports three different mechanisms, the initialization phase,
+ * delta cycles, and timed notifications.
+ *
+ * INITIALIZATION PHASE
+ *
+ * The initialization phase has three parts:
+ * 1. Run requested channel updates.
+ * 2. Make processes which need to initialize runnable (methods and threads
+ * which didn't have dont_initialize called on them).
+ * 3. Process delta notifications.
+ *
+ * First, the Kernel SimObject calls the update() method during its startup()
+ * callback which handles the requested channel updates. The Kernel also
+ * schedules an event to be run at time 0 with a slightly elevated priority
+ * so that it happens before any "normal" event.
+ *
+ * When that t0 event happens, it calls the schedulers initToReady method
+ * which performs step 2 above. That indirectly causes the scheduler's
+ * readyEvent to be scheduled with slightly lowered priority, ensuring it
+ * happens after any "normal" event.
+ *
+ * Because delta notifications are scheduled at the standard priority, all
+ * of those events will happen next, performing step 3 above. Once they finish,
+ * if the readyEvent was scheduled above, there shouldn't be any higher
+ * priority events in front of it. When it runs, it will start the first
+ * evaluate phase of the first delta cycle.
+ *
+ * DELTA CYCLE
+ *
+ * A delta cycle has three phases within it.
+ * 1. The evaluate phase where runnable processes are allowed to run.
+ * 2. The update phase where requested channel updates hapen.
+ * 3. The delta notification phase where delta notifications happen.
+ *
+ * The readyEvent runs the first two steps of the delta cycle. It first goes
+ * through the list of runnable processes and executes them until the set is
+ * empty, and then immediately runs the update phase. Since these are all part
+ * of the same event, there's no chance for other events to intervene and
+ * break the required order above.
+ *
+ * During the update phase above, the spec forbids any action which would make
+ * a process runnable. That means that once the update phase finishes, the set
+ * of runnable processes will be empty. There may, however, have been some
+ * delta notifications/timeouts which will have been scheduled during either
+ * the evaluate or update phase above. Because those are scheduled at the
+ * normal priority, they will now happen together until there aren't any
+ * delta events left.
+ *
+ * If any processes became runnable during the delta notification phase, the
+ * readyEvent will have been scheduled and will have been waiting patiently
+ * behind the delta notification events. That will now run, effectively
+ * starting the next delta cycle.
+ *
+ * TIMED NOTIFICATION PHASE
+ *
+ * If no processes became runnable, the event queue will continue to process
+ * events until it comes across a timed notification, aka a notification
+ * scheduled to happen in the future. Like delta notification events, those
+ * will all happen together since the readyEvent priority is lower,
+ * potentially marking new processes as ready. Once these events finish, the
+ * readyEvent may run, starting the next delta cycle.
+ */
class Scheduler
{
public:
Scheduler();
+ const std::string name() const { return "systemc_scheduler"; }
+
uint64_t numCycles() { return _numCycles; }
Process *current() { return _current; }
- // Run the initialization phase.
- void initialize();
-
- // Run delta cycles until time needs to advance.
- void runCycles();
+ // Mark processes that need to be initialized as ready.
+ void initToReady();
// Put a process on the list of processes to be initialized.
void init(Process *p) { initList.pushLast(p); }
@@ -59,15 +125,10 @@ class Scheduler
void yield();
// Put a process on the ready list.
- void
- ready(Process *p)
- {
- // Clump methods together to minimize context switching.
- if (p->procKind() == ::sc_core::SC_METHOD_PROC_)
- readyList.pushFirst(p);
- else
- readyList.pushLast(p);
- }
+ void ready(Process *p);
+
+ // Schedule an update for a given channel.
+ void requestUpdate(Channel *c);
// Run the given process immediately, preempting whatever may be running.
void
@@ -81,7 +142,22 @@ class Scheduler
yield();
}
+ // Set an event queue for scheduling events.
+ void setEventQueue(EventQueue *_eq) { eq = _eq; }
+
+ // Retrieve the event queue.
+ EventQueue &eventQueue() const { return *eq; }
+
+ // Run scheduled channel updates.
+ void update();
+
private:
+ EventQueue *eq;
+
+ void runReady();
+ EventWrapper<Scheduler, &Scheduler::runReady> readyEvent;
+ void scheduleReadyEvent();
+
uint64_t _numCycles;
Process *_current;
@@ -89,9 +165,7 @@ class Scheduler
ProcessList initList;
ProcessList readyList;
- void evaluate();
- void update();
- void delta();
+ ChannelList updateList;
};
extern Scheduler scheduler;