systemc: Implement pending activity related functions

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>
This commit is contained in:
Gabe Black
2018-07-18 20:59:56 -07:00
parent 91a6b12819
commit 743a1b5cdd
7 changed files with 110 additions and 30 deletions

View 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

View 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;
};

View 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(

View 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

View 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

View 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),

View 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;