scheduler.cc revision 13072
112953Sgabeblack@google.com/* 212953Sgabeblack@google.com * Copyright 2018 Google, Inc. 312953Sgabeblack@google.com * 412953Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 512953Sgabeblack@google.com * modification, are permitted provided that the following conditions are 612953Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 712953Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 812953Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 912953Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 1012953Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 1112953Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 1212953Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 1312953Sgabeblack@google.com * this software without specific prior written permission. 1412953Sgabeblack@google.com * 1512953Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1612953Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1712953Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1812953Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1912953Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2012953Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2112953Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2212953Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2312953Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2412953Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2512953Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2612953Sgabeblack@google.com * 2712953Sgabeblack@google.com * Authors: Gabe Black 2812953Sgabeblack@google.com */ 2912953Sgabeblack@google.com 3012953Sgabeblack@google.com#include "systemc/core/scheduler.hh" 3112953Sgabeblack@google.com 3212953Sgabeblack@google.com#include "base/fiber.hh" 3312954Sgabeblack@google.com#include "base/logging.hh" 3412954Sgabeblack@google.com#include "sim/eventq.hh" 3512982Sgabeblack@google.com#include "systemc/core/kernel.hh" 3612982Sgabeblack@google.com#include "systemc/ext/core/sc_main.hh" 3712953Sgabeblack@google.com 3812953Sgabeblack@google.comnamespace sc_gem5 3912953Sgabeblack@google.com{ 4012953Sgabeblack@google.com 4112954Sgabeblack@google.comScheduler::Scheduler() : 4212962Sgabeblack@google.com eq(nullptr), readyEvent(this, false, ReadyPriority), 4312961Sgabeblack@google.com pauseEvent(this, false, PausePriority), 4412961Sgabeblack@google.com stopEvent(this, false, StopPriority), 4512987Sgabeblack@google.com scMain(nullptr), 4612987Sgabeblack@google.com starvationEvent(this, false, StarvationPriority), 4712987Sgabeblack@google.com _started(false), _paused(false), _stopped(false), 4812961Sgabeblack@google.com maxTickEvent(this, false, MaxTickPriority), 4913067Sgabeblack@google.com _numCycles(0), _current(nullptr), initDone(false), 5013061Sgabeblack@google.com runOnce(false) 5112954Sgabeblack@google.com{} 5212953Sgabeblack@google.com 5313072Sgabeblack@google.comScheduler::~Scheduler() 5413072Sgabeblack@google.com{ 5513072Sgabeblack@google.com // Clear out everything that belongs to us to make sure nobody tries to 5613072Sgabeblack@google.com // clear themselves out after the scheduler goes away. 5713072Sgabeblack@google.com 5813072Sgabeblack@google.com // Delta notifications. 5913072Sgabeblack@google.com for (auto &e: deltas) 6013072Sgabeblack@google.com e->deschedule(); 6113072Sgabeblack@google.com 6213072Sgabeblack@google.com // Timed notifications. 6313072Sgabeblack@google.com for (auto &ts: timeSlots) { 6413072Sgabeblack@google.com for (auto &e: ts.second->events) 6513072Sgabeblack@google.com e->deschedule(); 6613072Sgabeblack@google.com delete ts.second; 6713072Sgabeblack@google.com ts.second = nullptr; 6813072Sgabeblack@google.com } 6913072Sgabeblack@google.com 7013072Sgabeblack@google.com // gem5 events. 7113072Sgabeblack@google.com if (readyEvent.scheduled()) 7213072Sgabeblack@google.com eq->deschedule(&readyEvent); 7313072Sgabeblack@google.com if (pauseEvent.scheduled()) 7413072Sgabeblack@google.com eq->deschedule(&pauseEvent); 7513072Sgabeblack@google.com if (stopEvent.scheduled()) 7613072Sgabeblack@google.com eq->deschedule(&stopEvent); 7713072Sgabeblack@google.com if (starvationEvent.scheduled()) 7813072Sgabeblack@google.com eq->deschedule(&starvationEvent); 7913072Sgabeblack@google.com if (maxTickEvent.scheduled()) 8013072Sgabeblack@google.com eq->deschedule(&maxTickEvent); 8113072Sgabeblack@google.com 8213072Sgabeblack@google.com Process *p; 8313072Sgabeblack@google.com while ((p = toFinalize.getNext())) 8413072Sgabeblack@google.com p->popListNode(); 8513072Sgabeblack@google.com while ((p = initList.getNext())) 8613072Sgabeblack@google.com p->popListNode(); 8713072Sgabeblack@google.com while ((p = readyList.getNext())) 8813072Sgabeblack@google.com p->popListNode(); 8913072Sgabeblack@google.com 9013072Sgabeblack@google.com Channel *c; 9113072Sgabeblack@google.com while ((c = updateList.getNext())) 9213072Sgabeblack@google.com c->popListNode(); 9313072Sgabeblack@google.com} 9413072Sgabeblack@google.com 9512953Sgabeblack@google.comvoid 9613067Sgabeblack@google.comScheduler::initPhase() 9712953Sgabeblack@google.com{ 9812957Sgabeblack@google.com for (Process *p = toFinalize.getNext(); p; p = toFinalize.getNext()) { 9912957Sgabeblack@google.com p->finalize(); 10012957Sgabeblack@google.com p->popListNode(); 10112957Sgabeblack@google.com } 10212957Sgabeblack@google.com 10312957Sgabeblack@google.com for (Process *p = initList.getNext(); p; p = initList.getNext()) { 10412957Sgabeblack@google.com p->finalize(); 10512996Sgabeblack@google.com p->popListNode(); 10612959Sgabeblack@google.com p->ready(); 10712957Sgabeblack@google.com } 10812957Sgabeblack@google.com 10913067Sgabeblack@google.com update(); 11013067Sgabeblack@google.com 11113067Sgabeblack@google.com for (auto &e: deltas) 11213067Sgabeblack@google.com e->run(); 11313067Sgabeblack@google.com deltas.clear(); 11413067Sgabeblack@google.com 11512985Sgabeblack@google.com for (auto ets: eventsToSchedule) 11612985Sgabeblack@google.com eq->schedule(ets.first, ets.second); 11712985Sgabeblack@google.com eventsToSchedule.clear(); 11812985Sgabeblack@google.com 11913068Sgabeblack@google.com if (_started) { 12013068Sgabeblack@google.com if (starved() && !runToTime) 12113068Sgabeblack@google.com scheduleStarvationEvent(); 12213069Sgabeblack@google.com kernel->status(::sc_core::SC_RUNNING); 12313068Sgabeblack@google.com } 12412961Sgabeblack@google.com 12513067Sgabeblack@google.com initDone = true; 12612957Sgabeblack@google.com} 12712957Sgabeblack@google.com 12812957Sgabeblack@google.comvoid 12912957Sgabeblack@google.comScheduler::reg(Process *p) 13012957Sgabeblack@google.com{ 13113067Sgabeblack@google.com if (initDone) { 13212957Sgabeblack@google.com // If we're past initialization, finalize static sensitivity. 13312957Sgabeblack@google.com p->finalize(); 13412957Sgabeblack@google.com // Mark the process as ready. 13512959Sgabeblack@google.com p->ready(); 13612957Sgabeblack@google.com } else { 13712957Sgabeblack@google.com // Otherwise, record that this process should be initialized once we 13812957Sgabeblack@google.com // get there. 13912957Sgabeblack@google.com initList.pushLast(p); 14012957Sgabeblack@google.com } 14112957Sgabeblack@google.com} 14212957Sgabeblack@google.com 14312957Sgabeblack@google.comvoid 14412957Sgabeblack@google.comScheduler::dontInitialize(Process *p) 14512957Sgabeblack@google.com{ 14613067Sgabeblack@google.com if (initDone) { 14712957Sgabeblack@google.com // Pop this process off of the ready list. 14812957Sgabeblack@google.com p->popListNode(); 14912957Sgabeblack@google.com } else { 15012957Sgabeblack@google.com // Push this process onto the list of processes which still need 15112957Sgabeblack@google.com // their static sensitivity to be finalized. That implicitly pops it 15212957Sgabeblack@google.com // off the list of processes to be initialized/marked ready. 15312957Sgabeblack@google.com toFinalize.pushLast(p); 15412957Sgabeblack@google.com } 15512953Sgabeblack@google.com} 15612953Sgabeblack@google.com 15712953Sgabeblack@google.comvoid 15812953Sgabeblack@google.comScheduler::yield() 15912953Sgabeblack@google.com{ 16012953Sgabeblack@google.com _current = readyList.getNext(); 16112953Sgabeblack@google.com if (!_current) { 16212953Sgabeblack@google.com // There are no more processes, so return control to evaluate. 16312953Sgabeblack@google.com Fiber::primaryFiber()->run(); 16412953Sgabeblack@google.com } else { 16512953Sgabeblack@google.com _current->popListNode(); 16612953Sgabeblack@google.com // Switch to whatever Fiber is supposed to run this process. All 16712953Sgabeblack@google.com // Fibers which aren't running should be parked at this line. 16812953Sgabeblack@google.com _current->fiber()->run(); 16912961Sgabeblack@google.com // If the current process needs to be manually started, start it. 17012961Sgabeblack@google.com if (_current && _current->needsStart()) 17112953Sgabeblack@google.com _current->run(); 17212953Sgabeblack@google.com } 17312995Sgabeblack@google.com if (_current && _current->excWrapper) { 17412995Sgabeblack@google.com // Make sure this isn't a method process. 17512995Sgabeblack@google.com assert(!_current->needsStart()); 17612995Sgabeblack@google.com auto ew = _current->excWrapper; 17712995Sgabeblack@google.com _current->excWrapper = nullptr; 17812995Sgabeblack@google.com ew->throw_it(); 17912995Sgabeblack@google.com } 18012953Sgabeblack@google.com} 18112953Sgabeblack@google.com 18212953Sgabeblack@google.comvoid 18312954Sgabeblack@google.comScheduler::ready(Process *p) 18412953Sgabeblack@google.com{ 18512954Sgabeblack@google.com // Clump methods together to minimize context switching. 18612954Sgabeblack@google.com if (p->procKind() == ::sc_core::SC_METHOD_PROC_) 18712954Sgabeblack@google.com readyList.pushFirst(p); 18812954Sgabeblack@google.com else 18912954Sgabeblack@google.com readyList.pushLast(p); 19012953Sgabeblack@google.com 19112954Sgabeblack@google.com scheduleReadyEvent(); 19212954Sgabeblack@google.com} 19312954Sgabeblack@google.com 19412954Sgabeblack@google.comvoid 19512954Sgabeblack@google.comScheduler::requestUpdate(Channel *c) 19612954Sgabeblack@google.com{ 19712954Sgabeblack@google.com updateList.pushLast(c); 19813069Sgabeblack@google.com scheduleReadyEvent(); 19912954Sgabeblack@google.com} 20012954Sgabeblack@google.com 20112954Sgabeblack@google.comvoid 20212954Sgabeblack@google.comScheduler::scheduleReadyEvent() 20312954Sgabeblack@google.com{ 20412954Sgabeblack@google.com // Schedule the evaluate and update phases. 20512954Sgabeblack@google.com if (!readyEvent.scheduled()) { 20613069Sgabeblack@google.com schedule(&readyEvent); 20712987Sgabeblack@google.com if (starvationEvent.scheduled()) 20813069Sgabeblack@google.com deschedule(&starvationEvent); 20912987Sgabeblack@google.com } 21012987Sgabeblack@google.com} 21112987Sgabeblack@google.com 21212987Sgabeblack@google.comvoid 21312987Sgabeblack@google.comScheduler::scheduleStarvationEvent() 21412987Sgabeblack@google.com{ 21512987Sgabeblack@google.com if (!starvationEvent.scheduled()) { 21613069Sgabeblack@google.com schedule(&starvationEvent); 21712987Sgabeblack@google.com if (readyEvent.scheduled()) 21813069Sgabeblack@google.com deschedule(&readyEvent); 21912954Sgabeblack@google.com } 22012954Sgabeblack@google.com} 22112954Sgabeblack@google.com 22212954Sgabeblack@google.comvoid 22312954Sgabeblack@google.comScheduler::runReady() 22412954Sgabeblack@google.com{ 22512954Sgabeblack@google.com bool empty = readyList.empty(); 22612954Sgabeblack@google.com 22712954Sgabeblack@google.com // The evaluation phase. 22812953Sgabeblack@google.com do { 22912953Sgabeblack@google.com yield(); 23012953Sgabeblack@google.com } while (!readyList.empty()); 23112954Sgabeblack@google.com 23212954Sgabeblack@google.com if (!empty) 23312954Sgabeblack@google.com _numCycles++; 23412954Sgabeblack@google.com 23512954Sgabeblack@google.com // The update phase. 23612954Sgabeblack@google.com update(); 23712954Sgabeblack@google.com 23812987Sgabeblack@google.com if (starved() && !runToTime) 23912987Sgabeblack@google.com scheduleStarvationEvent(); 24012987Sgabeblack@google.com 24113063Sgabeblack@google.com // The delta phase. 24213063Sgabeblack@google.com for (auto &e: deltas) 24313063Sgabeblack@google.com e->run(); 24413063Sgabeblack@google.com deltas.clear(); 24513061Sgabeblack@google.com 24613064Sgabeblack@google.com if (runOnce) 24713064Sgabeblack@google.com schedulePause(); 24812953Sgabeblack@google.com} 24912953Sgabeblack@google.com 25012953Sgabeblack@google.comvoid 25112953Sgabeblack@google.comScheduler::update() 25212953Sgabeblack@google.com{ 25312954Sgabeblack@google.com Channel *channel = updateList.getNext(); 25412954Sgabeblack@google.com while (channel) { 25512954Sgabeblack@google.com channel->popListNode(); 25612954Sgabeblack@google.com channel->update(); 25712954Sgabeblack@google.com channel = updateList.getNext(); 25812954Sgabeblack@google.com } 25912953Sgabeblack@google.com} 26012953Sgabeblack@google.com 26112961Sgabeblack@google.comvoid 26212961Sgabeblack@google.comScheduler::pause() 26312961Sgabeblack@google.com{ 26412961Sgabeblack@google.com _paused = true; 26512982Sgabeblack@google.com kernel->status(::sc_core::SC_PAUSED); 26613061Sgabeblack@google.com runOnce = false; 26712961Sgabeblack@google.com scMain->run(); 26812961Sgabeblack@google.com} 26912961Sgabeblack@google.com 27012961Sgabeblack@google.comvoid 27112961Sgabeblack@google.comScheduler::stop() 27212961Sgabeblack@google.com{ 27312961Sgabeblack@google.com _stopped = true; 27412982Sgabeblack@google.com kernel->stop(); 27513061Sgabeblack@google.com runOnce = false; 27612961Sgabeblack@google.com scMain->run(); 27712961Sgabeblack@google.com} 27812961Sgabeblack@google.com 27912961Sgabeblack@google.comvoid 28012961Sgabeblack@google.comScheduler::start(Tick max_tick, bool run_to_time) 28112961Sgabeblack@google.com{ 28212961Sgabeblack@google.com // We should be running from sc_main. Keep track of that Fiber to return 28312961Sgabeblack@google.com // to later. 28412961Sgabeblack@google.com scMain = Fiber::currentFiber(); 28512961Sgabeblack@google.com 28612961Sgabeblack@google.com _started = true; 28712961Sgabeblack@google.com _paused = false; 28812961Sgabeblack@google.com _stopped = false; 28912987Sgabeblack@google.com runToTime = run_to_time; 29012961Sgabeblack@google.com 29112961Sgabeblack@google.com maxTick = max_tick; 29212961Sgabeblack@google.com 29313067Sgabeblack@google.com if (initDone) { 29413068Sgabeblack@google.com if (starved() && !runToTime) 29513068Sgabeblack@google.com scheduleStarvationEvent(); 29612982Sgabeblack@google.com kernel->status(::sc_core::SC_RUNNING); 29712982Sgabeblack@google.com } 29812961Sgabeblack@google.com 29913069Sgabeblack@google.com schedule(&maxTickEvent, maxTick); 30013069Sgabeblack@google.com 30112961Sgabeblack@google.com // Return to gem5 to let it run events, etc. 30212961Sgabeblack@google.com Fiber::primaryFiber()->run(); 30312961Sgabeblack@google.com 30412961Sgabeblack@google.com if (pauseEvent.scheduled()) 30512961Sgabeblack@google.com eq->deschedule(&pauseEvent); 30612961Sgabeblack@google.com if (stopEvent.scheduled()) 30712961Sgabeblack@google.com eq->deschedule(&stopEvent); 30812961Sgabeblack@google.com if (maxTickEvent.scheduled()) 30912961Sgabeblack@google.com eq->deschedule(&maxTickEvent); 31012987Sgabeblack@google.com if (starvationEvent.scheduled()) 31112987Sgabeblack@google.com eq->deschedule(&starvationEvent); 31212961Sgabeblack@google.com} 31312961Sgabeblack@google.com 31412961Sgabeblack@google.comvoid 31513061Sgabeblack@google.comScheduler::oneCycle() 31613061Sgabeblack@google.com{ 31713061Sgabeblack@google.com runOnce = true; 31813061Sgabeblack@google.com start(::MaxTick, false); 31913061Sgabeblack@google.com} 32013061Sgabeblack@google.com 32113061Sgabeblack@google.comvoid 32212961Sgabeblack@google.comScheduler::schedulePause() 32312961Sgabeblack@google.com{ 32412961Sgabeblack@google.com if (pauseEvent.scheduled()) 32512961Sgabeblack@google.com return; 32612961Sgabeblack@google.com 32712961Sgabeblack@google.com eq->schedule(&pauseEvent, eq->getCurTick()); 32812961Sgabeblack@google.com} 32912961Sgabeblack@google.com 33012961Sgabeblack@google.comvoid 33112961Sgabeblack@google.comScheduler::scheduleStop(bool finish_delta) 33212961Sgabeblack@google.com{ 33312961Sgabeblack@google.com if (stopEvent.scheduled()) 33412961Sgabeblack@google.com return; 33512961Sgabeblack@google.com 33612961Sgabeblack@google.com if (!finish_delta) { 33712961Sgabeblack@google.com // If we're not supposed to finish the delta cycle, flush the list 33813064Sgabeblack@google.com // of ready processes, scheduled updates, and delta notifications. 33912961Sgabeblack@google.com Process *p; 34012961Sgabeblack@google.com while ((p = readyList.getNext())) 34112961Sgabeblack@google.com p->popListNode(); 34212961Sgabeblack@google.com Channel *c; 34312961Sgabeblack@google.com while ((c = updateList.getNext())) 34412961Sgabeblack@google.com c->popListNode(); 34513064Sgabeblack@google.com for (auto &e: deltas) 34613064Sgabeblack@google.com e->deschedule(); 34713064Sgabeblack@google.com deltas.clear(); 34812961Sgabeblack@google.com } 34912961Sgabeblack@google.com eq->schedule(&stopEvent, eq->getCurTick()); 35012961Sgabeblack@google.com} 35112961Sgabeblack@google.com 35212953Sgabeblack@google.comScheduler scheduler; 35312953Sgabeblack@google.com 35412953Sgabeblack@google.com} // namespace sc_gem5 355