scheduler.cc revision 13207:034ca389a810
16145Snate@binkert.org/* 26145Snate@binkert.org * Copyright 2018 Google, Inc. 36145Snate@binkert.org * 46145Snate@binkert.org * Redistribution and use in source and binary forms, with or without 56145Snate@binkert.org * modification, are permitted provided that the following conditions are 66145Snate@binkert.org * met: redistributions of source code must retain the above copyright 76145Snate@binkert.org * notice, this list of conditions and the following disclaimer; 86145Snate@binkert.org * redistributions in binary form must reproduce the above copyright 96145Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 106145Snate@binkert.org * documentation and/or other materials provided with the distribution; 116145Snate@binkert.org * neither the name of the copyright holders nor the names of its 126145Snate@binkert.org * contributors may be used to endorse or promote products derived from 136145Snate@binkert.org * this software without specific prior written permission. 146145Snate@binkert.org * 156145Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 166145Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 176145Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 186145Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 196145Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 206145Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 216145Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 226145Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 236145Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 246145Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 256145Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 266145Snate@binkert.org * 276145Snate@binkert.org * Authors: Gabe Black 286145Snate@binkert.org */ 297054Snate@binkert.org 307054Snate@binkert.org#include "systemc/core/scheduler.hh" 316145Snate@binkert.org 327055Snate@binkert.org#include "base/fiber.hh" 337454Snate@binkert.org#include "base/logging.hh" 347055Snate@binkert.org#include "sim/eventq.hh" 356154Snate@binkert.org#include "systemc/core/kernel.hh" 367054Snate@binkert.org#include "systemc/ext/core/sc_main.hh" 376145Snate@binkert.org#include "systemc/ext/utils/sc_report.hh" 386145Snate@binkert.org#include "systemc/ext/utils/sc_report_handler.hh" 396145Snate@binkert.org 406145Snate@binkert.orgnamespace sc_gem5 416145Snate@binkert.org{ 426145Snate@binkert.org 437054Snate@binkert.orgScheduler::Scheduler() : 447054Snate@binkert.org eq(nullptr), readyEvent(this, false, ReadyPriority), 457054Snate@binkert.org pauseEvent(this, false, PausePriority), 466876Ssteve.reinhardt@amd.com stopEvent(this, false, StopPriority), 476876Ssteve.reinhardt@amd.com scMain(nullptr), _throwToScMain(nullptr), 487054Snate@binkert.org starvationEvent(this, false, StarvationPriority), 496145Snate@binkert.org _elaborationDone(false), _started(false), _stopNow(false), 507054Snate@binkert.org _status(StatusOther), maxTickEvent(this, false, MaxTickPriority), 516145Snate@binkert.org _numCycles(0), _changeStamp(0), _current(nullptr), initDone(false), 528259SBrad.Beckmann@amd.com runOnce(false), readyList(nullptr) 538259SBrad.Beckmann@amd.com{} 548259SBrad.Beckmann@amd.com 558259SBrad.Beckmann@amd.comScheduler::~Scheduler() 569863Snilay@cs.wisc.edu{ 579863Snilay@cs.wisc.edu // Clear out everything that belongs to us to make sure nobody tries to 586145Snate@binkert.org // clear themselves out after the scheduler goes away. 5910311Snilay@cs.wisc.edu clear(); 6010311Snilay@cs.wisc.edu} 6110311Snilay@cs.wisc.edu 6210311Snilay@cs.wisc.eduvoid 6310311Snilay@cs.wisc.eduScheduler::clear() 646145Snate@binkert.org{ 6511064Snilay@cs.wisc.edu // Delta notifications. 666145Snate@binkert.org while (!deltas.empty()) 677054Snate@binkert.org deltas.front()->deschedule(); 688257SBrad.Beckmann@amd.com 698257SBrad.Beckmann@amd.com // Timed notifications. 709799Snilay@cs.wisc.edu for (auto &tsp: timeSlots) { 719799Snilay@cs.wisc.edu TimeSlot *&ts = tsp.second; 728257SBrad.Beckmann@amd.com while (!ts->events.empty()) 739799Snilay@cs.wisc.edu ts->events.front()->deschedule(); 748257SBrad.Beckmann@amd.com deschedule(ts); 758257SBrad.Beckmann@amd.com } 769799Snilay@cs.wisc.edu timeSlots.clear(); 776145Snate@binkert.org 787055Snate@binkert.org // gem5 events. 796145Snate@binkert.org if (readyEvent.scheduled()) 809302Snilay@cs.wisc.edu deschedule(&readyEvent); 819302Snilay@cs.wisc.edu if (pauseEvent.scheduled()) 829302Snilay@cs.wisc.edu deschedule(&pauseEvent); 837054Snate@binkert.org if (stopEvent.scheduled()) 847054Snate@binkert.org deschedule(&stopEvent); 857054Snate@binkert.org if (starvationEvent.scheduled()) 867054Snate@binkert.org deschedule(&starvationEvent); 877054Snate@binkert.org if (maxTickEvent.scheduled()) 887054Snate@binkert.org deschedule(&maxTickEvent); 896145Snate@binkert.org 907054Snate@binkert.org Process *p; 917054Snate@binkert.org while ((p = initList.getNext())) 927054Snate@binkert.org p->popListNode(); 9310311Snilay@cs.wisc.edu while ((p = readyListMethods.getNext())) 949858Snilay@cs.wisc.edu p->popListNode(); 9511021Sjthestness@gmail.com while ((p = readyListThreads.getNext())) 9611021Sjthestness@gmail.com p->popListNode(); 9711049Snilay@cs.wisc.edu 9811049Snilay@cs.wisc.edu Channel *c; 9911049Snilay@cs.wisc.edu while ((c = updateList.getNext())) 10011049Snilay@cs.wisc.edu c->popListNode(); 10111049Snilay@cs.wisc.edu} 1029863Snilay@cs.wisc.edu 1039863Snilay@cs.wisc.eduvoid 1049866Sjthestness@gmail.comScheduler::initPhase() 1059866Sjthestness@gmail.com{ 1066145Snate@binkert.org for (Process *p = initList.getNext(); p; p = initList.getNext()) { 1076145Snate@binkert.org p->popListNode(); 1087055Snate@binkert.org 1097055Snate@binkert.org if (p->dontInitialize()) { 1106145Snate@binkert.org if (!p->hasStaticSensitivities() && !p->internal()) { 1117054Snate@binkert.org SC_REPORT_WARNING( 1127055Snate@binkert.org "(W558) disable() or dont_initialize() called on " 1137054Snate@binkert.org "process with no static sensitivity, it will be " 1146145Snate@binkert.org "orphaned", p->name()); 1156145Snate@binkert.org } 1167054Snate@binkert.org } else { 117 p->ready(); 118 } 119 } 120 121 runUpdate(); 122 runDelta(); 123 124 for (auto ets: eventsToSchedule) 125 eq->schedule(ets.first, ets.second); 126 eventsToSchedule.clear(); 127 128 if (_started) { 129 if (!runToTime && starved()) 130 scheduleStarvationEvent(); 131 kernel->status(::sc_core::SC_RUNNING); 132 } 133 134 initDone = true; 135 136 status(StatusOther); 137} 138 139void 140Scheduler::reg(Process *p) 141{ 142 if (initDone) { 143 // If not marked as dontInitialize, mark as ready. 144 if (!p->dontInitialize()) 145 p->ready(); 146 } else { 147 // Otherwise, record that this process should be initialized once we 148 // get there. 149 initList.pushLast(p); 150 } 151} 152 153void 154Scheduler::yield() 155{ 156 // Pull a process from the active list. 157 _current = readyList->getNext(); 158 if (!_current) { 159 // There are no more processes, so return control to evaluate. 160 Fiber::primaryFiber()->run(); 161 } else { 162 _current->popListNode(); 163 // Switch to whatever Fiber is supposed to run this process. All 164 // Fibers which aren't running should be parked at this line. 165 _current->fiber()->run(); 166 // If the current process needs to be manually started, start it. 167 if (_current && _current->needsStart()) { 168 _current->needsStart(false); 169 try { 170 _current->run(); 171 } catch (...) { 172 throwToScMain(); 173 } 174 } 175 } 176 if (_current && _current->excWrapper) { 177 // Make sure this isn't a method process. 178 assert(!_current->needsStart()); 179 auto ew = _current->excWrapper; 180 _current->excWrapper = nullptr; 181 ew->throw_it(); 182 } 183} 184 185void 186Scheduler::ready(Process *p) 187{ 188 if (_stopNow) 189 return; 190 191 if (p->procKind() == ::sc_core::SC_METHOD_PROC_) 192 readyListMethods.pushLast(p); 193 else 194 readyListThreads.pushLast(p); 195 196 scheduleReadyEvent(); 197} 198 199void 200Scheduler::resume(Process *p) 201{ 202 if (initDone) 203 ready(p); 204 else 205 initList.pushLast(p); 206} 207 208bool 209listContains(ListNode *list, ListNode *target) 210{ 211 ListNode *n = list->nextListNode; 212 while (n != list) 213 if (n == target) 214 return true; 215 return false; 216} 217 218bool 219Scheduler::suspend(Process *p) 220{ 221 bool was_ready; 222 if (initDone) { 223 // After initialization, check if we're on a ready list. 224 was_ready = (p->nextListNode != nullptr); 225 p->popListNode(); 226 } else { 227 // Nothing is ready before init. 228 was_ready = false; 229 } 230 return was_ready; 231} 232 233void 234Scheduler::requestUpdate(Channel *c) 235{ 236 updateList.pushLast(c); 237 scheduleReadyEvent(); 238} 239 240void 241Scheduler::scheduleReadyEvent() 242{ 243 // Schedule the evaluate and update phases. 244 if (!readyEvent.scheduled()) { 245 schedule(&readyEvent); 246 if (starvationEvent.scheduled()) 247 deschedule(&starvationEvent); 248 } 249} 250 251void 252Scheduler::scheduleStarvationEvent() 253{ 254 if (!starvationEvent.scheduled()) { 255 schedule(&starvationEvent); 256 if (readyEvent.scheduled()) 257 deschedule(&readyEvent); 258 } 259} 260 261void 262Scheduler::runReady() 263{ 264 bool empty = readyListMethods.empty() && readyListThreads.empty(); 265 lastReadyTick = getCurTick(); 266 267 // The evaluation phase. 268 do { 269 // We run methods and threads in two seperate passes to emulate how 270 // Accellera orders things, but without having to scan through a 271 // unified list to find the next process of the correct type. 272 readyList = &readyListMethods; 273 while (!readyListMethods.empty()) 274 yield(); 275 276 readyList = &readyListThreads; 277 while (!readyListThreads.empty()) 278 yield(); 279 280 // We already know that readyListThreads is empty at this point. 281 } while (!readyListMethods.empty()); 282 283 if (!empty) { 284 _numCycles++; 285 _changeStamp++; 286 } 287 288 if (_stopNow) 289 return; 290 291 runUpdate(); 292 runDelta(); 293 294 if (!runToTime && starved()) 295 scheduleStarvationEvent(); 296 297 if (runOnce) 298 schedulePause(); 299 300 status(StatusOther); 301} 302 303void 304Scheduler::runUpdate() 305{ 306 status(StatusUpdate); 307 308 try { 309 Channel *channel = updateList.getNext(); 310 while (channel) { 311 channel->popListNode(); 312 channel->update(); 313 channel = updateList.getNext(); 314 } 315 } catch (...) { 316 throwToScMain(); 317 } 318} 319 320void 321Scheduler::runDelta() 322{ 323 status(StatusDelta); 324 325 try { 326 while (!deltas.empty()) 327 deltas.front()->run(); 328 } catch (...) { 329 throwToScMain(); 330 } 331} 332 333void 334Scheduler::pause() 335{ 336 status(StatusPaused); 337 kernel->status(::sc_core::SC_PAUSED); 338 runOnce = false; 339 if (scMain && !scMain->finished()) 340 scMain->run(); 341} 342 343void 344Scheduler::stop() 345{ 346 status(StatusStopped); 347 kernel->stop(); 348 349 clear(); 350 351 runOnce = false; 352 if (scMain && !scMain->finished()) 353 scMain->run(); 354} 355 356void 357Scheduler::start(Tick max_tick, bool run_to_time) 358{ 359 // We should be running from sc_main. Keep track of that Fiber to return 360 // to later. 361 scMain = Fiber::currentFiber(); 362 363 _started = true; 364 status(StatusOther); 365 runToTime = run_to_time; 366 367 maxTick = max_tick; 368 lastReadyTick = getCurTick(); 369 370 if (initDone) { 371 if (!runToTime && starved()) 372 scheduleStarvationEvent(); 373 kernel->status(::sc_core::SC_RUNNING); 374 } 375 376 schedule(&maxTickEvent, maxTick); 377 378 // Return to gem5 to let it run events, etc. 379 Fiber::primaryFiber()->run(); 380 381 if (pauseEvent.scheduled()) 382 deschedule(&pauseEvent); 383 if (stopEvent.scheduled()) 384 deschedule(&stopEvent); 385 if (maxTickEvent.scheduled()) 386 deschedule(&maxTickEvent); 387 if (starvationEvent.scheduled()) 388 deschedule(&starvationEvent); 389 390 if (_throwToScMain) { 391 const ::sc_core::sc_report *to_throw = _throwToScMain; 392 _throwToScMain = nullptr; 393 throw *to_throw; 394 } 395} 396 397void 398Scheduler::oneCycle() 399{ 400 runOnce = true; 401 scheduleReadyEvent(); 402 start(::MaxTick, false); 403} 404 405void 406Scheduler::schedulePause() 407{ 408 if (pauseEvent.scheduled()) 409 return; 410 411 schedule(&pauseEvent); 412} 413 414void 415Scheduler::throwToScMain(const ::sc_core::sc_report *r) 416{ 417 if (!r) 418 r = reportifyException(); 419 _throwToScMain = r; 420 status(StatusOther); 421 scMain->run(); 422} 423 424void 425Scheduler::scheduleStop(bool finish_delta) 426{ 427 if (stopEvent.scheduled()) 428 return; 429 430 if (!finish_delta) { 431 _stopNow = true; 432 // If we're not supposed to finish the delta cycle, flush all 433 // pending activity. 434 clear(); 435 } 436 schedule(&stopEvent); 437} 438 439Scheduler scheduler; 440 441namespace { 442 443void 444throwingReportHandler(const ::sc_core::sc_report &r, 445 const ::sc_core::sc_actions &) 446{ 447 throw r; 448} 449 450} // anonymous namespace 451 452const ::sc_core::sc_report * 453reportifyException() 454{ 455 ::sc_core::sc_report_handler_proc old_handler = 456 ::sc_core::sc_report_handler::get_handler(); 457 ::sc_core::sc_report_handler::set_handler(&throwingReportHandler); 458 459 try { 460 try { 461 // Rethrow the current exception so we can catch it and throw an 462 // sc_report instead if it's not a type we recognize/can handle. 463 throw; 464 } catch (const ::sc_core::sc_report &) { 465 // It's already a sc_report, so nothing to do. 466 throw; 467 } catch (const ::sc_core::sc_unwind_exception &) { 468 panic("Kill/reset exception escaped a Process::run()"); 469 } catch (const std::exception &e) { 470 SC_REPORT_ERROR("uncaught exception", e.what()); 471 } catch (const char *msg) { 472 SC_REPORT_ERROR("uncaught exception", msg); 473 } catch (...) { 474 SC_REPORT_ERROR("uncaught exception", "UNKNOWN EXCEPTION"); 475 } 476 } catch (const ::sc_core::sc_report &r) { 477 ::sc_core::sc_report_handler::set_handler(old_handler); 478 return &r; 479 } 480 panic("No exception thrown in reportifyException."); 481} 482 483} // namespace sc_gem5 484