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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user