diff options
-rw-r--r-- | src/systemc/core/scheduler.cc | 63 | ||||
-rw-r--r-- | src/systemc/core/scheduler.hh | 20 |
2 files changed, 54 insertions, 29 deletions
diff --git a/src/systemc/core/scheduler.cc b/src/systemc/core/scheduler.cc index cf34fe8b7..78b47cd4d 100644 --- a/src/systemc/core/scheduler.cc +++ b/src/systemc/core/scheduler.cc @@ -47,7 +47,7 @@ Scheduler::Scheduler() : _started(false), _paused(false), _stopped(false), _stopNow(false), maxTickEvent(this, false, MaxTickPriority), _numCycles(0), _changeStamp(0), _current(nullptr), initDone(false), - runOnce(false) + runOnce(false), readyList(nullptr) {} Scheduler::~Scheduler() @@ -90,7 +90,9 @@ Scheduler::clear() p->popListNode(); while ((p = initList.getNext())) p->popListNode(); - while ((p = readyList.getNext())) + while ((p = readyListMethods.getNext())) + p->popListNode(); + while ((p = readyListThreads.getNext())) p->popListNode(); Channel *c; @@ -162,7 +164,8 @@ Scheduler::dontInitialize(Process *p) void Scheduler::yield() { - _current = readyList.getNext(); + // Pull a process from the active list. + _current = readyList->getNext(); if (!_current) { // There are no more processes, so return control to evaluate. Fiber::primaryFiber()->run(); @@ -192,13 +195,10 @@ Scheduler::ready(Process *p) if (_stopNow) return; - // Clump methods together to minimize context switching. - static bool cluster_methods = false; - - if (cluster_methods && p->procKind() == ::sc_core::SC_METHOD_PROC_) - readyList.pushFirst(p); + if (p->procKind() == ::sc_core::SC_METHOD_PROC_) + readyListMethods.pushLast(p); else - readyList.pushLast(p); + readyListThreads.pushLast(p); scheduleReadyEvent(); } @@ -213,27 +213,31 @@ Scheduler::resume(Process *p) } bool +listContains(ListNode *list, ListNode *target) +{ + ListNode *n = list->nextListNode; + while (n != list) + if (n == target) + return true; + return false; +} + +bool Scheduler::suspend(Process *p) { + bool was_ready; if (initDone) { // After initialization, the only list we can be on is the ready list. - bool was_ready = (p->nextListNode != nullptr); + was_ready = (p->nextListNode != nullptr); p->popListNode(); - return was_ready; } else { - bool was_ready = false; - // Check the ready list to see if we find this process. - ListNode *n = readyList.nextListNode; - while (n != &readyList) { - if (n == p) { - was_ready = true; - break; - } - } + // Check the ready lists to see if we find this process. + was_ready = listContains(&readyListMethods, p) || + listContains(&readyListThreads, p); if (was_ready) toFinalize.pushLast(p); - return was_ready; } + return was_ready; } void @@ -267,13 +271,24 @@ Scheduler::scheduleStarvationEvent() void Scheduler::runReady() { - bool empty = readyList.empty(); + bool empty = readyListMethods.empty() && readyListThreads.empty(); lastReadyTick = getCurTick(); // The evaluation phase. do { - yield(); - } while (!readyList.empty()); + // We run methods and threads in two seperate passes to emulate how + // Accellera orders things, but without having to scan through a + // unified list to find the next process of the correct type. + readyList = &readyListMethods; + while (!readyListMethods.empty()) + yield(); + + readyList = &readyListThreads; + while (!readyListThreads.empty()) + yield(); + + // We already know that readyListThreads is empty at this point. + } while (!readyListMethods.empty()); if (!empty) { _numCycles++; diff --git a/src/systemc/core/scheduler.hh b/src/systemc/core/scheduler.hh index f0cbac43c..29501bc24 100644 --- a/src/systemc/core/scheduler.hh +++ b/src/systemc/core/scheduler.hh @@ -197,11 +197,16 @@ class Scheduler void runNow(Process *p) { + // This function may put a process on the wrong list, ie a method on + // the process list or vice versa. That's fine since that's just a + // performance optimization, and the important thing here is how the + // processes are ordered. + // If a process is running, schedule it/us to run again. if (_current) - readyList.pushFirst(_current); + readyList->pushFirst(_current); // Schedule p to run first. - readyList.pushFirst(p); + readyList->pushFirst(p); yield(); } @@ -290,7 +295,8 @@ class Scheduler bool pendingCurr() { - return !readyList.empty() || !updateList.empty() || !deltas.empty(); + return !readyListMethods.empty() || !readyListThreads.empty() || + !updateList.empty() || !deltas.empty(); } // Return whether there are pending timed notifications or timeouts. @@ -376,7 +382,8 @@ class Scheduler bool starved() { - return (readyList.empty() && updateList.empty() && deltas.empty() && + return (readyListMethods.empty() && readyListThreads.empty() && + updateList.empty() && deltas.empty() && (timeSlots.empty() || timeSlots.begin()->first > maxTick) && initList.empty()); } @@ -410,7 +417,10 @@ class Scheduler ProcessList initList; ProcessList toFinalize; - ProcessList readyList; + + ProcessList *readyList; + ProcessList readyListMethods; + ProcessList readyListThreads; ChannelList updateList; |