gem5  v19.0.0.0
scheduler.cc
Go to the documentation of this file.
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 
31 
32 #include "base/fiber.hh"
33 #include "base/logging.hh"
34 #include "sim/eventq.hh"
35 #include "sim/sim_exit.hh"
36 #include "systemc/core/kernel.hh"
42 #include "systemc/utils/report.hh"
44 
45 namespace sc_gem5
46 {
47 
49  eq(nullptr), readyEvent(this, false, ReadyPriority),
50  pauseEvent(this, false, PausePriority),
51  stopEvent(this, false, StopPriority), _throwUp(nullptr),
52  starvationEvent(this, false, StarvationPriority),
53  _elaborationDone(false), _started(false), _stopNow(false),
54  _status(StatusOther), maxTick(::MaxTick),
55  maxTickEvent(this, false, MaxTickPriority),
56  timeAdvancesEvent(this, false, TimeAdvancesPriority), _numCycles(0),
57  _changeStamp(0), _current(nullptr), initDone(false), runToTime(true),
58  runOnce(false)
59 {}
60 
62 {
63  // Clear out everything that belongs to us to make sure nobody tries to
64  // clear themselves out after the scheduler goes away.
65  clear();
66 }
67 
68 void
70 {
71  // Delta notifications.
72  while (!deltas.empty())
73  deltas.front()->deschedule();
74 
75  // Timed notifications.
76  for (auto &tsp: timeSlots) {
77  TimeSlot *&ts = tsp.second;
78  while (!ts->events.empty())
79  ts->events.front()->deschedule();
80  deschedule(ts);
81  }
82  timeSlots.clear();
83 
84  // gem5 events.
85  if (readyEvent.scheduled())
87  if (pauseEvent.scheduled())
89  if (stopEvent.scheduled())
91  if (starvationEvent.scheduled())
93  if (maxTickEvent.scheduled())
95  if (timeAdvancesEvent.scheduled())
97 
98  Process *p;
99  while ((p = initList.getNext()))
100  p->popListNode();
101  while ((p = readyListMethods.getNext()))
102  p->popListNode();
103  while ((p = readyListThreads.getNext()))
104  p->popListNode();
105 
106  Channel *c;
107  while ((c = updateList.getNext()))
108  c->popListNode();
109 }
110 
111 void
113 {
114  runUpdate();
115 
116  for (Process *p = initList.getNext(); p; p = initList.getNext()) {
117  p->popListNode();
118 
119  if (p->dontInitialize()) {
120  if (!p->hasStaticSensitivities() && !p->internal()) {
122  p->name());
123  }
124  } else {
125  p->ready();
126  }
127  }
128 
129  runDelta();
130 
131  for (auto ets: eventsToSchedule)
132  eq->schedule(ets.first, ets.second);
133  eventsToSchedule.clear();
134 
135  if (_started) {
136  if (!runToTime && starved())
139  }
140 
141  initDone = true;
142 
144 
146 }
147 
148 void
150 {
151  if (initDone) {
152  // If not marked as dontInitialize, mark as ready.
153  if (!p->dontInitialize())
154  p->ready();
155  } else {
156  // Otherwise, record that this process should be initialized once we
157  // get there.
158  initList.pushLast(p);
159  }
160 }
161 
162 void
164 {
165  // Pull a process from the active list.
167  if (!_current) {
168  // There are no more processes, so return control to evaluate.
170  } else {
172  _current->scheduled(false);
173  // Switch to whatever Fiber is supposed to run this process. All
174  // Fibers which aren't running should be parked at this line.
175  _current->fiber()->run();
176  // If the current process needs to be manually started, start it.
177  if (_current && _current->needsStart()) {
178  _current->needsStart(false);
179  // If a process hasn't started yet, "resetting" it just starts it
180  // and signals its reset event.
181  if (_current->inReset())
183  try {
184  _current->run();
185  } catch (...) {
186  throwUp();
187  }
188  }
189  }
190  if (_current && !_current->needsStart()) {
191  if (_current->excWrapper) {
192  auto ew = _current->excWrapper;
193  _current->excWrapper = nullptr;
194  ew->throw_it();
195  } else if (_current->inReset()) {
196  _current->reset(false);
197  }
198  }
199 }
200 
201 void
203 {
204  if (_stopNow)
205  return;
206 
207  p->scheduled(true);
208 
211  else
213 
214  if (!inEvaluate())
216 }
217 
218 void
220 {
221  if (initDone)
222  ready(p);
223  else
224  initList.pushLast(p);
225 }
226 
227 bool
229 {
230  ListNode *n = list->nextListNode;
231  while (n != list)
232  if (n == target)
233  return true;
234  return false;
235 }
236 
237 bool
239 {
240  bool was_ready;
241  if (initDone) {
242  // After initialization, check if we're on a ready list.
243  was_ready = (p->nextListNode != nullptr);
244  p->popListNode();
245  } else {
246  // Nothing is ready before init.
247  was_ready = false;
248  }
249  return was_ready;
250 }
251 
252 void
254 {
255  updateList.pushLast(c);
256  if (!inEvaluate())
258 }
259 
260 void
262 {
263  std::lock_guard<std::mutex> lock(asyncListMutex);
265 }
266 
267 void
269 {
270  // Schedule the evaluate and update phases.
271  if (!readyEvent.scheduled()) {
273  if (starvationEvent.scheduled())
275  }
276 }
277 
278 void
280 {
281  if (!starvationEvent.scheduled()) {
283  if (readyEvent.scheduled())
285  }
286 }
287 
288 void
290 {
292 
293  bool empty = readyListMethods.empty() && readyListThreads.empty();
295 
296  // The evaluation phase.
298  do {
299  yield();
300  } while (getNextReady());
301  _current = nullptr;
302 
303  if (!empty) {
304  _numCycles++;
305  _changeStamp++;
306  }
307 
308  if (_stopNow) {
310  return;
311  }
312 
313  runUpdate();
314  if (!traceFiles.empty())
315  trace(true);
316  runDelta();
317 
318  if (!runToTime && starved())
320 
321  if (runOnce)
322  schedulePause();
323 
325 }
326 
327 void
329 {
331  {
332  std::lock_guard<std::mutex> lock(asyncListMutex);
333  Channel *channel;
334  while ((channel = asyncUpdateList.getNext()) != nullptr)
335  updateList.pushLast(channel);
336  }
337 
338  try {
339  Channel *channel = updateList.getNext();
340  while (channel) {
341  channel->popListNode();
342  channel->update();
343  channel = updateList.getNext();
344  }
345  } catch (...) {
346  throwUp();
347  }
348 }
349 
350 void
352 {
354 
355  try {
356  while (!deltas.empty())
357  deltas.back()->run();
358  } catch (...) {
359  throwUp();
360  }
361 }
362 
363 void
365 {
368  runOnce = false;
369  if (scMainFiber.called()) {
370  if (!scMainFiber.finished())
371  scMainFiber.run();
372  } else {
373  if (scMainFiber.finished())
374  fatal("Pausing systemc after sc_main completed.");
375  else
376  exitSimLoopNow("systemc pause");
377  }
378 }
379 
380 void
382 {
384  kernel->stop();
385 
386  clear();
387 
388  runOnce = false;
389  if (scMainFiber.called()) {
390  if (!scMainFiber.finished())
391  scMainFiber.run();
392  } else {
393  if (scMainFiber.finished())
394  fatal("Stopping systemc after sc_main completed.");
395  else
396  exitSimLoopNow("systemc stop");
397  }
398 }
399 
400 void
401 Scheduler::start(Tick max_tick, bool run_to_time)
402 {
403  _started = true;
405  runToTime = run_to_time;
406 
407  maxTick = max_tick;
409 
410  if (initDone) {
411  if (!runToTime && starved())
414  }
415 
418 
419  // Return to gem5 to let it run events, etc.
421 
422  if (pauseEvent.scheduled())
424  if (stopEvent.scheduled())
426  if (maxTickEvent.scheduled())
428  if (starvationEvent.scheduled())
430 
431  if (_throwUp) {
432  const ::sc_core::sc_report *to_throw = _throwUp;
433  _throwUp = nullptr;
434  throw *to_throw;
435  }
436 }
437 
438 void
440 {
441  runOnce = true;
443  start(::MaxTick, false);
444 }
445 
446 void
448 {
449  if (pauseEvent.scheduled())
450  return;
451 
453 }
454 
455 void
457 {
458  if (scMainFiber.called() && !scMainFiber.finished()) {
460  _throwUp = &report;
462  scMainFiber.run();
463  } else {
466  }
467 }
468 
469 void
470 Scheduler::scheduleStop(bool finish_delta)
471 {
472  if (stopEvent.scheduled())
473  return;
474 
475  if (!finish_delta) {
476  _stopNow = true;
477  // If we're not supposed to finish the delta cycle, flush all
478  // pending activity.
479  clear();
480  }
482 }
483 
484 void
485 Scheduler::trace(bool delta)
486 {
487  for (auto tf: traceFiles)
488  tf->trace(delta);
489 }
490 
492 Process *getCurrentProcess() { return scheduler.current(); }
493 
494 namespace {
495 
496 void
497 throwingReportHandler(const ::sc_core::sc_report &r,
499 {
500  throw r;
501 }
502 
503 } // anonymous namespace
504 
505 const ::sc_core::sc_report
507 {
509  ::sc_core::sc_report_handler::set_handler(&throwingReportHandler);
510 
511  try {
512  try {
513  // Rethrow the current exception so we can catch it and throw an
514  // sc_report instead if it's not a type we recognize/can handle.
515  throw;
516  } catch (const ::sc_core::sc_report &) {
517  // It's already a sc_report, so nothing to do.
518  throw;
519  } catch (const ::sc_core::sc_unwind_exception &) {
520  panic("Kill/reset exception escaped a Process::run()");
521  } catch (const std::exception &e) {
524  } catch (const char *msg) {
527  } catch (...) {
530  "UNKNOWN EXCEPTION");
531  }
532  } catch (const ::sc_core::sc_report &r) {
534  return r;
535  }
536  panic("No exception thrown in reportifyException.");
537 }
538 
539 } // namespace sc_gem5
void scheduleReadyEvent()
Definition: scheduler.cc:268
unsigned sc_actions
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:167
Process * getNextReady()
Definition: scheduler.hh:417
bool suspend(Process *p)
Definition: scheduler.cc:238
Process * getCurrentProcess()
Definition: scheduler.cc:492
void run()
Start executing the fiber represented by this object.
Definition: fiber.cc:165
Bitfield< 55, 52 > ts
Bitfield< 29 > eq
Definition: miscregs.hh:50
uint64_t _changeStamp
Definition: scheduler.hh:472
bool finished() const
Returns whether the "main" function of this fiber has finished.
Definition: fiber.hh:83
void popListNode()
Definition: list.hh:53
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:175
EventWrapper< Scheduler, &Scheduler::pause > pauseEvent
Definition: scheduler.hh:429
void asyncRequestUpdate(Channel *c)
Definition: scheduler.cc:261
Kernel * kernel
Definition: kernel.cc:183
ProcessList readyListMethods
Definition: scheduler.hh:482
void start(Tick max_tick, bool run_to_time)
Definition: scheduler.cc:401
virtual ::sc_core::sc_curr_proc_kind procKind() const =0
void resume(Process *p)
Definition: scheduler.cc:219
static sc_core::sc_status status()
Definition: kernel.cc:56
void scheduleStarvationEvent()
Definition: scheduler.cc:279
const char SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_[]
Definition: messages.cc:119
static Fiber * primaryFiber()
Get a pointer to the primary Fiber.
Definition: fiber.cc:184
std::set< TraceFile * > traceFiles
Definition: scheduler.hh:492
void pushLast(T *t)
Definition: list.hh:91
bool dontInitialize()
Definition: process.hh:135
#define SC_REPORT_WARNING(msg_type, msg)
void scheduleTimeAdvancesEvent()
Definition: scheduler.hh:465
ChannelList updateList
Definition: scheduler.hh:485
Bitfield< 31 > n
void reg(Process *p)
Definition: scheduler.cc:149
void update()
Definition: channel.hh:50
void scheduleStop(bool finish_delta)
Definition: scheduler.cc:470
std::map<::Event *, Tick > eventsToSchedule
Definition: scheduler.hh:490
const Tick MaxTick
Definition: types.hh:65
uint64_t Tick
Tick count type.
Definition: types.hh:63
void deschedule(ScEvent *event)
Definition: scheduler.hh:265
Process * current()
Definition: scheduler.hh:172
ListNode * nextListNode
Definition: list.hh:49
ProcessList readyListThreads
Definition: scheduler.hh:483
EventWrapper< Scheduler, &Scheduler::pause > starvationEvent
Definition: scheduler.hh:442
EventWrapper< Scheduler, &Scheduler::timeAdvances > timeAdvancesEvent
Definition: scheduler.hh:463
static scfx_rep_node * list
Definition: scfx_rep.cc:336
void(* sc_report_handler_proc)(const sc_report &, const sc_actions &)
Scheduler scheduler
Definition: scheduler.cc:491
void exitSimLoopNow(const std::string &message, int exit_code, Tick repeat, bool serialize)
Schedule an event as above, but make it high priority so it runs before any normal events which are s...
Definition: sim_events.cc:101
sc_core::sc_report_handler_proc reportHandlerProc
Definition: report.cc:70
ChannelList asyncUpdateList
Definition: scheduler.hh:487
::sc_core::sc_event & resetEvent()
Definition: process.hh:103
EventQueue * eq
Definition: scheduler.hh:390
Bitfield< 9 > e
const ::sc_core::sc_report reportifyException()
Definition: scheduler.cc:506
void ready(Process *p)
Definition: scheduler.cc:202
void requestUpdate(Channel *c)
Definition: scheduler.cc:253
Bitfield< 29 > c
ExceptionWrapperBase * excWrapper
Definition: process.hh:93
void trace(bool delta)
Definition: scheduler.cc:485
EventWrapper< Scheduler, &Scheduler::runReady > readyEvent
Definition: scheduler.hh:424
void reset(bool inc_kids)
Definition: process.cc:171
static void stop()
Definition: kernel.cc:142
const ::sc_core::sc_report * _throwUp
Definition: scheduler.hh:432
virtual Fiber * fiber()
Definition: process.hh:123
TimeSlots timeSlots
Definition: scheduler.hh:414
bool needsStart() const
Definition: process.hh:68
void schedule(Event *event, Tick when, bool global=false)
Schedule the given event on this queue.
Definition: eventq_impl.hh:42
EventWrapper< Scheduler, &Scheduler::stop > stopEvent
Definition: scheduler.hh:430
Process * _current
Definition: scheduler.hh:474
bool scheduled() const
Definition: process.hh:75
#define SC_REPORT_ERROR(msg_type, msg)
bool empty()
Definition: list.hh:108
std::mutex asyncListMutex
Definition: scheduler.hh:488
const char SC_ID_DISABLE_WILL_ORPHAN_PROCESS_[]
Definition: messages.cc:134
EventWrapper< Scheduler, &Scheduler::maxTickFunc > maxTickEvent
Definition: scheduler.hh:460
Bitfield< 8 > tf
Definition: misc.hh:571
static void set_handler(sc_report_handler_proc)
ScMainFiber scMainFiber
bool listContains(ListNode *list, ListNode *target)
Definition: scheduler.cc:228
static sc_actions get_catch_actions()
void schedule(ScEvent *event, const ::sc_core::sc_time &delay)
Definition: scheduler.hh:240
Bitfield< 0 > p
uint64_t _numCycles
Definition: scheduler.hh:471
Bitfield< 5 > lock
Definition: types.hh:79
ProcessList initList
Definition: scheduler.hh:480
T * getNext()
Definition: list.hh:107
bool inReset()
Definition: process.hh:133

Generated on Fri Feb 28 2020 16:27:01 for gem5 by doxygen 1.8.13