scheduler.cc revision 13133
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. 5713076Sgabeblack@google.com clear(); 5813076Sgabeblack@google.com} 5913072Sgabeblack@google.com 6013076Sgabeblack@google.comvoid 6113076Sgabeblack@google.comScheduler::clear() 6213076Sgabeblack@google.com{ 6313072Sgabeblack@google.com // Delta notifications. 6413072Sgabeblack@google.com for (auto &e: deltas) 6513072Sgabeblack@google.com e->deschedule(); 6613076Sgabeblack@google.com deltas.clear(); 6713072Sgabeblack@google.com 6813072Sgabeblack@google.com // Timed notifications. 6913076Sgabeblack@google.com for (auto &tsp: timeSlots) { 7013076Sgabeblack@google.com TimeSlot *&ts = tsp.second; 7113076Sgabeblack@google.com for (auto &e: ts->events) 7213072Sgabeblack@google.com e->deschedule(); 7313088Sgabeblack@google.com deschedule(ts); 7413072Sgabeblack@google.com } 7513076Sgabeblack@google.com timeSlots.clear(); 7613072Sgabeblack@google.com 7713072Sgabeblack@google.com // gem5 events. 7813072Sgabeblack@google.com if (readyEvent.scheduled()) 7913088Sgabeblack@google.com deschedule(&readyEvent); 8013072Sgabeblack@google.com if (pauseEvent.scheduled()) 8113088Sgabeblack@google.com deschedule(&pauseEvent); 8213072Sgabeblack@google.com if (stopEvent.scheduled()) 8313088Sgabeblack@google.com deschedule(&stopEvent); 8413072Sgabeblack@google.com if (starvationEvent.scheduled()) 8513088Sgabeblack@google.com deschedule(&starvationEvent); 8613072Sgabeblack@google.com if (maxTickEvent.scheduled()) 8713088Sgabeblack@google.com deschedule(&maxTickEvent); 8813072Sgabeblack@google.com 8913072Sgabeblack@google.com Process *p; 9013072Sgabeblack@google.com while ((p = toFinalize.getNext())) 9113072Sgabeblack@google.com p->popListNode(); 9213072Sgabeblack@google.com while ((p = initList.getNext())) 9313072Sgabeblack@google.com p->popListNode(); 9413072Sgabeblack@google.com while ((p = readyList.getNext())) 9513072Sgabeblack@google.com p->popListNode(); 9613072Sgabeblack@google.com 9713072Sgabeblack@google.com Channel *c; 9813072Sgabeblack@google.com while ((c = updateList.getNext())) 9913072Sgabeblack@google.com c->popListNode(); 10013072Sgabeblack@google.com} 10113072Sgabeblack@google.com 10212953Sgabeblack@google.comvoid 10313067Sgabeblack@google.comScheduler::initPhase() 10412953Sgabeblack@google.com{ 10512957Sgabeblack@google.com for (Process *p = toFinalize.getNext(); p; p = toFinalize.getNext()) { 10612957Sgabeblack@google.com p->finalize(); 10712957Sgabeblack@google.com p->popListNode(); 10812957Sgabeblack@google.com } 10912957Sgabeblack@google.com 11012957Sgabeblack@google.com for (Process *p = initList.getNext(); p; p = initList.getNext()) { 11112957Sgabeblack@google.com p->finalize(); 11212996Sgabeblack@google.com p->popListNode(); 11312959Sgabeblack@google.com p->ready(); 11412957Sgabeblack@google.com } 11512957Sgabeblack@google.com 11613067Sgabeblack@google.com update(); 11713067Sgabeblack@google.com 11813067Sgabeblack@google.com for (auto &e: deltas) 11913067Sgabeblack@google.com e->run(); 12013067Sgabeblack@google.com deltas.clear(); 12113067Sgabeblack@google.com 12212985Sgabeblack@google.com for (auto ets: eventsToSchedule) 12312985Sgabeblack@google.com eq->schedule(ets.first, ets.second); 12412985Sgabeblack@google.com eventsToSchedule.clear(); 12512985Sgabeblack@google.com 12613068Sgabeblack@google.com if (_started) { 12713096Sgabeblack@google.com if (!runToTime && starved()) 12813068Sgabeblack@google.com scheduleStarvationEvent(); 12913069Sgabeblack@google.com kernel->status(::sc_core::SC_RUNNING); 13013068Sgabeblack@google.com } 13112961Sgabeblack@google.com 13213067Sgabeblack@google.com initDone = true; 13312957Sgabeblack@google.com} 13412957Sgabeblack@google.com 13512957Sgabeblack@google.comvoid 13612957Sgabeblack@google.comScheduler::reg(Process *p) 13712957Sgabeblack@google.com{ 13813067Sgabeblack@google.com if (initDone) { 13912957Sgabeblack@google.com // If we're past initialization, finalize static sensitivity. 14012957Sgabeblack@google.com p->finalize(); 14112957Sgabeblack@google.com // Mark the process as ready. 14212959Sgabeblack@google.com p->ready(); 14312957Sgabeblack@google.com } else { 14412957Sgabeblack@google.com // Otherwise, record that this process should be initialized once we 14512957Sgabeblack@google.com // get there. 14612957Sgabeblack@google.com initList.pushLast(p); 14712957Sgabeblack@google.com } 14812957Sgabeblack@google.com} 14912957Sgabeblack@google.com 15012957Sgabeblack@google.comvoid 15112957Sgabeblack@google.comScheduler::dontInitialize(Process *p) 15212957Sgabeblack@google.com{ 15313067Sgabeblack@google.com if (initDone) { 15412957Sgabeblack@google.com // Pop this process off of the ready list. 15512957Sgabeblack@google.com p->popListNode(); 15612957Sgabeblack@google.com } else { 15712957Sgabeblack@google.com // Push this process onto the list of processes which still need 15812957Sgabeblack@google.com // their static sensitivity to be finalized. That implicitly pops it 15912957Sgabeblack@google.com // off the list of processes to be initialized/marked ready. 16012957Sgabeblack@google.com toFinalize.pushLast(p); 16112957Sgabeblack@google.com } 16212953Sgabeblack@google.com} 16312953Sgabeblack@google.com 16412953Sgabeblack@google.comvoid 16512953Sgabeblack@google.comScheduler::yield() 16612953Sgabeblack@google.com{ 16712953Sgabeblack@google.com _current = readyList.getNext(); 16812953Sgabeblack@google.com if (!_current) { 16912953Sgabeblack@google.com // There are no more processes, so return control to evaluate. 17012953Sgabeblack@google.com Fiber::primaryFiber()->run(); 17112953Sgabeblack@google.com } else { 17212953Sgabeblack@google.com _current->popListNode(); 17312953Sgabeblack@google.com // Switch to whatever Fiber is supposed to run this process. All 17412953Sgabeblack@google.com // Fibers which aren't running should be parked at this line. 17512953Sgabeblack@google.com _current->fiber()->run(); 17612961Sgabeblack@google.com // If the current process needs to be manually started, start it. 17713093Sgabeblack@google.com if (_current && _current->needsStart()) { 17813093Sgabeblack@google.com _current->needsStart(false); 17912953Sgabeblack@google.com _current->run(); 18013093Sgabeblack@google.com } 18112953Sgabeblack@google.com } 18212995Sgabeblack@google.com if (_current && _current->excWrapper) { 18312995Sgabeblack@google.com // Make sure this isn't a method process. 18412995Sgabeblack@google.com assert(!_current->needsStart()); 18512995Sgabeblack@google.com auto ew = _current->excWrapper; 18612995Sgabeblack@google.com _current->excWrapper = nullptr; 18712995Sgabeblack@google.com ew->throw_it(); 18812995Sgabeblack@google.com } 18912953Sgabeblack@google.com} 19012953Sgabeblack@google.com 19112953Sgabeblack@google.comvoid 19212954Sgabeblack@google.comScheduler::ready(Process *p) 19312953Sgabeblack@google.com{ 19412954Sgabeblack@google.com // Clump methods together to minimize context switching. 19512954Sgabeblack@google.com if (p->procKind() == ::sc_core::SC_METHOD_PROC_) 19612954Sgabeblack@google.com readyList.pushFirst(p); 19712954Sgabeblack@google.com else 19812954Sgabeblack@google.com readyList.pushLast(p); 19912953Sgabeblack@google.com 20012954Sgabeblack@google.com scheduleReadyEvent(); 20112954Sgabeblack@google.com} 20212954Sgabeblack@google.com 20312954Sgabeblack@google.comvoid 20413133Sgabeblack@google.comScheduler::resume(Process *p) 20513133Sgabeblack@google.com{ 20613133Sgabeblack@google.com if (initDone) 20713133Sgabeblack@google.com ready(p); 20813133Sgabeblack@google.com else 20913133Sgabeblack@google.com initList.pushLast(p); 21013133Sgabeblack@google.com} 21113133Sgabeblack@google.com 21213133Sgabeblack@google.combool 21313133Sgabeblack@google.comScheduler::suspend(Process *p) 21413133Sgabeblack@google.com{ 21513133Sgabeblack@google.com if (initDone) { 21613133Sgabeblack@google.com // After initialization, the only list we can be on is the ready list. 21713133Sgabeblack@google.com bool was_ready = (p->nextListNode != nullptr); 21813133Sgabeblack@google.com p->popListNode(); 21913133Sgabeblack@google.com return was_ready; 22013133Sgabeblack@google.com } else { 22113133Sgabeblack@google.com bool was_ready = false; 22213133Sgabeblack@google.com // Check the ready list to see if we find this process. 22313133Sgabeblack@google.com ListNode *n = readyList.nextListNode; 22413133Sgabeblack@google.com while (n != &readyList) { 22513133Sgabeblack@google.com if (n == p) { 22613133Sgabeblack@google.com was_ready = true; 22713133Sgabeblack@google.com break; 22813133Sgabeblack@google.com } 22913133Sgabeblack@google.com } 23013133Sgabeblack@google.com if (was_ready) 23113133Sgabeblack@google.com toFinalize.pushLast(p); 23213133Sgabeblack@google.com return was_ready; 23313133Sgabeblack@google.com } 23413133Sgabeblack@google.com} 23513133Sgabeblack@google.com 23613133Sgabeblack@google.comvoid 23712954Sgabeblack@google.comScheduler::requestUpdate(Channel *c) 23812954Sgabeblack@google.com{ 23912954Sgabeblack@google.com updateList.pushLast(c); 24013069Sgabeblack@google.com scheduleReadyEvent(); 24112954Sgabeblack@google.com} 24212954Sgabeblack@google.com 24312954Sgabeblack@google.comvoid 24412954Sgabeblack@google.comScheduler::scheduleReadyEvent() 24512954Sgabeblack@google.com{ 24612954Sgabeblack@google.com // Schedule the evaluate and update phases. 24712954Sgabeblack@google.com if (!readyEvent.scheduled()) { 24813069Sgabeblack@google.com schedule(&readyEvent); 24912987Sgabeblack@google.com if (starvationEvent.scheduled()) 25013069Sgabeblack@google.com deschedule(&starvationEvent); 25112987Sgabeblack@google.com } 25212987Sgabeblack@google.com} 25312987Sgabeblack@google.com 25412987Sgabeblack@google.comvoid 25512987Sgabeblack@google.comScheduler::scheduleStarvationEvent() 25612987Sgabeblack@google.com{ 25712987Sgabeblack@google.com if (!starvationEvent.scheduled()) { 25813069Sgabeblack@google.com schedule(&starvationEvent); 25912987Sgabeblack@google.com if (readyEvent.scheduled()) 26013069Sgabeblack@google.com deschedule(&readyEvent); 26112954Sgabeblack@google.com } 26212954Sgabeblack@google.com} 26312954Sgabeblack@google.com 26412954Sgabeblack@google.comvoid 26512954Sgabeblack@google.comScheduler::runReady() 26612954Sgabeblack@google.com{ 26712954Sgabeblack@google.com bool empty = readyList.empty(); 26812954Sgabeblack@google.com 26912954Sgabeblack@google.com // The evaluation phase. 27012953Sgabeblack@google.com do { 27112953Sgabeblack@google.com yield(); 27212953Sgabeblack@google.com } while (!readyList.empty()); 27312954Sgabeblack@google.com 27412954Sgabeblack@google.com if (!empty) 27512954Sgabeblack@google.com _numCycles++; 27612954Sgabeblack@google.com 27712954Sgabeblack@google.com // The update phase. 27812954Sgabeblack@google.com update(); 27912954Sgabeblack@google.com 28013063Sgabeblack@google.com // The delta phase. 28113063Sgabeblack@google.com for (auto &e: deltas) 28213063Sgabeblack@google.com e->run(); 28313063Sgabeblack@google.com deltas.clear(); 28413061Sgabeblack@google.com 28513096Sgabeblack@google.com if (!runToTime && starved()) 28613096Sgabeblack@google.com scheduleStarvationEvent(); 28713096Sgabeblack@google.com 28813064Sgabeblack@google.com if (runOnce) 28913064Sgabeblack@google.com schedulePause(); 29012953Sgabeblack@google.com} 29112953Sgabeblack@google.com 29212953Sgabeblack@google.comvoid 29312953Sgabeblack@google.comScheduler::update() 29412953Sgabeblack@google.com{ 29512954Sgabeblack@google.com Channel *channel = updateList.getNext(); 29612954Sgabeblack@google.com while (channel) { 29712954Sgabeblack@google.com channel->popListNode(); 29812954Sgabeblack@google.com channel->update(); 29912954Sgabeblack@google.com channel = updateList.getNext(); 30012954Sgabeblack@google.com } 30112953Sgabeblack@google.com} 30212953Sgabeblack@google.com 30312961Sgabeblack@google.comvoid 30412961Sgabeblack@google.comScheduler::pause() 30512961Sgabeblack@google.com{ 30612961Sgabeblack@google.com _paused = true; 30712982Sgabeblack@google.com kernel->status(::sc_core::SC_PAUSED); 30813061Sgabeblack@google.com runOnce = false; 30912961Sgabeblack@google.com scMain->run(); 31012961Sgabeblack@google.com} 31112961Sgabeblack@google.com 31212961Sgabeblack@google.comvoid 31312961Sgabeblack@google.comScheduler::stop() 31412961Sgabeblack@google.com{ 31512961Sgabeblack@google.com _stopped = true; 31612982Sgabeblack@google.com kernel->stop(); 31713074Sgabeblack@google.com 31813076Sgabeblack@google.com clear(); 31913074Sgabeblack@google.com 32013061Sgabeblack@google.com runOnce = false; 32112961Sgabeblack@google.com scMain->run(); 32212961Sgabeblack@google.com} 32312961Sgabeblack@google.com 32412961Sgabeblack@google.comvoid 32512961Sgabeblack@google.comScheduler::start(Tick max_tick, bool run_to_time) 32612961Sgabeblack@google.com{ 32712961Sgabeblack@google.com // We should be running from sc_main. Keep track of that Fiber to return 32812961Sgabeblack@google.com // to later. 32912961Sgabeblack@google.com scMain = Fiber::currentFiber(); 33012961Sgabeblack@google.com 33112961Sgabeblack@google.com _started = true; 33212961Sgabeblack@google.com _paused = false; 33312961Sgabeblack@google.com _stopped = false; 33412987Sgabeblack@google.com runToTime = run_to_time; 33512961Sgabeblack@google.com 33612961Sgabeblack@google.com maxTick = max_tick; 33712961Sgabeblack@google.com 33813067Sgabeblack@google.com if (initDone) { 33913096Sgabeblack@google.com if (!runToTime && starved()) 34013068Sgabeblack@google.com scheduleStarvationEvent(); 34112982Sgabeblack@google.com kernel->status(::sc_core::SC_RUNNING); 34212982Sgabeblack@google.com } 34312961Sgabeblack@google.com 34413069Sgabeblack@google.com schedule(&maxTickEvent, maxTick); 34513069Sgabeblack@google.com 34612961Sgabeblack@google.com // Return to gem5 to let it run events, etc. 34712961Sgabeblack@google.com Fiber::primaryFiber()->run(); 34812961Sgabeblack@google.com 34912961Sgabeblack@google.com if (pauseEvent.scheduled()) 35013088Sgabeblack@google.com deschedule(&pauseEvent); 35112961Sgabeblack@google.com if (stopEvent.scheduled()) 35213088Sgabeblack@google.com deschedule(&stopEvent); 35312961Sgabeblack@google.com if (maxTickEvent.scheduled()) 35413088Sgabeblack@google.com deschedule(&maxTickEvent); 35512987Sgabeblack@google.com if (starvationEvent.scheduled()) 35613088Sgabeblack@google.com deschedule(&starvationEvent); 35712961Sgabeblack@google.com} 35812961Sgabeblack@google.com 35912961Sgabeblack@google.comvoid 36013061Sgabeblack@google.comScheduler::oneCycle() 36113061Sgabeblack@google.com{ 36213061Sgabeblack@google.com runOnce = true; 36313095Sgabeblack@google.com scheduleReadyEvent(); 36413061Sgabeblack@google.com start(::MaxTick, false); 36513061Sgabeblack@google.com} 36613061Sgabeblack@google.com 36713061Sgabeblack@google.comvoid 36812961Sgabeblack@google.comScheduler::schedulePause() 36912961Sgabeblack@google.com{ 37012961Sgabeblack@google.com if (pauseEvent.scheduled()) 37112961Sgabeblack@google.com return; 37212961Sgabeblack@google.com 37313088Sgabeblack@google.com schedule(&pauseEvent); 37412961Sgabeblack@google.com} 37512961Sgabeblack@google.com 37612961Sgabeblack@google.comvoid 37712961Sgabeblack@google.comScheduler::scheduleStop(bool finish_delta) 37812961Sgabeblack@google.com{ 37912961Sgabeblack@google.com if (stopEvent.scheduled()) 38012961Sgabeblack@google.com return; 38112961Sgabeblack@google.com 38212961Sgabeblack@google.com if (!finish_delta) { 38313076Sgabeblack@google.com // If we're not supposed to finish the delta cycle, flush all 38413076Sgabeblack@google.com // pending activity. 38513076Sgabeblack@google.com clear(); 38612961Sgabeblack@google.com } 38713088Sgabeblack@google.com schedule(&stopEvent); 38812961Sgabeblack@google.com} 38912961Sgabeblack@google.com 39012953Sgabeblack@google.comScheduler scheduler; 39112953Sgabeblack@google.com 39212953Sgabeblack@google.com} // namespace sc_gem5 393