gem5  v19.0.0.0
scheduler.hh
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 
30 #ifndef __SYSTEMC_CORE_SCHEDULER_HH__
31 #define __SYSTEMC_CORE_SCHEDULER_HH__
32 
33 #include <functional>
34 #include <map>
35 #include <mutex>
36 #include <set>
37 #include <vector>
38 
39 #include "base/logging.hh"
40 #include "sim/core.hh"
41 #include "sim/eventq.hh"
42 #include "systemc/core/channel.hh"
43 #include "systemc/core/list.hh"
44 #include "systemc/core/process.hh"
46 
47 class Fiber;
48 
49 namespace sc_gem5
50 {
51 
52 class TraceFile;
53 
56 
57 /*
58  * The scheduler supports three different mechanisms, the initialization phase,
59  * delta cycles, and timed notifications.
60  *
61  * INITIALIZATION PHASE
62  *
63  * The initialization phase has three parts:
64  * 1. Run requested channel updates.
65  * 2. Make processes which need to initialize runnable (methods and threads
66  * which didn't have dont_initialize called on them).
67  * 3. Process delta notifications.
68  *
69  * First, the Kernel SimObject calls the update() method during its startup()
70  * callback which handles the requested channel updates. The Kernel also
71  * schedules an event to be run at time 0 with a slightly elevated priority
72  * so that it happens before any "normal" event.
73  *
74  * When that t0 event happens, it calls the schedulers prepareForInit method
75  * which performs step 2 above. That indirectly causes the scheduler's
76  * readyEvent to be scheduled with slightly lowered priority, ensuring it
77  * happens after any "normal" event.
78  *
79  * Because delta notifications are scheduled at the standard priority, all
80  * of those events will happen next, performing step 3 above. Once they finish,
81  * if the readyEvent was scheduled above, there shouldn't be any higher
82  * priority events in front of it. When it runs, it will start the first
83  * evaluate phase of the first delta cycle.
84  *
85  * DELTA CYCLE
86  *
87  * A delta cycle has three phases within it.
88  * 1. The evaluate phase where runnable processes are allowed to run.
89  * 2. The update phase where requested channel updates hapen.
90  * 3. The delta notification phase where delta notifications happen.
91  *
92  * The readyEvent runs all three steps of the delta cycle. It first goes
93  * through the list of runnable processes and executes them until the set is
94  * empty, and then immediately runs the update phase. Since these are all part
95  * of the same event, there's no chance for other events to intervene and
96  * break the required order above.
97  *
98  * During the update phase above, the spec forbids any action which would make
99  * a process runnable. That means that once the update phase finishes, the set
100  * of runnable processes will be empty. There may, however, have been some
101  * delta notifications/timeouts which will have been scheduled during either
102  * the evaluate or update phase above. Those will have been accumulated in the
103  * scheduler, and are now all executed.
104  *
105  * If any processes became runnable during the delta notification phase, the
106  * readyEvent will have been scheduled and will be waiting and ready to run
107  * again, effectively starting the next delta cycle.
108  *
109  * TIMED NOTIFICATION PHASE
110  *
111  * If no processes became runnable, the event queue will continue to process
112  * events until it comes across an event which represents all the timed
113  * notifications which are supposed to happen at a particular time. The object
114  * which tracks them will execute all those notifications, and then destroy
115  * itself. If the readyEvent is now ready to run, the next delta cycle will
116  * start.
117  *
118  * PAUSE/STOP
119  *
120  * To inject a pause from sc_pause which should happen after the current delta
121  * cycle's delta notification phase, an event is scheduled with a lower than
122  * normal priority, but higher than the readyEvent. That ensures that any
123  * delta notifications which are scheduled with normal priority will happen
124  * first, since those are part of the current delta cycle. Then the pause
125  * event will happen before the next readyEvent which would start the next
126  * delta cycle. All of these events are scheduled for the current time, and so
127  * would happen before any timed notifications went off.
128  *
129  * To inject a stop from sc_stop, the delta cycles should stop before even the
130  * delta notifications have happened, but after the evaluate and update phases.
131  * For that, a stop event with slightly higher than normal priority will be
132  * scheduled so that it happens before any of the delta notification events
133  * which are at normal priority.
134  *
135  * MAX RUN TIME
136  *
137  * When sc_start is called, it's possible to pass in a maximum time the
138  * simulation should run to, at which point sc_pause is implicitly called. The
139  * simulation is supposed to run up to the latest timed notification phase
140  * which is less than or equal to the maximum time. In other words it should
141  * run timed notifications at the maximum time, but not the subsequent evaluate
142  * phase. That's implemented by scheduling an event at the max time with a
143  * priority which is lower than all the others except the ready event. Timed
144  * notifications will happen before it fires, but it will override any ready
145  * event and prevent the evaluate phase from starting.
146  */
147 
149 {
150  public:
152 
153  class TimeSlot : public ::Event
154  {
155  public:
157 
158  ScEvents events;
159  void process();
160  };
161 
162  typedef std::map<Tick, TimeSlot *> TimeSlots;
163 
164  Scheduler();
165  ~Scheduler();
166 
167  void clear();
168 
169  const std::string name() const { return "systemc_scheduler"; }
170 
171  uint64_t numCycles() { return _numCycles; }
172  Process *current() { return _current; }
173 
174  void initPhase();
175 
176  // Register a process with the scheduler.
177  void reg(Process *p);
178 
179  // Run the next process, if there is one.
180  void yield();
181 
182  // Put a process on the ready list.
183  void ready(Process *p);
184 
185  // Mark a process as ready if init is finished, or put it on the list of
186  // processes to be initialized.
187  void resume(Process *p);
188 
189  // Remove a process from the ready/init list if it was on one of them, and
190  // return if it was.
191  bool suspend(Process *p);
192 
193  // Schedule an update for a given channel.
194  void requestUpdate(Channel *c);
195  // Same as above, but may be called from a different thread.
196  void asyncRequestUpdate(Channel *c);
197 
198  // Run the given process immediately, preempting whatever may be running.
199  void
201  {
202  // This function may put a process on the wrong list, ie a thread
203  // the method list. That's fine since that's just a performance
204  // optimization, and the important thing here is how the processes are
205  // ordered.
206 
207  // If a process is running, schedule it/us to run again.
208  if (_current)
210  // Schedule p to run first.
212  yield();
213  }
214 
215  // Run this process at the next opportunity.
216  void
218  {
219  // Like above, it's ok if this isn't a method. Putting it on this list
220  // just gives it priority.
222  if (!inEvaluate())
224  }
225 
226  // Set an event queue for scheduling events.
227  void setEventQueue(EventQueue *_eq) { eq = _eq; }
228 
229  // Get the current time according to gem5.
230  Tick getCurTick() { return eq ? eq->getCurTick() : 0; }
231 
232  Tick
233  delayed(const ::sc_core::sc_time &delay)
234  {
235  return getCurTick() + delay.value();
236  }
237 
238  // For scheduling delayed/timed notifications/timeouts.
239  void
240  schedule(ScEvent *event, const ::sc_core::sc_time &delay)
241  {
242  Tick tick = delayed(delay);
243  if (tick < getCurTick())
244  tick = getCurTick();
245 
246  // Delta notification/timeout.
247  if (delay.value() == 0) {
248  event->schedule(deltas, tick);
249  if (!inEvaluate() && !inUpdate())
251  return;
252  }
253 
254  // Timed notification/timeout.
255  TimeSlot *&ts = timeSlots[tick];
256  if (!ts) {
257  ts = new TimeSlot;
258  schedule(ts, tick);
259  }
260  event->schedule(ts->events, tick);
261  }
262 
263  // For descheduling delayed/timed notifications/timeouts.
264  void
266  {
267  ScEvents *on = event->scheduledOn();
268 
269  if (on == &deltas) {
270  event->deschedule();
271  return;
272  }
273 
274  // Timed notification/timeout.
275  auto tsit = timeSlots.find(event->when());
276  panic_if(tsit == timeSlots.end(),
277  "Descheduling event at time with no events.");
278  TimeSlot *ts = tsit->second;
279  ScEvents &events = ts->events;
280  assert(on == &events);
281  event->deschedule();
282 
283  // If no more events are happening at this time slot, get rid of it.
284  if (events.empty()) {
285  deschedule(ts);
286  timeSlots.erase(tsit);
287  }
288  }
289 
290  void
292  {
293  assert(ts == timeSlots.begin()->second);
294  timeSlots.erase(timeSlots.begin());
295  if (!runToTime && starved())
298  }
299 
300  // Pending activity ignores gem5 activity, much like how a systemc
301  // simulation wouldn't know about asynchronous external events (socket IO
302  // for instance) that might happen before time advances in a pure
303  // systemc simulation. Also the spec lists what specific types of pending
304  // activity needs to be counted, which obviously doesn't include gem5
305  // events.
306 
307  // Return whether there's pending systemc activity at this time.
308  bool
310  {
311  return !readyListMethods.empty() || !readyListThreads.empty() ||
312  !updateList.empty() || !deltas.empty();
313  }
314 
315  // Return whether there are pending timed notifications or timeouts.
316  bool
318  {
319  return !timeSlots.empty();
320  }
321 
322  // Return how many ticks there are until the first pending event, if any.
323  Tick
325  {
326  if (pendingCurr())
327  return 0;
328  if (pendingFuture())
329  return timeSlots.begin()->first - getCurTick();
330  return MaxTick - getCurTick();
331  }
332 
333  // Run scheduled channel updates.
334  void runUpdate();
335 
336  // Run delta events.
337  void runDelta();
338 
339  void start(Tick max_tick, bool run_to_time);
340  void oneCycle();
341 
342  void schedulePause();
343  void scheduleStop(bool finish_delta);
344 
345  enum Status
346  {
354  };
355 
358 
359  bool paused() { return status() == StatusPaused; }
360  bool stopped() { return status() == StatusStopped; }
361  bool inEvaluate() { return status() == StatusEvaluate; }
362  bool inUpdate() { return status() == StatusUpdate; }
363  bool inDelta() { return status() == StatusDelta; }
364  bool inTiming() { return status() == StatusTiming; }
365 
366  uint64_t changeStamp() { return _changeStamp; }
368 
369  // Throw upwards, either to sc_main or to the report handler if sc_main
370  // isn't running.
371  void throwUp();
372 
373  Status status() { return _status; }
374  void status(Status s) { _status = s; }
375 
376  void registerTraceFile(TraceFile *tf) { traceFiles.insert(tf); }
378 
379  private:
382 
383  static Priority StopPriority = DefaultPriority - 1;
384  static Priority PausePriority = DefaultPriority + 1;
385  static Priority MaxTickPriority = DefaultPriority + 2;
386  static Priority ReadyPriority = DefaultPriority + 3;
389 
391 
392  // For gem5 style events.
393  void
395  {
396  if (initDone)
397  eq->schedule(event, tick);
398  else
399  eventsToSchedule[event] = tick;
400  }
401 
402  void schedule(::Event *event) { schedule(event, getCurTick()); }
403 
404  void
406  {
407  if (initDone)
408  eq->deschedule(event);
409  else
410  eventsToSchedule.erase(event);
411  }
412 
413  ScEvents deltas;
414  TimeSlots timeSlots;
415 
416  Process *
418  {
420  return p ? p : readyListThreads.getNext();
421  }
422 
423  void runReady();
425  void scheduleReadyEvent();
426 
427  void pause();
428  void stop();
431 
432  const ::sc_core::sc_report *_throwUp;
433 
434  bool
436  {
437  return (readyListMethods.empty() && readyListThreads.empty() &&
438  updateList.empty() && deltas.empty() &&
439  (timeSlots.empty() || timeSlots.begin()->first > maxTick) &&
440  initList.empty());
441  }
444 
446  bool _started;
447  bool _stopNow;
448 
450 
453  void
455  {
456  if (lastReadyTick != getCurTick())
457  _changeStamp++;
458  pause();
459  }
461 
462  void timeAdvances() { trace(false); }
464  void
466  {
467  if (!traceFiles.empty() && !timeAdvancesEvent.scheduled())
468  schedule(&timeAdvancesEvent);
469  }
470 
471  uint64_t _numCycles;
472  uint64_t _changeStamp;
473 
475 
476  bool initDone;
477  bool runToTime;
478  bool runOnce;
479 
480  ProcessList initList;
481 
482  ProcessList readyListMethods;
483  ProcessList readyListThreads;
484 
485  ChannelList updateList;
486 
487  ChannelList asyncUpdateList;
488  std::mutex asyncListMutex;
489 
490  std::map<::Event *, Tick> eventsToSchedule;
491 
492  std::set<TraceFile *> traceFiles;
493 
494  void trace(bool delta);
495 };
496 
497 extern Scheduler scheduler;
498 
499 // A proxy function to avoid having to expose the scheduler in header files.
501 
502 inline void
504 {
505  scheduler.stepChangeStamp();
506  scheduler.status(StatusTiming);
507 
508  try {
509  while (!events.empty())
510  events.front()->run();
511  } catch (...) {
512  if (events.empty())
513  scheduler.completeTimeSlot(this);
514  else
515  scheduler.schedule(this);
516  scheduler.throwUp();
517  }
518 
519  scheduler.status(StatusOther);
520  scheduler.completeTimeSlot(this);
521 }
522 
523 const ::sc_core::sc_report reportifyException();
524 
525 } // namespace sc_gem5
526 
527 #endif // __SYSTEMC_CORE_SCHEDULER_H__
void scheduleReadyEvent()
Definition: scheduler.cc:268
Process * getNextReady()
Definition: scheduler.hh:417
bool suspend(Process *p)
Definition: scheduler.cc:238
Process * getCurrentProcess()
Definition: scheduler.cc:492
void schedule(::Event *event)
Definition: scheduler.hh:402
Bitfield< 55, 52 > ts
uint64_t _changeStamp
Definition: scheduler.hh:472
const std::string name() const
Definition: scheduler.hh:169
bool elaborationDone()
Definition: scheduler.hh:356
void runNext(Process *p)
Definition: scheduler.hh:217
EventWrapper< Scheduler, &Scheduler::pause > pauseEvent
Definition: scheduler.hh:429
void asyncRequestUpdate(Channel *c)
Definition: scheduler.cc:261
void deschedule(Event *event)
Deschedule the specified event.
Definition: eventq_impl.hh:69
static Priority DefaultPriority
Definition: scheduler.hh:381
ProcessList readyListMethods
Definition: scheduler.hh:482
void start(Tick max_tick, bool run_to_time)
Definition: scheduler.cc:401
int8_t Priority
Definition: eventq.hh:117
void resume(Process *p)
Definition: scheduler.cc:219
void status(Status s)
Definition: scheduler.hh:374
void scheduleStarvationEvent()
Definition: scheduler.cc:279
std::set< TraceFile * > traceFiles
Definition: scheduler.hh:492
uint64_t numCycles()
Definition: scheduler.hh:171
void registerTraceFile(TraceFile *tf)
Definition: scheduler.hh:376
void scheduleTimeAdvancesEvent()
Definition: scheduler.hh:465
void completeTimeSlot(TimeSlot *ts)
Definition: scheduler.hh:291
ChannelList updateList
Definition: scheduler.hh:485
static const FlagsType AutoDelete
Definition: eventq.hh:104
void pushFirst(T *t)
Definition: list.hh:74
void reg(Process *p)
Definition: scheduler.cc:149
void scheduleStop(bool finish_delta)
Definition: scheduler.cc:470
NodeList< Channel > ChannelList
Definition: scheduler.hh:55
Bitfield< 7 > b
std::map<::Event *, Tick > eventsToSchedule
Definition: scheduler.hh:490
const Tick MaxTick
Definition: types.hh:65
static Priority MaxTickPriority
Definition: scheduler.hh:385
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:385
Queue of events sorted in time order.
Definition: eventq.hh:492
Bitfield< 4 > s
uint64_t Tick
Tick count type.
Definition: types.hh:63
void deschedule(ScEvent *event)
Definition: scheduler.hh:265
Process * current()
Definition: scheduler.hh:172
void elaborationDone(bool b)
Definition: scheduler.hh:357
void runNow(Process *p)
Definition: scheduler.hh:200
ProcessList readyListThreads
Definition: scheduler.hh:483
EventWrapper< Scheduler, &Scheduler::pause > starvationEvent
Definition: scheduler.hh:442
EventWrapper< Scheduler, &Scheduler::timeAdvances > timeAdvancesEvent
Definition: scheduler.hh:463
Scheduler scheduler
Definition: scheduler.cc:491
void unregisterTraceFile(TraceFile *tf)
Definition: scheduler.hh:377
uint64_t changeStamp()
Definition: scheduler.hh:366
const EventBase::Priority Priority
Definition: scheduler.hh:380
Bitfield< 10, 5 > event
ChannelList asyncUpdateList
Definition: scheduler.hh:487
Tick getCurTick() const
Definition: eventq.hh:627
void setEventQueue(EventQueue *_eq)
Definition: scheduler.hh:227
void when(Tick w)
Definition: sched_event.hh:83
EventQueue * eq
Definition: scheduler.hh:390
void deschedule(::Event *event)
Definition: scheduler.hh:405
static Priority PausePriority
Definition: scheduler.hh:384
const ::sc_core::sc_report reportifyException()
Definition: scheduler.cc:506
void ready(Process *p)
Definition: scheduler.cc:202
Tick delayed(const ::sc_core::sc_time &delay)
Definition: scheduler.hh:233
void requestUpdate(Channel *c)
Definition: scheduler.cc:253
Bitfield< 29 > c
EventWrapper< Scheduler, &Scheduler::runReady > readyEvent
Definition: scheduler.hh:424
This class represents a fiber, which is a light weight sort of thread which is cooperatively schedule...
Definition: fiber.hh:64
const ::sc_core::sc_report * _throwUp
Definition: scheduler.hh:432
TimeSlots timeSlots
Definition: scheduler.hh:414
virtual void trace(const char *action)
trace event activity
Definition: eventq.cc:384
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 empty()
Definition: list.hh:108
static Priority StopPriority
Definition: scheduler.hh:383
std::mutex asyncListMutex
Definition: scheduler.hh:488
static const Priority Default_Pri
Default is zero for historical reasons.
Definition: eventq.hh:149
void stepChangeStamp()
Definition: scheduler.hh:367
std::list< ScEvent * > ScEvents
Definition: scheduler.hh:151
NodeList< Process > ProcessList
Definition: scheduler.hh:52
static Priority ReadyPriority
Definition: scheduler.hh:386
EventWrapper< Scheduler, &Scheduler::maxTickFunc > maxTickEvent
Definition: scheduler.hh:460
static Priority StarvationPriority
Definition: scheduler.hh:387
std::map< Tick, TimeSlot * > TimeSlots
Definition: scheduler.hh:162
Bitfield< 8 > tf
Definition: misc.hh:571
void schedule(ScEvent *event, const ::sc_core::sc_time &delay)
Definition: scheduler.hh:240
Bitfield< 0 > p
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:185
static Priority TimeAdvancesPriority
Definition: scheduler.hh:388
uint64_t _numCycles
Definition: scheduler.hh:471
void schedule(::Event *event, Tick tick)
Definition: scheduler.hh:394
ProcessList initList
Definition: scheduler.hh:480
static const Priority Maximum_Pri
Maximum priority.
Definition: eventq.hh:179
T * getNext()
Definition: list.hh:107
Bitfield< 0 > on
Definition: dt_constants.hh:89

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