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

Generated on Wed Dec 21 2022 10:22:35 for gem5 by doxygen 1.9.1