scheduler.cc revision 12961:9bd3a469fd11
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), _pendingCurr(0), _pendingFuture(0), 41 readyEvent(this, false, ReadyPriority), 42 pauseEvent(this, false, PausePriority), 43 stopEvent(this, false, StopPriority), 44 scMain(nullptr), _started(false), _paused(false), _stopped(false), 45 maxTickEvent(this, false, MaxTickPriority), 46 _numCycles(0), _current(nullptr), initReady(false) 47{} 48 49void 50Scheduler::prepareForInit() 51{ 52 for (Process *p = toFinalize.getNext(); p; p = toFinalize.getNext()) { 53 p->finalize(); 54 p->popListNode(); 55 } 56 57 for (Process *p = initList.getNext(); p; p = initList.getNext()) { 58 p->finalize(); 59 p->ready(); 60 } 61 62 if (_started) 63 eq->schedule(&maxTickEvent, maxTick); 64 65 initReady = true; 66} 67 68void 69Scheduler::reg(Process *p) 70{ 71 if (initReady) { 72 // If we're past initialization, finalize static sensitivity. 73 p->finalize(); 74 // Mark the process as ready. 75 p->ready(); 76 } else { 77 // Otherwise, record that this process should be initialized once we 78 // get there. 79 initList.pushLast(p); 80 } 81} 82 83void 84Scheduler::dontInitialize(Process *p) 85{ 86 if (initReady) { 87 // Pop this process off of the ready list. 88 p->popListNode(); 89 } else { 90 // Push this process onto the list of processes which still need 91 // their static sensitivity to be finalized. That implicitly pops it 92 // off the list of processes to be initialized/marked ready. 93 toFinalize.pushLast(p); 94 } 95} 96 97void 98Scheduler::yield() 99{ 100 _current = readyList.getNext(); 101 if (!_current) { 102 // There are no more processes, so return control to evaluate. 103 Fiber::primaryFiber()->run(); 104 } else { 105 _current->popListNode(); 106 // Switch to whatever Fiber is supposed to run this process. All 107 // Fibers which aren't running should be parked at this line. 108 _current->fiber()->run(); 109 // If the current process needs to be manually started, start it. 110 if (_current && _current->needsStart()) 111 _current->run(); 112 } 113} 114 115void 116Scheduler::ready(Process *p) 117{ 118 // Clump methods together to minimize context switching. 119 if (p->procKind() == ::sc_core::SC_METHOD_PROC_) 120 readyList.pushFirst(p); 121 else 122 readyList.pushLast(p); 123 124 scheduleReadyEvent(); 125} 126 127void 128Scheduler::requestUpdate(Channel *c) 129{ 130 updateList.pushLast(c); 131 scheduleReadyEvent(); 132} 133 134void 135Scheduler::scheduleReadyEvent() 136{ 137 // Schedule the evaluate and update phases. 138 if (!readyEvent.scheduled()) { 139 panic_if(!eq, "Need to schedule ready, but no event manager.\n"); 140 eq->schedule(&readyEvent, eq->getCurTick()); 141 } 142} 143 144void 145Scheduler::runReady() 146{ 147 bool empty = readyList.empty(); 148 149 // The evaluation phase. 150 do { 151 yield(); 152 } while (!readyList.empty()); 153 154 if (!empty) 155 _numCycles++; 156 157 // The update phase. 158 update(); 159 160 // The delta phase will happen naturally through the event queue. 161} 162 163void 164Scheduler::update() 165{ 166 Channel *channel = updateList.getNext(); 167 while (channel) { 168 channel->popListNode(); 169 channel->update(); 170 channel = updateList.getNext(); 171 } 172} 173 174void 175Scheduler::pause() 176{ 177 _paused = true; 178 scMain->run(); 179} 180 181void 182Scheduler::stop() 183{ 184 _stopped = true; 185 scMain->run(); 186} 187 188void 189Scheduler::start(Tick max_tick, bool run_to_time) 190{ 191 // We should be running from sc_main. Keep track of that Fiber to return 192 // to later. 193 scMain = Fiber::currentFiber(); 194 195 _started = true; 196 _paused = false; 197 _stopped = false; 198 199 maxTick = max_tick; 200 201 if (initReady) 202 eq->schedule(&maxTickEvent, maxTick); 203 204 // Return to gem5 to let it run events, etc. 205 Fiber::primaryFiber()->run(); 206 207 if (pauseEvent.scheduled()) 208 eq->deschedule(&pauseEvent); 209 if (stopEvent.scheduled()) 210 eq->deschedule(&stopEvent); 211 if (maxTickEvent.scheduled()) 212 eq->deschedule(&maxTickEvent); 213} 214 215void 216Scheduler::schedulePause() 217{ 218 if (pauseEvent.scheduled()) 219 return; 220 221 eq->schedule(&pauseEvent, eq->getCurTick()); 222} 223 224void 225Scheduler::scheduleStop(bool finish_delta) 226{ 227 if (stopEvent.scheduled()) 228 return; 229 230 if (!finish_delta) { 231 // If we're not supposed to finish the delta cycle, flush the list 232 // of ready processes and scheduled updates. 233 Process *p; 234 while ((p = readyList.getNext())) 235 p->popListNode(); 236 Channel *c; 237 while ((c = updateList.getNext())) 238 c->popListNode(); 239 } 240 eq->schedule(&stopEvent, eq->getCurTick()); 241} 242 243Scheduler scheduler; 244 245} // namespace sc_gem5 246