scheduler.hh (13061:9b868a2ab73c) | scheduler.hh (13063:c9905ead0041) |
---|---|
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 --- 16 unchanged lines hidden (view full) --- 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 | 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 --- 16 unchanged lines hidden (view full) --- 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 <set> |
|
33#include <vector> 34 35#include "base/logging.hh" | 36#include <vector> 37 38#include "base/logging.hh" |
39#include "sim/core.hh" |
|
36#include "sim/eventq.hh" 37#include "systemc/core/channel.hh" 38#include "systemc/core/list.hh" 39#include "systemc/core/process.hh" | 40#include "sim/eventq.hh" 41#include "systemc/core/channel.hh" 42#include "systemc/core/list.hh" 43#include "systemc/core/process.hh" |
44#include "systemc/core/sched_event.hh" |
|
40 41class Fiber; 42 43namespace sc_gem5 44{ 45 46typedef NodeList<Process> ProcessList; 47typedef NodeList<Channel> ChannelList; --- 28 unchanged lines hidden (view full) --- 76 * 77 * DELTA CYCLE 78 * 79 * A delta cycle has three phases within it. 80 * 1. The evaluate phase where runnable processes are allowed to run. 81 * 2. The update phase where requested channel updates hapen. 82 * 3. The delta notification phase where delta notifications happen. 83 * | 45 46class Fiber; 47 48namespace sc_gem5 49{ 50 51typedef NodeList<Process> ProcessList; 52typedef NodeList<Channel> ChannelList; --- 28 unchanged lines hidden (view full) --- 81 * 82 * DELTA CYCLE 83 * 84 * A delta cycle has three phases within it. 85 * 1. The evaluate phase where runnable processes are allowed to run. 86 * 2. The update phase where requested channel updates hapen. 87 * 3. The delta notification phase where delta notifications happen. 88 * |
84 * The readyEvent runs the first two steps of the delta cycle. It first goes | 89 * The readyEvent runs all three steps of the delta cycle. It first goes |
85 * through the list of runnable processes and executes them until the set is 86 * empty, and then immediately runs the update phase. Since these are all part 87 * of the same event, there's no chance for other events to intervene and 88 * break the required order above. 89 * 90 * During the update phase above, the spec forbids any action which would make 91 * a process runnable. That means that once the update phase finishes, the set 92 * of runnable processes will be empty. There may, however, have been some 93 * delta notifications/timeouts which will have been scheduled during either | 90 * through the list of runnable processes and executes them until the set is 91 * empty, and then immediately runs the update phase. Since these are all part 92 * of the same event, there's no chance for other events to intervene and 93 * break the required order above. 94 * 95 * During the update phase above, the spec forbids any action which would make 96 * a process runnable. That means that once the update phase finishes, the set 97 * of runnable processes will be empty. There may, however, have been some 98 * delta notifications/timeouts which will have been scheduled during either |
94 * the evaluate or update phase above. Because those are scheduled at the 95 * normal priority, they will now happen together until there aren't any 96 * delta events left. | 99 * the evaluate or update phase above. Those will have been accumulated in the 100 * scheduler, and are now all executed. |
97 * 98 * If any processes became runnable during the delta notification phase, the | 101 * 102 * If any processes became runnable during the delta notification phase, the |
99 * readyEvent will have been scheduled and will have been waiting patiently 100 * behind the delta notification events. That will now run, effectively 101 * starting the next delta cycle. | 103 * readyEvent will have been scheduled and will be waiting and ready to run 104 * again, effectively starting the next delta cycle. |
102 * 103 * TIMED NOTIFICATION PHASE 104 * 105 * If no processes became runnable, the event queue will continue to process | 105 * 106 * TIMED NOTIFICATION PHASE 107 * 108 * If no processes became runnable, the event queue will continue to process |
106 * events until it comes across a timed notification, aka a notification 107 * scheduled to happen in the future. Like delta notification events, those 108 * will all happen together since the readyEvent priority is lower, 109 * potentially marking new processes as ready. Once these events finish, the 110 * readyEvent may run, starting the next delta cycle. | 109 * events until it comes across an event which represents all the timed 110 * notifications which are supposed to happen at a particular time. The object 111 * which tracks them will execute all those notifications, and then destroy 112 * itself. If the readyEvent is now ready to run, the next delta cycle will 113 * start. |
111 * 112 * PAUSE/STOP 113 * 114 * To inject a pause from sc_pause which should happen after the current delta 115 * cycle's delta notification phase, an event is scheduled with a lower than 116 * normal priority, but higher than the readyEvent. That ensures that any 117 * delta notifications which are scheduled with normal priority will happen 118 * first, since those are part of the current delta cycle. Then the pause --- 18 unchanged lines hidden (view full) --- 137 * priority which is lower than all the others except the ready event. Timed 138 * notifications will happen before it fires, but it will override any ready 139 * event and prevent the evaluate phase from starting. 140 */ 141 142class Scheduler 143{ 144 public: | 114 * 115 * PAUSE/STOP 116 * 117 * To inject a pause from sc_pause which should happen after the current delta 118 * cycle's delta notification phase, an event is scheduled with a lower than 119 * normal priority, but higher than the readyEvent. That ensures that any 120 * delta notifications which are scheduled with normal priority will happen 121 * first, since those are part of the current delta cycle. Then the pause --- 18 unchanged lines hidden (view full) --- 140 * priority which is lower than all the others except the ready event. Timed 141 * notifications will happen before it fires, but it will override any ready 142 * event and prevent the evaluate phase from starting. 143 */ 144 145class Scheduler 146{ 147 public: |
148 typedef std::set<ScEvent *> ScEvents; 149 150 class TimeSlot : public ::Event 151 { 152 public: 153 TimeSlot() : ::Event(Default_Pri, AutoDelete) {} 154 155 ScEvents events; 156 void process(); 157 }; 158 159 typedef std::map<Tick, TimeSlot *> TimeSlots; 160 |
|
145 Scheduler(); 146 147 const std::string name() const { return "systemc_scheduler"; } 148 149 uint64_t numCycles() { return _numCycles; } 150 Process *current() { return _current; } 151 152 // Prepare for initialization. --- 27 unchanged lines hidden (view full) --- 180 } 181 182 // Set an event queue for scheduling events. 183 void setEventQueue(EventQueue *_eq) { eq = _eq; } 184 185 // Get the current time according to gem5. 186 Tick getCurTick() { return eq ? eq->getCurTick() : 0; } 187 | 161 Scheduler(); 162 163 const std::string name() const { return "systemc_scheduler"; } 164 165 uint64_t numCycles() { return _numCycles; } 166 Process *current() { return _current; } 167 168 // Prepare for initialization. --- 27 unchanged lines hidden (view full) --- 196 } 197 198 // Set an event queue for scheduling events. 199 void setEventQueue(EventQueue *_eq) { eq = _eq; } 200 201 // Get the current time according to gem5. 202 Tick getCurTick() { return eq ? eq->getCurTick() : 0; } 203 |
204 Tick 205 delayed(const ::sc_core::sc_time &delay) 206 { 207 //XXX We're assuming the systemc time resolution is in ps. 208 return getCurTick() + delay.value() * SimClock::Int::ps; 209 } 210 |
|
188 // For scheduling delayed/timed notifications/timeouts. 189 void | 211 // For scheduling delayed/timed notifications/timeouts. 212 void |
190 schedule(::Event *event, Tick tick) | 213 schedule(ScEvent *event, const ::sc_core::sc_time &delay) |
191 { | 214 { |
192 pendingTicks[tick]++; | 215 Tick tick = delayed(delay); 216 event->schedule(tick); |
193 | 217 |
194 if (initReady) 195 eq->schedule(event, tick); 196 else 197 eventsToSchedule[event] = tick; | 218 // Delta notification/timeout. 219 if (delay.value() == 0) { 220 deltas.insert(event); 221 scheduleReadyEvent(); 222 return; 223 } 224 225 // Timed notification/timeout. 226 TimeSlot *&ts = timeSlots[tick]; 227 if (!ts) { 228 ts = new TimeSlot; 229 if (initReady) 230 eq->schedule(ts, tick); 231 else 232 eventsToSchedule[ts] = tick; 233 } 234 ts->events.insert(event); |
198 } 199 200 // For descheduling delayed/timed notifications/timeouts. 201 void | 235 } 236 237 // For descheduling delayed/timed notifications/timeouts. 238 void |
202 deschedule(::Event *event) | 239 deschedule(ScEvent *event) |
203 { | 240 { |
204 auto it = pendingTicks.find(event->when()); 205 if (--it->second == 0) 206 pendingTicks.erase(it); | 241 if (event->when() == getCurTick()) { 242 // Remove from delta notifications. 243 deltas.erase(event); 244 event->deschedule(); 245 return; 246 } |
207 | 247 |
208 if (initReady) 209 eq->deschedule(event); 210 else 211 eventsToSchedule.erase(event); | 248 // Timed notification/timeout. 249 auto tsit = timeSlots.find(event->when()); 250 panic_if(tsit == timeSlots.end(), 251 "Descheduling event at time with no events."); 252 TimeSlot *ts = tsit->second; 253 ScEvents &events = ts->events; 254 events.erase(event); 255 event->deschedule(); 256 257 // If no more events are happening at this time slot, get rid of it. 258 if (events.empty()) { 259 if (initReady) 260 eq->deschedule(ts); 261 else 262 eventsToSchedule.erase(ts); 263 timeSlots.erase(tsit); 264 } |
212 } 213 | 265 } 266 |
214 // Tell the scheduler than an event fired for bookkeeping purposes. | |
215 void | 267 void |
216 eventHappened() | 268 completeTimeSlot(TimeSlot *ts) |
217 { | 269 { |
218 auto it = pendingTicks.begin(); 219 if (--it->second == 0) 220 pendingTicks.erase(it); 221 222 if (starved() && !runToTime) 223 scheduleStarvationEvent(); | 270 assert(ts == timeSlots.begin()->second); 271 timeSlots.erase(timeSlots.begin()); |
224 } 225 226 // Pending activity ignores gem5 activity, much like how a systemc 227 // simulation wouldn't know about asynchronous external events (socket IO 228 // for instance) that might happen before time advances in a pure 229 // systemc simulation. Also the spec lists what specific types of pending 230 // activity needs to be counted, which obviously doesn't include gem5 231 // events. 232 233 // Return whether there's pending systemc activity at this time. 234 bool 235 pendingCurr() 236 { | 272 } 273 274 // Pending activity ignores gem5 activity, much like how a systemc 275 // simulation wouldn't know about asynchronous external events (socket IO 276 // for instance) that might happen before time advances in a pure 277 // systemc simulation. Also the spec lists what specific types of pending 278 // activity needs to be counted, which obviously doesn't include gem5 279 // events. 280 281 // Return whether there's pending systemc activity at this time. 282 bool 283 pendingCurr() 284 { |
237 if (!readyList.empty() || !updateList.empty()) 238 return true; 239 return pendingTicks.size() && 240 pendingTicks.begin()->first == getCurTick(); | 285 return !readyList.empty() || !updateList.empty() || !deltas.empty(); |
241 } 242 243 // Return whether there are pending timed notifications or timeouts. 244 bool 245 pendingFuture() 246 { | 286 } 287 288 // Return whether there are pending timed notifications or timeouts. 289 bool 290 pendingFuture() 291 { |
247 switch (pendingTicks.size()) { 248 case 0: return false; 249 case 1: return pendingTicks.begin()->first > getCurTick(); 250 default: return true; 251 } | 292 return !timeSlots.empty(); |
252 } 253 254 // Return how many ticks there are until the first pending event, if any. 255 Tick 256 timeToPending() 257 { | 293 } 294 295 // Return how many ticks there are until the first pending event, if any. 296 Tick 297 timeToPending() 298 { |
258 if (!readyList.empty() || !updateList.empty()) | 299 if (pendingCurr()) |
259 return 0; | 300 return 0; |
260 else if (pendingTicks.size()) 261 return pendingTicks.begin()->first - getCurTick(); 262 else 263 return MaxTick - getCurTick(); | 301 if (pendingFuture()) 302 return timeSlots.begin()->first - getCurTick(); 303 return MaxTick - getCurTick(); |
264 } 265 266 // Run scheduled channel updates. 267 void update(); 268 269 void setScMainFiber(Fiber *sc_main) { scMain = sc_main; } 270 271 void start(Tick max_tick, bool run_to_time); --- 11 unchanged lines hidden (view full) --- 283 284 static Priority StopPriority = DefaultPriority - 1; 285 static Priority PausePriority = DefaultPriority + 1; 286 static Priority MaxTickPriority = DefaultPriority + 2; 287 static Priority ReadyPriority = DefaultPriority + 3; 288 static Priority StarvationPriority = ReadyPriority; 289 290 EventQueue *eq; | 304 } 305 306 // Run scheduled channel updates. 307 void update(); 308 309 void setScMainFiber(Fiber *sc_main) { scMain = sc_main; } 310 311 void start(Tick max_tick, bool run_to_time); --- 11 unchanged lines hidden (view full) --- 323 324 static Priority StopPriority = DefaultPriority - 1; 325 static Priority PausePriority = DefaultPriority + 1; 326 static Priority MaxTickPriority = DefaultPriority + 2; 327 static Priority ReadyPriority = DefaultPriority + 3; 328 static Priority StarvationPriority = ReadyPriority; 329 330 EventQueue *eq; |
291 std::map<Tick, int> pendingTicks; | |
292 | 331 |
332 ScEvents deltas; 333 TimeSlots timeSlots; 334 |
|
293 void runReady(); 294 EventWrapper<Scheduler, &Scheduler::runReady> readyEvent; 295 void scheduleReadyEvent(); 296 297 void pause(); 298 void stop(); 299 EventWrapper<Scheduler, &Scheduler::pause> pauseEvent; 300 EventWrapper<Scheduler, &Scheduler::stop> stopEvent; 301 Fiber *scMain; 302 303 bool 304 starved() 305 { | 335 void runReady(); 336 EventWrapper<Scheduler, &Scheduler::runReady> readyEvent; 337 void scheduleReadyEvent(); 338 339 void pause(); 340 void stop(); 341 EventWrapper<Scheduler, &Scheduler::pause> pauseEvent; 342 EventWrapper<Scheduler, &Scheduler::stop> stopEvent; 343 Fiber *scMain; 344 345 bool 346 starved() 347 { |
306 return (readyList.empty() && updateList.empty() && 307 (pendingTicks.empty() || 308 pendingTicks.begin()->first > maxTick) && | 348 return (readyList.empty() && updateList.empty() && deltas.empty() && 349 (timeSlots.empty() || timeSlots.begin()->first > maxTick) && |
309 initList.empty()); 310 } 311 EventWrapper<Scheduler, &Scheduler::pause> starvationEvent; 312 void scheduleStarvationEvent(); 313 314 bool _started; 315 bool _paused; 316 bool _stopped; --- 15 unchanged lines hidden (view full) --- 332 333 ChannelList updateList; 334 335 std::map<::Event *, Tick> eventsToSchedule; 336}; 337 338extern Scheduler scheduler; 339 | 350 initList.empty()); 351 } 352 EventWrapper<Scheduler, &Scheduler::pause> starvationEvent; 353 void scheduleStarvationEvent(); 354 355 bool _started; 356 bool _paused; 357 bool _stopped; --- 15 unchanged lines hidden (view full) --- 373 374 ChannelList updateList; 375 376 std::map<::Event *, Tick> eventsToSchedule; 377}; 378 379extern Scheduler scheduler; 380 |
381inline void 382Scheduler::TimeSlot::process() 383{ 384 for (auto &e: events) 385 e->run(); 386 scheduler.completeTimeSlot(this); 387} 388 |
|
340} // namespace sc_gem5 341 342#endif // __SYSTEMC_CORE_SCHEDULER_H__ | 389} // namespace sc_gem5 390 391#endif // __SYSTEMC_CORE_SCHEDULER_H__ |