systemc: Implement pending activity related functions
authorGabe Black <gabeblack@google.com>
Thu, 19 Jul 2018 03:59:56 +0000 (20:59 -0700)
committerGabe Black <gabeblack@google.com>
Wed, 5 Sep 2018 06:09:21 +0000 (06:09 +0000)
Track the number of notifications/timeouts that are scheduled at any
given time. This lets us implement sc_pending_activity_at_current_time,
sc_pending_activity_at_future_time, and sc_time_to_pending_activity.

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

src/systemc/core/event.cc
src/systemc/core/event.hh
src/systemc/core/process.cc
src/systemc/core/process.hh
src/systemc/core/sc_main.cc
src/systemc/core/scheduler.cc
src/systemc/core/scheduler.hh

index 5008074f640c1096c2c946a30640dd864f19f3c5..1623cf9e867a797c76e3066642a4e919baef4d79 100644 (file)
@@ -43,7 +43,7 @@ namespace sc_gem5
 Event::Event(sc_core::sc_event *_sc_event) : Event(_sc_event, "") {}
 
 Event::Event(sc_core::sc_event *_sc_event, const char *_basename) :
-    _sc_event(_sc_event), _basename(_basename), delayedNotify(this)
+    _sc_event(_sc_event), _basename(_basename), delayedNotifyEvent(this)
 {
     Module *p = currentModule();
 
@@ -120,29 +120,35 @@ Event::notify()
         s->notify(this);
 }
 
+void
+Event::delayedNotify()
+{
+    scheduler.eventHappened();
+    notify();
+}
+
 void
 Event::notify(const sc_core::sc_time &t)
 {
     //XXX We're assuming the systemc time resolution is in ps.
-    Tick new_tick = t.value() * SimClock::Int::ps +
-        scheduler.eventQueue().getCurTick();
-    if (delayedNotify.scheduled()) {
-        Tick old_tick = delayedNotify.when();
+    Tick new_tick = t.value() * SimClock::Int::ps + scheduler.getCurTick();
+    if (delayedNotifyEvent.scheduled()) {
+        Tick old_tick = delayedNotifyEvent.when();
 
         if (new_tick >= old_tick)
             return;
 
-        scheduler.eventQueue().deschedule(&delayedNotify);
+        scheduler.deschedule(&delayedNotifyEvent);
     }
 
-    scheduler.eventQueue().schedule(&delayedNotify, new_tick);
+    scheduler.schedule(&delayedNotifyEvent, new_tick);
 }
 
 void
 Event::cancel()
 {
-    if (delayedNotify.scheduled())
-        scheduler.eventQueue().deschedule(&delayedNotify);
+    if (delayedNotifyEvent.scheduled())
+        scheduler.deschedule(&delayedNotifyEvent);
 }
 
 bool
index a9d318382cf9978c7af0236491ec505fb97afcd4..6d2f46d4218cd593aa3b872dee7eb3727edd906d 100644 (file)
@@ -105,7 +105,8 @@ class Event
     sc_core::sc_object *parent;
     EventsIt parentIt;
 
-    EventWrapper<Event, &Event::notify> delayedNotify;
+    void delayedNotify();
+    EventWrapper<Event, &Event::delayedNotify> delayedNotifyEvent;
 
     mutable std::set<Sensitivity *> sensitivities;
 };
