gem5 v24.0.0.0
Loading...
Searching...
No Matches
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"
42#include "systemc/core/list.hh"
45
46class Fiber;
47
48namespace sc_gem5
49{
50
51class 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
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 {
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.
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
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
398 void registerTraceFile(TraceFile *tf) { traceFiles.insert(tf); }
399 void unregisterTraceFile(TraceFile *tf) { traceFiles.erase(tf); }
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
445 void schedule(gem5::Event *event) { schedule(event, getCurTick()); }
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 {
482 updateList.empty() && deltas.empty() &&
483 (timeSlots.empty() ||
484 timeSlots.front()->targeted_when > maxTick) &&
485 initList.empty());
486 }
489
493
495
498 void
500 {
501 if (lastReadyTick != getCurTick())
502 _changeStamp++;
503 pause();
504 }
506
507 void timeAdvances() { trace(false); }
509 void
515
516 uint64_t _numCycles;
517 uint64_t _changeStamp;
518
520
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
543extern Scheduler scheduler;
544
545// A proxy function to avoid having to expose the scheduler in header files.
547
548inline 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);
563 }
564
567}
568
569const ::sc_core::sc_report reportifyException();
570
571} // namespace sc_gem5
572
573#endif // __SYSTEMC_CORE_SCHEDULER_H__
static const FlagsType AutoDelete
Definition eventq.hh:110
Queue of events sorted in time order.
Definition eventq.hh:616
Wrap a member function inside MemberEventWrapper to use it as an event callback.
Definition eventq.hh:1092
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
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
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
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
std::map< gem5::Event *, gem5::Tick > eventsToSchedule
Definition scheduler.hh:536
ChannelList asyncUpdateList
Definition scheduler.hh:532
void asyncRequestUpdate(Channel *c)
Definition scheduler.cc:258
gem5::MemberEventWrapper<&Scheduler::timeAdvances > timeAdvancesEvent
Definition scheduler.hh:508
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
gem5::MemberEventWrapper<&Scheduler::pause > starvationEvent
Definition scheduler.hh:487
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
Process * current()
Definition scheduler.hh:185
void reg(Process *p)
Definition scheduler.cc:146
static Priority MaxTickPriority
Definition scheduler.hh:428
gem5::MemberEventWrapper<&Scheduler::maxTickFunc > maxTickEvent
Definition scheduler.hh:505
gem5::MemberEventWrapper<&Scheduler::stop > stopEvent
Definition scheduler.hh:474
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
gem5::MemberEventWrapper<&Scheduler::runReady > readyEvent
Definition scheduler.hh:468
void scheduleStarvationEvent()
Definition scheduler.cc:277
TimeSlot * acquireTimeSlot(gem5::Tick tick)
Definition scheduler.hh:402
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
void scheduleTimeAdvancesEvent()
Definition scheduler.hh:510
Process * getNextReady()
Definition scheduler.hh:461
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::MemberEventWrapper<&Scheduler::pause > pauseEvent
Definition scheduler.hh:473
STL list class.
Definition stl.hh:51
SwitchingFiber b
SwitchingFiber c
int8_t Priority
Definition eventq.hh:126
void schedule(Event *event, Tick when, bool global=false)
Schedule the given event on this queue.
Definition eventq.hh:757
void deschedule(Event *event)
Deschedule the specified event.
Definition eventq.hh:790
static const Priority Maximum_Pri
Maximum priority.
Definition eventq.hh:244
bool scheduled() const
Determine if the current event is scheduled.
Definition eventq.hh:458
Tick getCurTick() const
While curTick() is useful for any object assigned to this event queue, if an object that is assigned ...
Definition eventq.hh:850
static const Priority Default_Pri
Default is zero for historical reasons.
Definition eventq.hh:182
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:214
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
uint64_t Tick
Tick count type.
Definition types.hh:58
const Tick MaxTick
Definition types.hh:60
NodeList< Process > ProcessList
Definition scheduler.hh:53
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
void pushFirst(T *t)
Definition list.hh:72

Generated on Tue Jun 18 2024 16:24:06 for gem5 by doxygen 1.11.0