scheduler.cc revision 13329:a2d273c8e667
14486Sbinkertn@umich.edu/* 24486Sbinkertn@umich.edu * Copyright 2018 Google, Inc. 34486Sbinkertn@umich.edu * 44486Sbinkertn@umich.edu * Redistribution and use in source and binary forms, with or without 54486Sbinkertn@umich.edu * modification, are permitted provided that the following conditions are 64486Sbinkertn@umich.edu * met: redistributions of source code must retain the above copyright 74486Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer; 84486Sbinkertn@umich.edu * redistributions in binary form must reproduce the above copyright 94486Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer in the 104486Sbinkertn@umich.edu * documentation and/or other materials provided with the distribution; 114486Sbinkertn@umich.edu * neither the name of the copyright holders nor the names of its 124486Sbinkertn@umich.edu * contributors may be used to endorse or promote products derived from 134486Sbinkertn@umich.edu * this software without specific prior written permission. 144486Sbinkertn@umich.edu * 154486Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 164486Sbinkertn@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 174486Sbinkertn@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 184486Sbinkertn@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 194486Sbinkertn@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 204486Sbinkertn@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 214486Sbinkertn@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 224486Sbinkertn@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 234486Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 244486Sbinkertn@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 254486Sbinkertn@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 264486Sbinkertn@umich.edu * 274486Sbinkertn@umich.edu * Authors: Gabe Black 284486Sbinkertn@umich.edu */ 293630SN/A 303630SN/A#include "systemc/core/scheduler.hh" 314104SN/A 325478Snate@binkert.org#include "base/fiber.hh" 335478Snate@binkert.org#include "base/logging.hh" 343743SN/A#include "sim/eventq.hh" 353630SN/A#include "systemc/core/kernel.hh" 363898SN/A#include "systemc/ext/core/messages.hh" 373898SN/A#include "systemc/ext/core/sc_main.hh" 383898SN/A#include "systemc/ext/utils/sc_report.hh" 399338SAndreas.Sandberg@arm.com#include "systemc/ext/utils/sc_report_handler.hh" 403898SN/A#include "systemc/utils/report.hh" 413898SN/A#include "systemc/utils/tracefile.hh" 423898SN/A 433914SN/Anamespace sc_gem5 443914SN/A{ 459338SAndreas.Sandberg@arm.com 463914SN/AScheduler::Scheduler() : 473914SN/A eq(nullptr), readyEvent(this, false, ReadyPriority), 483914SN/A pauseEvent(this, false, PausePriority), 494104SN/A stopEvent(this, false, StopPriority), 504104SN/A scMain(nullptr), _throwToScMain(nullptr), 519338SAndreas.Sandberg@arm.com starvationEvent(this, false, StarvationPriority), 528742Sgblack@eecs.umich.edu _elaborationDone(false), _started(false), _stopNow(false), 539162Sandreas.hansson@arm.com _status(StatusOther), maxTickEvent(this, false, MaxTickPriority), 544104SN/A timeAdvancesEvent(this, false, TimeAdvancesPriority), _numCycles(0), 553914SN/A _changeStamp(0), _current(nullptr), initDone(false), runOnce(false) 563630SN/A{} 573630SN/A 589338SAndreas.Sandberg@arm.comScheduler::~Scheduler() 593630SN/A{ 603630SN/A // Clear out everything that belongs to us to make sure nobody tries to 614007SN/A // clear themselves out after the scheduler goes away. 624007SN/A clear(); 633630SN/A} 643814SN/A 654007SN/Avoid 664007SN/AScheduler::clear() 673814SN/A{ 684007SN/A // Delta notifications. 694007SN/A while (!deltas.empty()) 703814SN/A deltas.front()->deschedule(); 713814SN/A 724007SN/A // Timed notifications. 734007SN/A for (auto &tsp: timeSlots) { 743814SN/A TimeSlot *&ts = tsp.second; 753814SN/A while (!ts->events.empty()) 764007SN/A ts->events.front()->deschedule(); 774007SN/A deschedule(ts); 783814SN/A } 793814SN/A timeSlots.clear(); 804007SN/A 814007SN/A // gem5 events. 823814SN/A if (readyEvent.scheduled()) 833814SN/A deschedule(&readyEvent); 844007SN/A if (pauseEvent.scheduled()) 854007SN/A deschedule(&pauseEvent); 863814SN/A if (stopEvent.scheduled()) 873825SN/A deschedule(&stopEvent); 884007SN/A if (starvationEvent.scheduled()) 894007SN/A deschedule(&starvationEvent); 903825SN/A if (maxTickEvent.scheduled()) 913825SN/A deschedule(&maxTickEvent); 924007SN/A if (timeAdvancesEvent.scheduled()) 934007SN/A deschedule(&timeAdvancesEvent); 943825SN/A 953825SN/A Process *p; 964007SN/A while ((p = initList.getNext())) 974007SN/A p->popListNode(); 983825SN/A while ((p = readyListMethods.getNext())) 993825SN/A p->popListNode(); 1004007SN/A while ((p = readyListThreads.getNext())) 1014007SN/A p->popListNode(); 1023825SN/A 1034007SN/A Channel *c; 1044007SN/A while ((c = updateList.getNext())) 1053814SN/A c->popListNode(); 1065478Snate@binkert.org} 1073814SN/A 1083914SN/Avoid 1093914SN/AScheduler::initPhase() 1105478Snate@binkert.org{ 1113814SN/A for (Process *p = initList.getNext(); p; p = initList.getNext()) { 1123630SN/A p->popListNode(); 1134104SN/A 1144104SN/A if (p->dontInitialize()) { 1154104SN/A if (!p->hasStaticSensitivities() && !p->internal()) { 1168847Sandreas.hansson@arm.com SC_REPORT_WARNING(sc_core::SC_ID_DISABLE_WILL_ORPHAN_PROCESS_, 1178847Sandreas.hansson@arm.com p->name()); 1184104SN/A } 1194104SN/A } else { 1203630SN/A p->ready(); 1213630SN/A } 1223630SN/A } 1233630SN/A 12412274Sgabeblack@google.com runUpdate(); 12512274Sgabeblack@google.com runDelta(); 1268847Sandreas.hansson@arm.com 1278847Sandreas.hansson@arm.com for (auto ets: eventsToSchedule) 1288847Sandreas.hansson@arm.com eq->schedule(ets.first, ets.second); 1298847Sandreas.hansson@arm.com eventsToSchedule.clear(); 1308847Sandreas.hansson@arm.com 1318847Sandreas.hansson@arm.com if (_started) { 1328847Sandreas.hansson@arm.com if (!runToTime && starved()) 1338847Sandreas.hansson@arm.com scheduleStarvationEvent(); 1348847Sandreas.hansson@arm.com kernel->status(::sc_core::SC_RUNNING); 1358847Sandreas.hansson@arm.com } 1368847Sandreas.hansson@arm.com 1378847Sandreas.hansson@arm.com initDone = true; 1388847Sandreas.hansson@arm.com 1398847Sandreas.hansson@arm.com status(StatusOther); 140 141 scheduleTimeAdvancesEvent(); 142} 143 144void 145Scheduler::reg(Process *p) 146{ 147 if (initDone) { 148 // If not marked as dontInitialize, mark as ready. 149 if (!p->dontInitialize()) 150 p->ready(); 151 } else { 152 // Otherwise, record that this process should be initialized once we 153 // get there. 154 initList.pushLast(p); 155 } 156} 157 158void 159Scheduler::yield() 160{ 161 // Pull a process from the active list. 162 _current = getNextReady(); 163 if (!_current) { 164 // There are no more processes, so return control to evaluate. 165 Fiber::primaryFiber()->run(); 166 } else { 167 _current->popListNode(); 168 _current->scheduled(false); 169 // Switch to whatever Fiber is supposed to run this process. All 170 // Fibers which aren't running should be parked at this line. 171 _current->fiber()->run(); 172 // If the current process needs to be manually started, start it. 173 if (_current && _current->needsStart()) { 174 _current->needsStart(false); 175 // If a process hasn't started yet, "resetting" it just starts it 176 // and signals its reset event. 177 if (_current->inReset()) 178 _current->resetEvent().notify(); 179 try { 180 _current->run(); 181 } catch (...) { 182 throwToScMain(); 183 } 184 } 185 } 186 if (_current && !_current->needsStart()) { 187 if (_current->excWrapper) { 188 auto ew = _current->excWrapper; 189 _current->excWrapper = nullptr; 190 ew->throw_it(); 191 } else if (_current->inReset()) { 192 _current->reset(false); 193 } 194 } 195} 196 197void 198Scheduler::ready(Process *p) 199{ 200 if (_stopNow) 201 return; 202 203 p->scheduled(true); 204 205 if (p->procKind() == ::sc_core::SC_METHOD_PROC_) 206 readyListMethods.pushLast(p); 207 else 208 readyListThreads.pushLast(p); 209 210 if (!inEvaluate()) 211 scheduleReadyEvent(); 212} 213 214void 215Scheduler::resume(Process *p) 216{ 217 if (initDone) 218 ready(p); 219 else 220 initList.pushLast(p); 221} 222 223bool 224listContains(ListNode *list, ListNode *target) 225{ 226 ListNode *n = list->nextListNode; 227 while (n != list) 228 if (n == target) 229 return true; 230 return false; 231} 232 233bool 234Scheduler::suspend(Process *p) 235{ 236 bool was_ready; 237 if (initDone) { 238 // After initialization, check if we're on a ready list. 239 was_ready = (p->nextListNode != nullptr); 240 p->popListNode(); 241 } else { 242 // Nothing is ready before init. 243 was_ready = false; 244 } 245 return was_ready; 246} 247 248void 249Scheduler::requestUpdate(Channel *c) 250{ 251 updateList.pushLast(c); 252 if (!inEvaluate()) 253 scheduleReadyEvent(); 254} 255 256void 257Scheduler::scheduleReadyEvent() 258{ 259 // Schedule the evaluate and update phases. 260 if (!readyEvent.scheduled()) { 261 schedule(&readyEvent); 262 if (starvationEvent.scheduled()) 263 deschedule(&starvationEvent); 264 } 265} 266 267void 268Scheduler::scheduleStarvationEvent() 269{ 270 if (!starvationEvent.scheduled()) { 271 schedule(&starvationEvent); 272 if (readyEvent.scheduled()) 273 deschedule(&readyEvent); 274 } 275} 276 277void 278Scheduler::runReady() 279{ 280 scheduleTimeAdvancesEvent(); 281 282 bool empty = readyListMethods.empty() && readyListThreads.empty(); 283 lastReadyTick = getCurTick(); 284 285 // The evaluation phase. 286 status(StatusEvaluate); 287 do { 288 yield(); 289 } while (getNextReady()); 290 _current = nullptr; 291 292 if (!empty) { 293 _numCycles++; 294 _changeStamp++; 295 } 296 297 if (_stopNow) { 298 status(StatusOther); 299 return; 300 } 301 302 runUpdate(); 303 if (!traceFiles.empty()) 304 trace(true); 305 runDelta(); 306 307 if (!runToTime && starved()) 308 scheduleStarvationEvent(); 309 310 if (runOnce) 311 schedulePause(); 312 313 status(StatusOther); 314} 315 316void 317Scheduler::runUpdate() 318{ 319 status(StatusUpdate); 320 321 try { 322 Channel *channel = updateList.getNext(); 323 while (channel) { 324 channel->popListNode(); 325 channel->update(); 326 channel = updateList.getNext(); 327 } 328 } catch (...) { 329 throwToScMain(); 330 } 331} 332 333void 334Scheduler::runDelta() 335{ 336 status(StatusDelta); 337 338 try { 339 while (!deltas.empty()) 340 deltas.back()->run(); 341 } catch (...) { 342 throwToScMain(); 343 } 344} 345 346void 347Scheduler::pause() 348{ 349 status(StatusPaused); 350 kernel->status(::sc_core::SC_PAUSED); 351 runOnce = false; 352 if (scMain && !scMain->finished()) 353 scMain->run(); 354} 355 356void 357Scheduler::stop() 358{ 359 status(StatusStopped); 360 kernel->stop(); 361 362 clear(); 363 364 runOnce = false; 365 if (scMain && !scMain->finished()) 366 scMain->run(); 367} 368 369void 370Scheduler::start(Tick max_tick, bool run_to_time) 371{ 372 // We should be running from sc_main. Keep track of that Fiber to return 373 // to later. 374 scMain = Fiber::currentFiber(); 375 376 _started = true; 377 status(StatusOther); 378 runToTime = run_to_time; 379 380 maxTick = max_tick; 381 lastReadyTick = getCurTick(); 382 383 if (initDone) { 384 if (!runToTime && starved()) 385 scheduleStarvationEvent(); 386 kernel->status(::sc_core::SC_RUNNING); 387 } 388 389 schedule(&maxTickEvent, maxTick); 390 scheduleTimeAdvancesEvent(); 391 392 // Return to gem5 to let it run events, etc. 393 Fiber::primaryFiber()->run(); 394 395 if (pauseEvent.scheduled()) 396 deschedule(&pauseEvent); 397 if (stopEvent.scheduled()) 398 deschedule(&stopEvent); 399 if (maxTickEvent.scheduled()) 400 deschedule(&maxTickEvent); 401 if (starvationEvent.scheduled()) 402 deschedule(&starvationEvent); 403 404 if (_throwToScMain) { 405 const ::sc_core::sc_report *to_throw = _throwToScMain; 406 _throwToScMain = nullptr; 407 throw *to_throw; 408 } 409} 410 411void 412Scheduler::oneCycle() 413{ 414 runOnce = true; 415 scheduleReadyEvent(); 416 start(::MaxTick, false); 417} 418 419void 420Scheduler::schedulePause() 421{ 422 if (pauseEvent.scheduled()) 423 return; 424 425 schedule(&pauseEvent); 426} 427 428void 429Scheduler::throwToScMain() 430{ 431 ::sc_core::sc_report report = reportifyException(); 432 _throwToScMain = &report; 433 status(StatusOther); 434 scMain->run(); 435} 436 437void 438Scheduler::scheduleStop(bool finish_delta) 439{ 440 if (stopEvent.scheduled()) 441 return; 442 443 if (!finish_delta) { 444 _stopNow = true; 445 // If we're not supposed to finish the delta cycle, flush all 446 // pending activity. 447 clear(); 448 } 449 schedule(&stopEvent); 450} 451 452void 453Scheduler::trace(bool delta) 454{ 455 for (auto tf: traceFiles) 456 tf->trace(delta); 457} 458 459Scheduler scheduler; 460Process *getCurrentProcess() { return scheduler.current(); } 461 462namespace { 463 464void 465throwingReportHandler(const ::sc_core::sc_report &r, 466 const ::sc_core::sc_actions &) 467{ 468 throw r; 469} 470 471} // anonymous namespace 472 473const ::sc_core::sc_report 474reportifyException() 475{ 476 ::sc_core::sc_report_handler_proc old_handler = reportHandlerProc; 477 ::sc_core::sc_report_handler::set_handler(&throwingReportHandler); 478 479 try { 480 try { 481 // Rethrow the current exception so we can catch it and throw an 482 // sc_report instead if it's not a type we recognize/can handle. 483 throw; 484 } catch (const ::sc_core::sc_report &) { 485 // It's already a sc_report, so nothing to do. 486 throw; 487 } catch (const ::sc_core::sc_unwind_exception &) { 488 panic("Kill/reset exception escaped a Process::run()"); 489 } catch (const std::exception &e) { 490 SC_REPORT_ERROR( 491 sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_, e.what()); 492 } catch (const char *msg) { 493 SC_REPORT_ERROR( 494 sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_, msg); 495 } catch (...) { 496 SC_REPORT_ERROR( 497 sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_, 498 "UNKNOWN EXCEPTION"); 499 } 500 } catch (const ::sc_core::sc_report &r) { 501 ::sc_core::sc_report_handler::set_handler(old_handler); 502 return r; 503 } 504 panic("No exception thrown in reportifyException."); 505} 506 507} // namespace sc_gem5 508