index 7ed187fe1c9034cc8b9561ab14a6387c85828ab7..ad297a23c789c2c7d36decc6d597326361547a96 100644 (file)
@@ -37,16 +37,23 @@ namespace sc_gem5
 {
 
 SensitivityTimeout::SensitivityTimeout(Process *p, ::sc_core::sc_time t) :
-    Sensitivity(p), timeoutEvent(this), timeout(t)
+    Sensitivity(p), timeoutEvent(this), time(t)
 {
-    Tick when = scheduler.eventQueue().getCurTick() + timeout.value();
-    scheduler.eventQueue().schedule(&timeoutEvent, when);
+    Tick when = scheduler.getCurTick() + time.value();
+    scheduler.schedule(&timeoutEvent, when);
 }
 
 SensitivityTimeout::~SensitivityTimeout()
 {
     if (timeoutEvent.scheduled())
-        scheduler.eventQueue().deschedule(&timeoutEvent);
+        scheduler.deschedule(&timeoutEvent);
+}
+
+void
+SensitivityTimeout::timeout()
+{
+    scheduler.eventHappened();
+    notify();
 }
 
 SensitivityEvent::SensitivityEvent(
index 7c75d6244cec0727674d61dbbe5fc1177b3cb102..afdbb379869e2f7491dd59a6a94a5a95940bcf46 100644 (file)
@@ -66,8 +66,10 @@ class Sensitivity
 class SensitivityTimeout : virtual public Sensitivity
 {
   private:
-    EventWrapper<Sensitivity, &Sensitivity::notify> timeoutEvent;
-    ::sc_core::sc_time timeout;
+    void timeout();
+    EventWrapper<SensitivityTimeout,
+        &SensitivityTimeout::timeout> timeoutEvent;
+    ::sc_core::sc_time time;
 
   public:
     SensitivityTimeout(Process *p, ::sc_core::sc_time t);
@@ -98,7 +100,7 @@ class SensitivityEventAndList : virtual public Sensitivity
             Process *p, const ::sc_core::sc_event_and_list *list);
     ~SensitivityEventAndList();
 
-    virtual void notifyWork(Event *e) override;
+    void notifyWork(Event *e) override;
 };
 
 class SensitivityEventOrList : virtual public Sensitivity
index 120bbf9ae1751ee2c2c0b19a79389c05dfb2c3a4..103b3032fbf0d4ca183f4917f5d196b4c4d41ae6 100644 (file)
@@ -140,7 +140,7 @@ sc_argv()
 void
 sc_start()
 {
-    Tick now = curEventQueue() ? curEventQueue()->getCurTick() : 0;
+    Tick now = ::sc_gem5::scheduler.getCurTick();
     sc_start(sc_time::from_value(MaxTick - now), SC_EXIT_ON_STARVATION);
 }
 
@@ -156,7 +156,7 @@ sc_start(const sc_time &time, sc_starvation_policy p)
 {
     _status = SC_RUNNING;
 
-    Tick now = curEventQueue() ? curEventQueue()->getCurTick() : 0;
+    Tick now = ::sc_gem5::scheduler.getCurTick();
     ::sc_gem5::scheduler.start(now + time.value(), p == SC_RUN_TO_TIME);
 
     if (::sc_gem5::scheduler.paused())
@@ -200,7 +200,7 @@ const sc_time &
 sc_time_stamp()
 {
     static sc_time tstamp;
-    Tick tick = sc_gem5::scheduler.eventQueue().getCurTick();
+    Tick tick = ::sc_gem5::scheduler.getCurTick();
     //XXX We're assuming the systemc time resolution is in ps.
     tstamp = sc_time::from_value(tick / SimClock::Int::ps);
     return tstamp;
@@ -221,15 +221,13 @@ sc_is_running()
 bool
 sc_pending_activity_at_current_time()
 {
-    warn("%s not implemented.\n", __PRETTY_FUNCTION__);
-    return false;
+    return ::sc_gem5::scheduler.pendingCurr();
 }
 
 bool
 sc_pending_activity_at_future_time()
 {
-    warn("%s not implemented.\n", __PRETTY_FUNCTION__);
-    return false;
+    return ::sc_gem5::scheduler.pendingFuture();
 }
 
 bool
@@ -242,8 +240,7 @@ sc_pending_activity()
 sc_time
 sc_time_to_pending_activity()
 {
-    warn("%s not implemented.\n", __PRETTY_FUNCTION__);
-    return sc_time();
+    return sc_time::from_value(::sc_gem5::scheduler.timeToPending());
 }
 
 sc_status
index e3d275bb1ddf618f1f1d90d6c528c2cd95c517bd..eab6f482ce28f383ca3c2189a189157e64d78ed1 100644 (file)
@@ -37,8 +37,7 @@ namespace sc_gem5
 {
 
 Scheduler::Scheduler() :
-    eq(nullptr), _pendingCurr(0), _pendingFuture(0),
-    readyEvent(this, false, ReadyPriority),
+    eq(nullptr), readyEvent(this, false, ReadyPriority),
     pauseEvent(this, false, PausePriority),
     stopEvent(this, false, StopPriority),
     scMain(nullptr), _started(false), _paused(false), _stopped(false),
index 5db5556ae5fb29de028d9db9f47412b98f667dd9..3ac7f419f7d293e1267aaf6d09df8151c38c935b 100644 (file)
@@ -179,8 +179,75 @@ class Scheduler
     // Set an event queue for scheduling events.
     void setEventQueue(EventQueue *_eq) { eq = _eq; }
 
-    // Retrieve the event queue.
-    EventQueue &eventQueue() const { return *eq; }
+    // Get the current time according to gem5.
+    Tick getCurTick() { return eq ? eq->getCurTick() : 0; }
+
+    // For scheduling delayed/timed notifications/timeouts.
+    void
+    schedule(::Event *event, Tick tick)
+    {
+        pendingTicks[tick]++;
+        eq->schedule(event, tick);
+    }
+
+    // For descheduling delayed/timed notifications/timeouts.
+    void
+    deschedule(::Event *event)
+    {
+        auto it = pendingTicks.find(event->when());
+        if (--it->second == 0)
+            pendingTicks.erase(it);
+        eq->deschedule(event);
+    }
+
+    // Tell the scheduler than an event fired for bookkeeping purposes.
+    void
+    eventHappened()
+    {
+        auto it = pendingTicks.begin();
+        if (--it->second == 0)
+            pendingTicks.erase(it);
+    }
+
+    // Pending activity ignores gem5 activity, much like how a systemc
+    // simulation wouldn't know about asynchronous external events (socket IO
+    // for instance) that might happen before time advances in a pure
+    // systemc simulation. Also the spec lists what specific types of pending
+    // activity needs to be counted, which obviously doesn't include gem5
+    // events.
+
+    // Return whether there's pending systemc activity at this time.
+    bool
+    pendingCurr()
+    {
+        if (!readyList.empty() || !updateList.empty())
+            return true;
+        return pendingTicks.size() &&
+            pendingTicks.begin()->first == getCurTick();
+    }
+
+    // Return whether there are pending timed notifications or timeouts.
+    bool
+    pendingFuture()
+    {
+        switch (pendingTicks.size()) {
+          case 0: return false;
+          case 1: return pendingTicks.begin()->first > getCurTick();
+          default: return true;
+        }
+    }
+
+    // Return how many ticks there are until the first pending event, if any.
+    Tick
+    timeToPending()
+    {
+        if (!readyList.empty() || !updateList.empty())
+            return 0;
+        else if (pendingTicks.size())
+            return pendingTicks.begin()->first - getCurTick();
+        else
+            return MaxTick - getCurTick();
+    }
 
     // Run scheduled channel updates.
     void update();
@@ -205,6 +272,7 @@ class Scheduler
     static Priority MaxTickPriority = DefaultPriority + 3;
 
     EventQueue *eq;
+    std::map<Tick, int> pendingTicks;
 
     void runReady();
     EventWrapper<Scheduler, &Scheduler::runReady> readyEvent;