systemc: use list instead of map in scheduler
The queue in systemC scheduler is implemented as a std::map. This provides the best big-O solution. However, most of simulation usecases has very small number of pending events. This is expected as we usually only trigger a few new events after some events are processed. In such scenario, we should optimize for insert/erase instead of search. This change use std::list instead of std::map. As a proof, we can find that gem5's original event_queue is also implemented as a list instead of tree. We see 5% speed improvement with the example provided by Matthias Jung: https://gist.github.com/myzinsky/557200aa04556de44a317e0a10f51840 Change-Id: I75c30df9134e94df42fd778115cf923488ff5886 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/34515 Reviewed-by: Gabe Black <gabeblack@google.com> Maintainer: Gabe Black <gabeblack@google.com> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
@@ -71,8 +71,7 @@ Scheduler::clear()
|
||||
deltas.front()->deschedule();
|
||||
|
||||
// Timed notifications.
|
||||
for (auto &tsp: timeSlots) {
|
||||
TimeSlot *&ts = tsp.second;
|
||||
for (auto &ts: timeSlots) {
|
||||
while (!ts->events.empty())
|
||||
ts->events.front()->deschedule();
|
||||
deschedule(ts);
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#define __SYSTEMC_CORE_SCHEDULER_HH__
|
||||
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
@@ -151,13 +152,17 @@ class Scheduler
|
||||
class TimeSlot : public ::Event
|
||||
{
|
||||
public:
|
||||
TimeSlot() : ::Event(Default_Pri, AutoDelete) {}
|
||||
|
||||
TimeSlot(const Tick& targeted_when) : ::Event(Default_Pri, AutoDelete),
|
||||
targeted_when(targeted_when) {}
|
||||
// Event::when() is only set after it's scheduled to an event queue.
|
||||
// However, TimeSlot won't be scheduled before init is done. We need
|
||||
// to keep the real 'targeted_when' information before scheduled.
|
||||
Tick targeted_when;
|
||||
ScEvents events;
|
||||
void process();
|
||||
};
|
||||
|
||||
typedef std::map<Tick, TimeSlot *> TimeSlots;
|
||||
typedef std::list<TimeSlot *> TimeSlots;
|
||||
|
||||
Scheduler();
|
||||
~Scheduler();
|
||||
@@ -250,12 +255,14 @@ class Scheduler
|
||||
}
|
||||
|
||||
// Timed notification/timeout.
|
||||
TimeSlot *&ts = timeSlots[tick];
|
||||
if (!ts) {
|
||||
ts = new TimeSlot;
|
||||
schedule(ts, tick);
|
||||
auto it = timeSlots.begin();
|
||||
while (it != timeSlots.end() && (*it)->targeted_when < tick)
|
||||
it++;
|
||||
if (it == timeSlots.end() || (*it)->targeted_when != tick) {
|
||||
it = timeSlots.emplace(it, new TimeSlot(tick));
|
||||
schedule(*it, tick);
|
||||
}
|
||||
event->schedule(ts->events, tick);
|
||||
event->schedule((*it)->events, tick);
|
||||
}
|
||||
|
||||
// For descheduling delayed/timed notifications/timeouts.
|
||||
@@ -270,10 +277,15 @@ class Scheduler
|
||||
}
|
||||
|
||||
// Timed notification/timeout.
|
||||
auto tsit = timeSlots.find(event->when());
|
||||
panic_if(tsit == timeSlots.end(),
|
||||
auto tsit = timeSlots.begin();
|
||||
while (tsit != timeSlots.end() &&
|
||||
(*tsit)->targeted_when < event->when())
|
||||
tsit++;
|
||||
|
||||
panic_if(tsit == timeSlots.end() ||
|
||||
(*tsit)->targeted_when != event->when(),
|
||||
"Descheduling event at time with no events.");
|
||||
TimeSlot *ts = tsit->second;
|
||||
TimeSlot *ts = *tsit;
|
||||
ScEvents &events = ts->events;
|
||||
assert(on == &events);
|
||||
event->deschedule();
|
||||
@@ -288,7 +300,7 @@ class Scheduler
|
||||
void
|
||||
completeTimeSlot(TimeSlot *ts)
|
||||
{
|
||||
assert(ts == timeSlots.begin()->second);
|
||||
assert(ts == timeSlots.front());
|
||||
timeSlots.erase(timeSlots.begin());
|
||||
if (!runToTime && starved())
|
||||
scheduleStarvationEvent();
|
||||
@@ -324,7 +336,7 @@ class Scheduler
|
||||
if (pendingCurr())
|
||||
return 0;
|
||||
if (pendingFuture())
|
||||
return timeSlots.begin()->first - getCurTick();
|
||||
return timeSlots.front()->targeted_when - getCurTick();
|
||||
return MaxTick - getCurTick();
|
||||
}
|
||||
|
||||
@@ -434,7 +446,8 @@ class Scheduler
|
||||
{
|
||||
return (readyListMethods.empty() && readyListThreads.empty() &&
|
||||
updateList.empty() && deltas.empty() &&
|
||||
(timeSlots.empty() || timeSlots.begin()->first > maxTick) &&
|
||||
(timeSlots.empty() ||
|
||||
timeSlots.front()->targeted_when > maxTick) &&
|
||||
initList.empty());
|
||||
}
|
||||
EventWrapper<Scheduler, &Scheduler::pause> starvationEvent;
|
||||
|
||||
Reference in New Issue
Block a user