scheduler.cc revision 13069
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 5312953Sgabeblack@google.comvoid 5413067Sgabeblack@google.comScheduler::initPhase() 5512953Sgabeblack@google.com{ 5612957Sgabeblack@google.com for (Process *p = toFinalize.getNext(); p; p = toFinalize.getNext()) { 5712957Sgabeblack@google.com p->finalize(); 5812957Sgabeblack@google.com p->popListNode(); 5912957Sgabeblack@google.com } 6012957Sgabeblack@google.com 6112957Sgabeblack@google.com for (Process *p = initList.getNext(); p; p = initList.getNext()) { 6212957Sgabeblack@google.com p->finalize(); 6312996Sgabeblack@google.com p->popListNode(); 6412959Sgabeblack@google.com p->ready(); 6512957Sgabeblack@google.com } 6612957Sgabeblack@google.com 6713067Sgabeblack@google.com update(); 6813067Sgabeblack@google.com 6913067Sgabeblack@google.com for (auto &e: deltas) 7013067Sgabeblack@google.com e->run(); 7113067Sgabeblack@google.com deltas.clear(); 7213067Sgabeblack@google.com 7312985Sgabeblack@google.com for (auto ets: eventsToSchedule) 7412985Sgabeblack@google.com eq->schedule(ets.first, ets.second); 7512985Sgabeblack@google.com eventsToSchedule.clear(); 7612985Sgabeblack@google.com 7713068Sgabeblack@google.com if (_started) { 7813068Sgabeblack@google.com if (starved() && !runToTime) 7913068Sgabeblack@google.com scheduleStarvationEvent(); 8013069Sgabeblack@google.com kernel->status(::sc_core::SC_RUNNING); 8113068Sgabeblack@google.com } 8212961Sgabeblack@google.com 8313067Sgabeblack@google.com initDone = true; 8412957Sgabeblack@google.com} 8512957Sgabeblack@google.com 8612957Sgabeblack@google.comvoid 8712957Sgabeblack@google.comScheduler::reg(Process *p) 8812957Sgabeblack@google.com{ 8913067Sgabeblack@google.com if (initDone) { 9012957Sgabeblack@google.com // If we're past initialization, finalize static sensitivity. 9112957Sgabeblack@google.com p->finalize(); 9212957Sgabeblack@google.com // Mark the process as ready. 9312959Sgabeblack@google.com p->ready(); 9412957Sgabeblack@google.com } else { 9512957Sgabeblack@google.com // Otherwise, record that this process should be initialized once we 9612957Sgabeblack@google.com // get there. 9712957Sgabeblack@google.com initList.pushLast(p); 9812957Sgabeblack@google.com } 9912957Sgabeblack@google.com} 10012957Sgabeblack@google.com 10112957Sgabeblack@google.comvoid 10212957Sgabeblack@google.comScheduler::dontInitialize(Process *p) 10312957Sgabeblack@google.com{ 10413067Sgabeblack@google.com if (initDone) { 10512957Sgabeblack@google.com // Pop this process off of the ready list. 10612957Sgabeblack@google.com p->popListNode(); 10712957Sgabeblack@google.com } else { 10812957Sgabeblack@google.com // Push this process onto the list of processes which still need 10912957Sgabeblack@google.com // their static sensitivity to be finalized. That implicitly pops it 11012957Sgabeblack@google.com // off the list of processes to be initialized/marked ready. 11112957Sgabeblack@google.com toFinalize.pushLast(p); 11212957Sgabeblack@google.com } 11312953Sgabeblack@google.com} 11412953Sgabeblack@google.com 11512953Sgabeblack@google.comvoid 11612953Sgabeblack@google.comScheduler::yield() 11712953Sgabeblack@google.com{ 11812953Sgabeblack@google.com _current = readyList.getNext(); 11912953Sgabeblack@google.com if (!_current) { 12012953Sgabeblack@google.com // There are no more processes, so return control to evaluate. 12112953Sgabeblack@google.com Fiber::primaryFiber()->run(); 12212953Sgabeblack@google.com } else { 12312953Sgabeblack@google.com _current->popListNode(); 12412953Sgabeblack@google.com // Switch to whatever Fiber is supposed to run this process. All 12512953Sgabeblack@google.com // Fibers which aren't running should be parked at this line. 12612953Sgabeblack@google.com _current->fiber()->run(); 12712961Sgabeblack@google.com // If the current process needs to be manually started, start it. 12812961Sgabeblack@google.com if (_current && _current->needsStart()) 12912953Sgabeblack@google.com _current->run(); 13012953Sgabeblack@google.com } 13112995Sgabeblack@google.com if (_current && _current->excWrapper) { 13212995Sgabeblack@google.com // Make sure this isn't a method process. 13312995Sgabeblack@google.com assert(!_current->needsStart()); 13412995Sgabeblack@google.com auto ew = _current->excWrapper; 13512995Sgabeblack@google.com _current->excWrapper = nullptr; 13612995Sgabeblack@google.com ew->throw_it(); 13712995Sgabeblack@google.com } 13812953Sgabeblack@google.com} 13912953Sgabeblack@google.com 14012953Sgabeblack@google.comvoid 14112954Sgabeblack@google.comScheduler::ready(Process *p) 14212953Sgabeblack@google.com{ 14312954Sgabeblack@google.com // Clump methods together to minimize context switching. 14412954Sgabeblack@google.com if (p->procKind() == ::sc_core::SC_METHOD_PROC_) 14512954Sgabeblack@google.com readyList.pushFirst(p); 14612954Sgabeblack@google.com else 14712954Sgabeblack@google.com readyList.pushLast(p); 14812953Sgabeblack@google.com 14912954Sgabeblack@google.com scheduleReadyEvent(); 15012954Sgabeblack@google.com} 15112954Sgabeblack@google.com 15212954Sgabeblack@google.comvoid 15312954Sgabeblack@google.comScheduler::requestUpdate(Channel *c) 15412954Sgabeblack@google.com{ 15512954Sgabeblack@google.com updateList.pushLast(c); 15613069Sgabeblack@google.com scheduleReadyEvent(); 15712954Sgabeblack@google.com} 15812954Sgabeblack@google.com 15912954Sgabeblack@google.comvoid 16012954Sgabeblack@google.comScheduler::scheduleReadyEvent() 16112954Sgabeblack@google.com{ 16212954Sgabeblack@google.com // Schedule the evaluate and update phases. 16312954Sgabeblack@google.com if (!readyEvent.scheduled()) { 16413069Sgabeblack@google.com schedule(&readyEvent); 16512987Sgabeblack@google.com if (starvationEvent.scheduled()) 16613069Sgabeblack@google.com deschedule(&starvationEvent); 16712987Sgabeblack@google.com } 16812987Sgabeblack@google.com} 16912987Sgabeblack@google.com 17012987Sgabeblack@google.comvoid 17112987Sgabeblack@google.comScheduler::scheduleStarvationEvent() 17212987Sgabeblack@google.com{ 17312987Sgabeblack@google.com if (!starvationEvent.scheduled()) { 17413069Sgabeblack@google.com schedule(&starvationEvent); 17512987Sgabeblack@google.com if (readyEvent.scheduled()) 17613069Sgabeblack@google.com deschedule(&readyEvent); 17712954Sgabeblack@google.com } 17812954Sgabeblack@google.com} 17912954Sgabeblack@google.com 18012954Sgabeblack@google.comvoid 18112954Sgabeblack@google.comScheduler::runReady() 18212954Sgabeblack@google.com{ 18312954Sgabeblack@google.com bool empty = readyList.empty(); 18412954Sgabeblack@google.com 18512954Sgabeblack@google.com // The evaluation phase. 18612953Sgabeblack@google.com do { 18712953Sgabeblack@google.com yield(); 18812953Sgabeblack@google.com } while (!readyList.empty()); 18912954Sgabeblack@google.com 19012954Sgabeblack@google.com if (!empty) 19112954Sgabeblack@google.com _numCycles++; 19212954Sgabeblack@google.com 19312954Sgabeblack@google.com // The update phase. 19412954Sgabeblack@google.com update(); 19512954Sgabeblack@google.com 19612987Sgabeblack@google.com if (starved() && !runToTime) 19712987Sgabeblack@google.com scheduleStarvationEvent(); 19812987Sgabeblack@google.com 19913063Sgabeblack@google.com // The delta phase. 20013063Sgabeblack@google.com for (auto &e: deltas) 20113063Sgabeblack@google.com e->run(); 20213063Sgabeblack@google.com deltas.clear(); 20313061Sgabeblack@google.com 20413064Sgabeblack@google.com if (runOnce) 20513064Sgabeblack@google.com schedulePause(); 20612953Sgabeblack@google.com} 20712953Sgabeblack@google.com 20812953Sgabeblack@google.comvoid 20912953Sgabeblack@google.comScheduler::update() 21012953Sgabeblack@google.com{ 21112954Sgabeblack@google.com Channel *channel = updateList.getNext(); 21212954Sgabeblack@google.com while (channel) { 21312954Sgabeblack@google.com channel->popListNode(); 21412954Sgabeblack@google.com channel->update(); 21512954Sgabeblack@google.com channel = updateList.getNext(); 21612954Sgabeblack@google.com } 21712953Sgabeblack@google.com} 21812953Sgabeblack@google.com 21912961Sgabeblack@google.comvoid 22012961Sgabeblack@google.comScheduler::pause() 22112961Sgabeblack@google.com{ 22212961Sgabeblack@google.com _paused = true; 22312982Sgabeblack@google.com kernel->status(::sc_core::SC_PAUSED); 22413061Sgabeblack@google.com runOnce = false; 22512961Sgabeblack@google.com scMain->run(); 22612961Sgabeblack@google.com} 22712961Sgabeblack@google.com 22812961Sgabeblack@google.comvoid 22912961Sgabeblack@google.comScheduler::stop() 23012961Sgabeblack@google.com{ 23112961Sgabeblack@google.com _stopped = true; 23212982Sgabeblack@google.com kernel->stop(); 23313061Sgabeblack@google.com runOnce = false; 23412961Sgabeblack@google.com scMain->run(); 23512961Sgabeblack@google.com} 23612961Sgabeblack@google.com 23712961Sgabeblack@google.comvoid 23812961Sgabeblack@google.comScheduler::start(Tick max_tick, bool run_to_time) 23912961Sgabeblack@google.com{ 24012961Sgabeblack@google.com // We should be running from sc_main. Keep track of that Fiber to return 24112961Sgabeblack@google.com // to later. 24212961Sgabeblack@google.com scMain = Fiber::currentFiber(); 24312961Sgabeblack@google.com 24412961Sgabeblack@google.com _started = true; 24512961Sgabeblack@google.com _paused = false; 24612961Sgabeblack@google.com _stopped = false; 24712987Sgabeblack@google.com runToTime = run_to_time; 24812961Sgabeblack@google.com 24912961Sgabeblack@google.com maxTick = max_tick; 25012961Sgabeblack@google.com 25113067Sgabeblack@google.com if (initDone) { 25213068Sgabeblack@google.com if (starved() && !runToTime) 25313068Sgabeblack@google.com scheduleStarvationEvent(); 25412982Sgabeblack@google.com kernel->status(::sc_core::SC_RUNNING); 25512982Sgabeblack@google.com } 25612961Sgabeblack@google.com 25713069Sgabeblack@google.com schedule(&maxTickEvent, maxTick); 25813069Sgabeblack@google.com 25912961Sgabeblack@google.com // Return to gem5 to let it run events, etc. 26012961Sgabeblack@google.com Fiber::primaryFiber()->run(); 26112961Sgabeblack@google.com 26212961Sgabeblack@google.com if (pauseEvent.scheduled()) 26312961Sgabeblack@google.com eq->deschedule(&pauseEvent); 26412961Sgabeblack@google.com if (stopEvent.scheduled()) 26512961Sgabeblack@google.com eq->deschedule(&stopEvent); 26612961Sgabeblack@google.com if (maxTickEvent.scheduled()) 26712961Sgabeblack@google.com eq->deschedule(&maxTickEvent); 26812987Sgabeblack@google.com if (starvationEvent.scheduled()) 26912987Sgabeblack@google.com eq->deschedule(&starvationEvent); 27012961Sgabeblack@google.com} 27112961Sgabeblack@google.com 27212961Sgabeblack@google.comvoid 27313061Sgabeblack@google.comScheduler::oneCycle() 27413061Sgabeblack@google.com{ 27513061Sgabeblack@google.com runOnce = true; 27613061Sgabeblack@google.com start(::MaxTick, false); 27713061Sgabeblack@google.com} 27813061Sgabeblack@google.com 27913061Sgabeblack@google.comvoid 28012961Sgabeblack@google.comScheduler::schedulePause() 28112961Sgabeblack@google.com{ 28212961Sgabeblack@google.com if (pauseEvent.scheduled()) 28312961Sgabeblack@google.com return; 28412961Sgabeblack@google.com 28512961Sgabeblack@google.com eq->schedule(&pauseEvent, eq->getCurTick()); 28612961Sgabeblack@google.com} 28712961Sgabeblack@google.com 28812961Sgabeblack@google.comvoid 28912961Sgabeblack@google.comScheduler::scheduleStop(bool finish_delta) 29012961Sgabeblack@google.com{ 29112961Sgabeblack@google.com if (stopEvent.scheduled()) 29212961Sgabeblack@google.com return; 29312961Sgabeblack@google.com 29412961Sgabeblack@google.com if (!finish_delta) { 29512961Sgabeblack@google.com // If we're not supposed to finish the delta cycle, flush the list 29613064Sgabeblack@google.com // of ready processes, scheduled updates, and delta notifications. 29712961Sgabeblack@google.com Process *p; 29812961Sgabeblack@google.com while ((p = readyList.getNext())) 29912961Sgabeblack@google.com p->popListNode(); 30012961Sgabeblack@google.com Channel *c; 30112961Sgabeblack@google.com while ((c = updateList.getNext())) 30212961Sgabeblack@google.com c->popListNode(); 30313064Sgabeblack@google.com for (auto &e: deltas) 30413064Sgabeblack@google.com e->deschedule(); 30513064Sgabeblack@google.com deltas.clear(); 30612961Sgabeblack@google.com } 30712961Sgabeblack@google.com eq->schedule(&stopEvent, eq->getCurTick()); 30812961Sgabeblack@google.com} 30912961Sgabeblack@google.com 31012953Sgabeblack@google.comScheduler scheduler; 31112953Sgabeblack@google.com 31212953Sgabeblack@google.com} // namespace sc_gem5 313