scheduler.cc revision 13244:deedec45898f
12SN/A/* 21762SN/A * Copyright 2018 Google, Inc. 32SN/A * 42SN/A * Redistribution and use in source and binary forms, with or without 52SN/A * modification, are permitted provided that the following conditions are 62SN/A * met: redistributions of source code must retain the above copyright 72SN/A * notice, this list of conditions and the following disclaimer; 82SN/A * redistributions in binary form must reproduce the above copyright 92SN/A * notice, this list of conditions and the following disclaimer in the 102SN/A * documentation and/or other materials provided with the distribution; 112SN/A * neither the name of the copyright holders nor the names of its 122SN/A * contributors may be used to endorse or promote products derived from 132SN/A * this software without specific prior written permission. 142SN/A * 152SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 162SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 172SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 182SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 192SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 202SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 212SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 222SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 232SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 242SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 252SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 262SN/A * 272665Ssaidi@eecs.umich.edu * Authors: Gabe Black 282665Ssaidi@eecs.umich.edu */ 292SN/A 302SN/A#include "systemc/core/scheduler.hh" 312SN/A 327840Snate@binkert.org#include "base/fiber.hh" 332SN/A#include "base/logging.hh" 34400SN/A#include "sim/eventq.hh" 357840Snate@binkert.org#include "systemc/core/kernel.hh" 367862Sgblack@eecs.umich.edu#include "systemc/ext/core/sc_main.hh" 377870Sgblack@eecs.umich.edu#include "systemc/ext/utils/sc_report.hh" 382SN/A#include "systemc/ext/utils/sc_report_handler.hh" 392SN/A 402SN/Anamespace sc_gem5 417840Snate@binkert.org{ 427840Snate@binkert.org 432SN/AScheduler::Scheduler() : 447840Snate@binkert.org eq(nullptr), readyEvent(this, false, ReadyPriority), 457840Snate@binkert.org pauseEvent(this, false, PausePriority), 467840Snate@binkert.org stopEvent(this, false, StopPriority), 47400SN/A scMain(nullptr), _throwToScMain(nullptr), 487840Snate@binkert.org starvationEvent(this, false, StarvationPriority), 497840Snate@binkert.org _elaborationDone(false), _started(false), _stopNow(false), 507840Snate@binkert.org _status(StatusOther), maxTickEvent(this, false, MaxTickPriority), 51400SN/A _numCycles(0), _changeStamp(0), _current(nullptr), initDone(false), 52400SN/A runOnce(false) 537862Sgblack@eecs.umich.edu{} 547862Sgblack@eecs.umich.edu 557862Sgblack@eecs.umich.eduScheduler::~Scheduler() 567862Sgblack@eecs.umich.edu{ 577862Sgblack@eecs.umich.edu // Clear out everything that belongs to us to make sure nobody tries to 587862Sgblack@eecs.umich.edu // clear themselves out after the scheduler goes away. 597862Sgblack@eecs.umich.edu clear(); 607862Sgblack@eecs.umich.edu} 617862Sgblack@eecs.umich.edu 627862Sgblack@eecs.umich.eduvoid 637862Sgblack@eecs.umich.eduScheduler::clear() 647862Sgblack@eecs.umich.edu{ 657862Sgblack@eecs.umich.edu // Delta notifications. 66400SN/A while (!deltas.empty()) 677840Snate@binkert.org deltas.front()->deschedule(); 68400SN/A 697840Snate@binkert.org // Timed notifications. 70400SN/A for (auto &tsp: timeSlots) { 71400SN/A TimeSlot *&ts = tsp.second; 72400SN/A while (!ts->events.empty()) 733918Ssaidi@eecs.umich.edu ts->events.front()->deschedule(); 747840Snate@binkert.org deschedule(ts); 753918Ssaidi@eecs.umich.edu } 76400SN/A timeSlots.clear(); 773918Ssaidi@eecs.umich.edu 78400SN/A // gem5 events. 79400SN/A if (readyEvent.scheduled()) 802SN/A deschedule(&readyEvent); 812SN/A if (pauseEvent.scheduled()) 82400SN/A deschedule(&pauseEvent); 83400SN/A if (stopEvent.scheduled()) 84400SN/A deschedule(&stopEvent); 85400SN/A if (starvationEvent.scheduled()) 862SN/A deschedule(&starvationEvent); 877840Snate@binkert.org if (maxTickEvent.scheduled()) 887840Snate@binkert.org deschedule(&maxTickEvent); 89400SN/A 907840Snate@binkert.org Process *p; 917840Snate@binkert.org while ((p = initList.getNext())) 927840Snate@binkert.org p->popListNode(); 937840Snate@binkert.org while ((p = readyListMethods.getNext())) 947840Snate@binkert.org p->popListNode(); 957840Snate@binkert.org while ((p = readyListThreads.getNext())) 967840Snate@binkert.org p->popListNode(); 977840Snate@binkert.org 987840Snate@binkert.org Channel *c; 997840Snate@binkert.org while ((c = updateList.getNext())) 1007840Snate@binkert.org c->popListNode(); 1017840Snate@binkert.org} 1027840Snate@binkert.org 1037840Snate@binkert.orgvoid 1047840Snate@binkert.orgScheduler::initPhase() 1057840Snate@binkert.org{ 1067840Snate@binkert.org for (Process *p = initList.getNext(); p; p = initList.getNext()) { 1077840Snate@binkert.org p->popListNode(); 1087840Snate@binkert.org 1097840Snate@binkert.org if (p->dontInitialize()) { 1107840Snate@binkert.org if (!p->hasStaticSensitivities() && !p->internal()) { 1117840Snate@binkert.org SC_REPORT_WARNING( 1127840Snate@binkert.org "(W558) disable() or dont_initialize() called on " 1137840Snate@binkert.org "process with no static sensitivity, it will be " 1147840Snate@binkert.org "orphaned", p->name()); 115400SN/A } 1162SN/A } else { 1177840Snate@binkert.org p->ready(); 1187870Sgblack@eecs.umich.edu } 1197870Sgblack@eecs.umich.edu } 1207870Sgblack@eecs.umich.edu 1217870Sgblack@eecs.umich.edu runUpdate(); 1227870Sgblack@eecs.umich.edu runDelta(); 1237870Sgblack@eecs.umich.edu 1247870Sgblack@eecs.umich.edu for (auto ets: eventsToSchedule) 1257870Sgblack@eecs.umich.edu eq->schedule(ets.first, ets.second); 1267870Sgblack@eecs.umich.edu eventsToSchedule.clear(); 1277870Sgblack@eecs.umich.edu 1287870Sgblack@eecs.umich.edu if (_started) { 1297870Sgblack@eecs.umich.edu if (!runToTime && starved()) 1307870Sgblack@eecs.umich.edu scheduleStarvationEvent(); 1317870Sgblack@eecs.umich.edu kernel->status(::sc_core::SC_RUNNING); 1327870Sgblack@eecs.umich.edu } 1337870Sgblack@eecs.umich.edu 1347870Sgblack@eecs.umich.edu initDone = true; 1357870Sgblack@eecs.umich.edu 1367870Sgblack@eecs.umich.edu status(StatusOther); 1377840Snate@binkert.org} 138400SN/A 1397840Snate@binkert.orgvoid 1407840Snate@binkert.orgScheduler::reg(Process *p) 1417840Snate@binkert.org{ 1427840Snate@binkert.org if (initDone) { 1437840Snate@binkert.org // If not marked as dontInitialize, mark as ready. 1447840Snate@binkert.org if (!p->dontInitialize()) 1457840Snate@binkert.org p->ready(); 146400SN/A } 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 = getNextReady(); 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 if (!inEvaluate()) 197 scheduleReadyEvent(); 198} 199 200void 201Scheduler::resume(Process *p) 202{ 203 if (initDone) 204 ready(p); 205 else 206 initList.pushLast(p); 207} 208 209bool 210listContains(ListNode *list, ListNode *target) 211{ 212 ListNode *n = list->nextListNode; 213 while (n != list) 214 if (n == target) 215 return true; 216 return false; 217} 218 219bool 220Scheduler::suspend(Process *p) 221{ 222 bool was_ready; 223 if (initDone) { 224 // After initialization, check if we're on a ready list. 225 was_ready = (p->nextListNode != nullptr); 226 p->popListNode(); 227 } else { 228 // Nothing is ready before init. 229 was_ready = false; 230 } 231 return was_ready; 232} 233 234void 235Scheduler::requestUpdate(Channel *c) 236{ 237 updateList.pushLast(c); 238 if (!inEvaluate()) 239 scheduleReadyEvent(); 240} 241 242void 243Scheduler::scheduleReadyEvent() 244{ 245 // Schedule the evaluate and update phases. 246 if (!readyEvent.scheduled()) { 247 schedule(&readyEvent); 248 if (starvationEvent.scheduled()) 249 deschedule(&starvationEvent); 250 } 251} 252 253void 254Scheduler::scheduleStarvationEvent() 255{ 256 if (!starvationEvent.scheduled()) { 257 schedule(&starvationEvent); 258 if (readyEvent.scheduled()) 259 deschedule(&readyEvent); 260 } 261} 262 263void 264Scheduler::runReady() 265{ 266 bool empty = readyListMethods.empty() && readyListThreads.empty(); 267 lastReadyTick = getCurTick(); 268 269 // The evaluation phase. 270 do { 271 yield(); 272 } while (getNextReady()); 273 274 if (!empty) { 275 _numCycles++; 276 _changeStamp++; 277 } 278 279 if (_stopNow) { 280 status(StatusOther); 281 return; 282 } 283 284 runUpdate(); 285 runDelta(); 286 287 if (!runToTime && starved()) 288 scheduleStarvationEvent(); 289 290 if (runOnce) 291 schedulePause(); 292 293 status(StatusOther); 294} 295 296void 297Scheduler::runUpdate() 298{ 299 status(StatusUpdate); 300 301 try { 302 Channel *channel = updateList.getNext(); 303 while (channel) { 304 channel->popListNode(); 305 channel->update(); 306 channel = updateList.getNext(); 307 } 308 } catch (...) { 309 throwToScMain(); 310 } 311} 312 313void 314Scheduler::runDelta() 315{ 316 status(StatusDelta); 317 318 try { 319 while (!deltas.empty()) 320 deltas.front()->run(); 321 } catch (...) { 322 throwToScMain(); 323 } 324} 325 326void 327Scheduler::pause() 328{ 329 status(StatusPaused); 330 kernel->status(::sc_core::SC_PAUSED); 331 runOnce = false; 332 if (scMain && !scMain->finished()) 333 scMain->run(); 334} 335 336void 337Scheduler::stop() 338{ 339 status(StatusStopped); 340 kernel->stop(); 341 342 clear(); 343 344 runOnce = false; 345 if (scMain && !scMain->finished()) 346 scMain->run(); 347} 348 349void 350Scheduler::start(Tick max_tick, bool run_to_time) 351{ 352 // We should be running from sc_main. Keep track of that Fiber to return 353 // to later. 354 scMain = Fiber::currentFiber(); 355 356 _started = true; 357 status(StatusOther); 358 runToTime = run_to_time; 359 360 maxTick = max_tick; 361 lastReadyTick = getCurTick(); 362 363 if (initDone) { 364 if (!runToTime && starved()) 365 scheduleStarvationEvent(); 366 kernel->status(::sc_core::SC_RUNNING); 367 } 368 369 schedule(&maxTickEvent, maxTick); 370 371 // Return to gem5 to let it run events, etc. 372 Fiber::primaryFiber()->run(); 373 374 if (pauseEvent.scheduled()) 375 deschedule(&pauseEvent); 376 if (stopEvent.scheduled()) 377 deschedule(&stopEvent); 378 if (maxTickEvent.scheduled()) 379 deschedule(&maxTickEvent); 380 if (starvationEvent.scheduled()) 381 deschedule(&starvationEvent); 382 383 if (_throwToScMain) { 384 const ::sc_core::sc_report *to_throw = _throwToScMain; 385 _throwToScMain = nullptr; 386 throw *to_throw; 387 } 388} 389 390void 391Scheduler::oneCycle() 392{ 393 runOnce = true; 394 scheduleReadyEvent(); 395 start(::MaxTick, false); 396} 397 398void 399Scheduler::schedulePause() 400{ 401 if (pauseEvent.scheduled()) 402 return; 403 404 schedule(&pauseEvent); 405} 406 407void 408Scheduler::throwToScMain(const ::sc_core::sc_report *r) 409{ 410 if (!r) 411 r = reportifyException(); 412 _throwToScMain = r; 413 status(StatusOther); 414 scMain->run(); 415} 416 417void 418Scheduler::scheduleStop(bool finish_delta) 419{ 420 if (stopEvent.scheduled()) 421 return; 422 423 if (!finish_delta) { 424 _stopNow = true; 425 // If we're not supposed to finish the delta cycle, flush all 426 // pending activity. 427 clear(); 428 } 429 schedule(&stopEvent); 430} 431 432Scheduler scheduler; 433 434namespace { 435 436void 437throwingReportHandler(const ::sc_core::sc_report &r, 438 const ::sc_core::sc_actions &) 439{ 440 throw r; 441} 442 443} // anonymous namespace 444 445const ::sc_core::sc_report * 446reportifyException() 447{ 448 ::sc_core::sc_report_handler_proc old_handler = 449 ::sc_core::sc_report_handler::get_handler(); 450 ::sc_core::sc_report_handler::set_handler(&throwingReportHandler); 451 452 try { 453 try { 454 // Rethrow the current exception so we can catch it and throw an 455 // sc_report instead if it's not a type we recognize/can handle. 456 throw; 457 } catch (const ::sc_core::sc_report &) { 458 // It's already a sc_report, so nothing to do. 459 throw; 460 } catch (const ::sc_core::sc_unwind_exception &) { 461 panic("Kill/reset exception escaped a Process::run()"); 462 } catch (const std::exception &e) { 463 SC_REPORT_ERROR("uncaught exception", e.what()); 464 } catch (const char *msg) { 465 SC_REPORT_ERROR("uncaught exception", msg); 466 } catch (...) { 467 SC_REPORT_ERROR("uncaught exception", "UNKNOWN EXCEPTION"); 468 } 469 } catch (const ::sc_core::sc_report &r) { 470 ::sc_core::sc_report_handler::set_handler(old_handler); 471 return &r; 472 } 473 panic("No exception thrown in reportifyException."); 474} 475 476} // namespace sc_gem5 477