scheduler.cc revision 12962:004cc9133bd6
1/* 2 * Copyright 2018 Google, Inc. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer; 8 * redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution; 11 * neither the name of the copyright holders nor the names of its 12 * contributors may be used to endorse or promote products derived from 13 * this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * Authors: Gabe Black 28 */ 29 30#include "systemc/core/scheduler.hh" 31 32#include "base/fiber.hh" 33#include "base/logging.hh" 34#include "sim/eventq.hh" 35 36namespace sc_gem5 37{ 38 39Scheduler::Scheduler() : 40 eq(nullptr), readyEvent(this, false, ReadyPriority), 41 pauseEvent(this, false, PausePriority), 42 stopEvent(this, false, StopPriority), 43 scMain(nullptr), _started(false), _paused(false), _stopped(false), 44 maxTickEvent(this, false, MaxTickPriority), 45 _numCycles(0), _current(nullptr), initReady(false) 46{} 47 48void 49Scheduler::prepareForInit() 50{ 51 for (Process *p = toFinalize.getNext(); p; p = toFinalize.getNext()) { 52 p->finalize(); 53 p->popListNode(); 54 } 55 56 for (Process *p = initList.getNext(); p; p = initList.getNext()) { 57 p->finalize(); 58 p->ready(); 59 } 60 61 if (_started) 62 eq->schedule(&maxTickEvent, maxTick); 63 64 initReady = true; 65} 66 67void 68Scheduler::reg(Process *p) 69{ 70 if (initReady) { 71 // If we're past initialization, finalize static sensitivity. 72 p->finalize(); 73 // Mark the process as ready. 74 p->ready(); 75 } else { 76 // Otherwise, record that this process should be initialized once we 77 // get there. 78 initList.pushLast(p); 79 } 80} 81 82void 83Scheduler::dontInitialize(Process *p) 84{ 85 if (initReady) { 86 // Pop this process off of the ready list. 87 p->popListNode(); 88 } else { 89 // Push this process onto the list of processes which still need 90 // their static sensitivity to be finalized. That implicitly pops it 91 // off the list of processes to be initialized/marked ready. 92 toFinalize.pushLast(p); 93 } 94} 95 96void 97Scheduler::yield() 98{ 99 _current = readyList.getNext(); 100 if (!_current) { 101 // There are no more processes, so return control to evaluate. 102 Fiber::primaryFiber()->run(); 103 } else { 104 _current->popListNode(); 105 // Switch to whatever Fiber is supposed to run this process. All 106 // Fibers which aren't running should be parked at this line. 107 _current->fiber()->run(); 108 // If the current process needs to be manually started, start it. 109 if (_current && _current->needsStart()) 110 _current->run(); 111 } 112} 113 114void 115Scheduler::ready(Process *p) 116{ 117 // Clump methods together to minimize context switching. 118 if (p->procKind() == ::sc_core::SC_METHOD_PROC_) 119 readyList.pushFirst(p); 120 else 121 readyList.pushLast(p); 122 123 scheduleReadyEvent(); 124} 125 126void 127Scheduler::requestUpdate(Channel *c) 128{ 129 updateList.pushLast(c); 130 scheduleReadyEvent(); 131} 132 133void 134Scheduler::scheduleReadyEvent() 135{ 136 // Schedule the evaluate and update phases. 137 if (!readyEvent.scheduled()) { 138 panic_if(!eq, "Need to schedule ready, but no event manager.\n"); 139 eq->schedule(&readyEvent, eq->getCurTick()); 140 } 141} 142 143void 144Scheduler::runReady() 145{ 146 bool empty = readyList.empty(); 147 148 // The evaluation phase. 149 do { 150 yield(); 151 } while (!readyList.empty()); 152 153 if (!empty) 154 _numCycles++; 155 156 // The update phase. 157 update(); 158 159 // The delta phase will happen naturally through the event queue. 160} 161 162void 163Scheduler::update() 164{ 165 Channel *channel = updateList.getNext(); 166 while (channel) { 167 channel->popListNode(); 168 channel->update(); 169 channel = updateList.getNext(); 170 } 171} 172 173void 174Scheduler::pause() 175{ 176 _paused = true; 177 scMain->run(); 178} 179 180void 181Scheduler::stop() 182{ 183 _stopped = true; 184 scMain->run(); 185} 186 187void 188Scheduler::start(Tick max_tick, bool run_to_time) 189{ 190 // We should be running from sc_main. Keep track of that Fiber to return 191 // to later. 192 scMain = Fiber::currentFiber(); 193 194 _started = true; 195 _paused = false; 196 _stopped = false; 197 198 maxTick = max_tick; 199 200 if (initReady) 201 eq->schedule(&maxTickEvent, maxTick); 202 203 // Return to gem5 to let it run events, etc. 204 Fiber::primaryFiber()->run(); 205 206 if (pauseEvent.scheduled()) 207 eq->deschedule(&pauseEvent); 208 if (stopEvent.scheduled()) 209 eq->deschedule(&stopEvent); 210 if (maxTickEvent.scheduled()) 211 eq->deschedule(&maxTickEvent); 212} 213 214void 215Scheduler::schedulePause() 216{ 217 if (pauseEvent.scheduled()) 218 return; 219 220 eq->schedule(&pauseEvent, eq->getCurTick()); 221} 222 223void 224Scheduler::scheduleStop(bool finish_delta) 225{ 226 if (stopEvent.scheduled()) 227 return; 228 229 if (!finish_delta) { 230 // If we're not supposed to finish the delta cycle, flush the list 231 // of ready processes and scheduled updates. 232 Process *p; 233 while ((p = readyList.getNext())) 234 p->popListNode(); 235 Channel *c; 236 while ((c = updateList.getNext())) 237 c->popListNode(); 238 } 239 eq->schedule(&stopEvent, eq->getCurTick()); 240} 241 242Scheduler scheduler; 243 244} // namespace sc_gem5 245