systemc: Implement the SC_EXIT_ON_STARVATION exit mode.
authorGabe Black <gabeblack@google.com>
Fri, 20 Jul 2018 23:28:54 +0000 (16:28 -0700)
committerGabe Black <gabeblack@google.com>
Tue, 11 Sep 2018 21:42:55 +0000 (21:42 +0000)
This mode implies checking whether there's any activity left either
before starting a delta cycle, or processing delta or timed
notification or timeout.

Change-Id: I0780a1f720cf63f3d2907b8dd28685266b52d6b4
Reviewed-on: https://gem5-review.googlesource.com/12038
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Gabe Black <gabeblack@google.com>

src/systemc/core/scheduler.cc
src/systemc/core/scheduler.hh

index 5174627d0854c9f16688bb7686d8953bb7ea314b..c2b5ec38d605abe57dd355fce54a35321caa05b5 100644 (file)
@@ -42,7 +42,9 @@ Scheduler::Scheduler() :
     eq(nullptr), readyEvent(this, false, ReadyPriority),
     pauseEvent(this, false, PausePriority),
     stopEvent(this, false, StopPriority),
-    scMain(nullptr), _started(false), _paused(false), _stopped(false),
+    scMain(nullptr),
+    starvationEvent(this, false, StarvationPriority),
+    _started(false), _paused(false), _stopped(false),
     maxTickEvent(this, false, MaxTickPriority),
     _numCycles(0), _current(nullptr), initReady(false)
 {}
@@ -143,6 +145,20 @@ Scheduler::scheduleReadyEvent()
     if (!readyEvent.scheduled()) {
         panic_if(!eq, "Need to schedule ready, but no event manager.\n");
         eq->schedule(&readyEvent, eq->getCurTick());
+        if (starvationEvent.scheduled())
+            eq->deschedule(&starvationEvent);
+    }
+}
+
+void
+Scheduler::scheduleStarvationEvent()
+{
+    if (!starvationEvent.scheduled()) {
+        panic_if(!eq, "Need to schedule starvation event, "
+                "but no event manager.\n");
+        eq->schedule(&starvationEvent, eq->getCurTick());
+        if (readyEvent.scheduled())
+            eq->deschedule(&readyEvent);
     }
 }
 
@@ -162,6 +178,9 @@ Scheduler::runReady()
     // The update phase.
     update();
 
+    if (starved() && !runToTime)
+        scheduleStarvationEvent();
+
     // The delta phase will happen naturally through the event queue.
 }
 
@@ -202,9 +221,13 @@ Scheduler::start(Tick max_tick, bool run_to_time)
     _started = true;
     _paused = false;
     _stopped = false;
+    runToTime = run_to_time;
 
     maxTick = max_tick;
 
+    if (starved() && !runToTime)
+        return;
+
     if (initReady) {
         kernel->status(::sc_core::SC_RUNNING);
         eq->schedule(&maxTickEvent, maxTick);
@@ -219,6 +242,8 @@ Scheduler::start(Tick max_tick, bool run_to_time)
         eq->deschedule(&stopEvent);
     if (maxTickEvent.scheduled())
         eq->deschedule(&maxTickEvent);
+    if (starvationEvent.scheduled())
+        eq->deschedule(&starvationEvent);
 }
 
 void
index 73d660e9e800e9319de13a1c5cf6edc2b9f7f3ec..0c755eda47a7ac3332f3c749cf4a26aacfa4a10a 100644 (file)
@@ -215,6 +215,9 @@ class Scheduler
         auto it = pendingTicks.begin();
         if (--it->second == 0)
             pendingTicks.erase(it);
+
+        if (starved() && !runToTime)
+            scheduleStarvationEvent();
     }
 
     // Pending activity ignores gem5 activity, much like how a systemc
@@ -277,6 +280,7 @@ class Scheduler
     static Priority StopPriority = DefaultPriority - 1;
     static Priority PausePriority = DefaultPriority + 1;
     static Priority ReadyPriority = DefaultPriority + 2;
+    static Priority StarvationPriority = ReadyPriority;
     static Priority MaxTickPriority = DefaultPriority + 3;
 
     EventQueue *eq;
@@ -292,6 +296,17 @@ class Scheduler
     EventWrapper<Scheduler, &Scheduler::stop> stopEvent;
     Fiber *scMain;
 
+    bool
+    starved()
+    {
+        return (readyList.empty() && updateList.empty() &&
+                (pendingTicks.empty() ||
+                 pendingTicks.begin()->first > maxTick) &&
+                initList.empty());
+    }
+    EventWrapper<Scheduler, &Scheduler::pause> starvationEvent;
+    void scheduleStarvationEvent();
+
     bool _started;
     bool _paused;
     bool _stopped;
@@ -304,6 +319,7 @@ class Scheduler
     Process *_current;
 
     bool initReady;
+    bool runToTime;
 
     ProcessList initList;
     ProcessList toFinalize;