scheduler.hh revision 12961
12068SN/A/* 22068SN/A * Copyright 2018 Google, Inc. 32068SN/A * 42068SN/A * Redistribution and use in source and binary forms, with or without 52068SN/A * modification, are permitted provided that the following conditions are 62068SN/A * met: redistributions of source code must retain the above copyright 72068SN/A * notice, this list of conditions and the following disclaimer; 82068SN/A * redistributions in binary form must reproduce the above copyright 92068SN/A * notice, this list of conditions and the following disclaimer in the 102068SN/A * documentation and/or other materials provided with the distribution; 112068SN/A * neither the name of the copyright holders nor the names of its 122068SN/A * contributors may be used to endorse or promote products derived from 132068SN/A * this software without specific prior written permission. 142068SN/A * 152068SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 162068SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 172068SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 182068SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 192068SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 202068SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 212068SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 222068SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 232068SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 242068SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 252068SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 262068SN/A * 272068SN/A * Authors: Gabe Black 282665Ssaidi@eecs.umich.edu */ 292665Ssaidi@eecs.umich.edu 302665Ssaidi@eecs.umich.edu#ifndef __SYSTEMC_CORE_SCHEDULER_HH__ 312068SN/A#define __SYSTEMC_CORE_SCHEDULER_HH__ 322649Ssaidi@eecs.umich.edu 332649Ssaidi@eecs.umich.edu#include <vector> 342649Ssaidi@eecs.umich.edu 352649Ssaidi@eecs.umich.edu#include "base/logging.hh" 362649Ssaidi@eecs.umich.edu#include "sim/eventq.hh" 372068SN/A#include "systemc/core/channel.hh" 382068SN/A#include "systemc/core/list.hh" 392068SN/A#include "systemc/core/process.hh" 402068SN/A 412068SN/Aclass Fiber; 422068SN/A 432068SN/Anamespace sc_gem5 442068SN/A{ 452068SN/A 462068SN/Atypedef NodeList<Process> ProcessList; 472068SN/Atypedef NodeList<Channel> ChannelList; 482107SN/A 492068SN/A/* 502107SN/A * The scheduler supports three different mechanisms, the initialization phase, 512068SN/A * delta cycles, and timed notifications. 522068SN/A * 532227SN/A * INITIALIZATION PHASE 542107SN/A * 552107SN/A * The initialization phase has three parts: 562068SN/A * 1. Run requested channel updates. 572068SN/A * 2. Make processes which need to initialize runnable (methods and threads 582068SN/A * which didn't have dont_initialize called on them). 592068SN/A * 3. Process delta notifications. 602068SN/A * 612068SN/A * First, the Kernel SimObject calls the update() method during its startup() 622068SN/A * callback which handles the requested channel updates. The Kernel also 632068SN/A * schedules an event to be run at time 0 with a slightly elevated priority 642068SN/A * so that it happens before any "normal" event. 652068SN/A * 662107SN/A * When that t0 event happens, it calls the schedulers prepareForInit method 672107SN/A * which performs step 2 above. That indirectly causes the scheduler's 682068SN/A * readyEvent to be scheduled with slightly lowered priority, ensuring it 692068SN/A * happens after any "normal" event. 702068SN/A * 712068SN/A * Because delta notifications are scheduled at the standard priority, all 722068SN/A * of those events will happen next, performing step 3 above. Once they finish, 732068SN/A * if the readyEvent was scheduled above, there shouldn't be any higher 742068SN/A * priority events in front of it. When it runs, it will start the first 752068SN/A * evaluate phase of the first delta cycle. 762068SN/A * 772068SN/A * DELTA CYCLE 782068SN/A * 792068SN/A * A delta cycle has three phases within it. 802068SN/A * 1. The evaluate phase where runnable processes are allowed to run. 812227SN/A * 2. The update phase where requested channel updates hapen. 822107SN/A * 3. The delta notification phase where delta notifications happen. 832107SN/A * 842068SN/A * The readyEvent runs the first two steps of the delta cycle. It first goes 852068SN/A * through the list of runnable processes and executes them until the set is 862068SN/A * empty, and then immediately runs the update phase. Since these are all part 872068SN/A * of the same event, there's no chance for other events to intervene and 882068SN/A * break the required order above. 892068SN/A * 902068SN/A * During the update phase above, the spec forbids any action which would make 912068SN/A * a process runnable. That means that once the update phase finishes, the set 922068SN/A * of runnable processes will be empty. There may, however, have been some 932068SN/A * delta notifications/timeouts which will have been scheduled during either 942068SN/A * the evaluate or update phase above. Because those are scheduled at the 952068SN/A * normal priority, they will now happen together until there aren't any 962068SN/A * delta events left. 972068SN/A * 982068SN/A * If any processes became runnable during the delta notification phase, the 992068SN/A * readyEvent will have been scheduled and will have been waiting patiently 1002227SN/A * behind the delta notification events. That will now run, effectively 1012107SN/A * starting the next delta cycle. 1022107SN/A * 1032068SN/A * TIMED NOTIFICATION PHASE 1042068SN/A * 1052068SN/A * If no processes became runnable, the event queue will continue to process 1062068SN/A * events until it comes across a timed notification, aka a notification 1072068SN/A * scheduled to happen in the future. Like delta notification events, those 1082068SN/A * will all happen together since the readyEvent priority is lower, 1092068SN/A * potentially marking new processes as ready. Once these events finish, the 1102068SN/A * readyEvent may run, starting the next delta cycle. 1112068SN/A * 1122068SN/A * PAUSE/STOP 1132068SN/A * 1142068SN/A * To inject a pause from sc_pause which should happen after the current delta 1152068SN/A * cycle's delta notification phase, an event is scheduled with a lower than 1162068SN/A * normal priority, but higher than the readyEvent. That ensures that any 1172068SN/A * delta notifications which are scheduled with normal priority will happen 1182068SN/A * first, since those are part of the current delta cycle. Then the pause 1192068SN/A * event will happen before the next readyEvent which would start the next 1202068SN/A * delta cycle. All of these events are scheduled for the current time, and so 1212068SN/A * would happen before any timed notifications went off. 1222068SN/A * 1232068SN/A * To inject a stop from sc_stop, the delta cycles should stop before even the 1242068SN/A * delta notifications have happened, but after the evaluate and update phases. 1252068SN/A * For that, a stop event with slightly higher than normal priority will be 1262068SN/A * scheduled so that it happens before any of the delta notification events 1272068SN/A * which are at normal priority. 1282068SN/A * 1292068SN/A * MAX RUN TIME 1302068SN/A * 1312068SN/A * When sc_start is called, it's possible to pass in a maximum time the 1322068SN/A * simulation should run to, at which point sc_pause is implicitly called. 1332068SN/A * That's implemented by scheduling an event at the max time with a priority 1342068SN/A * which is lower than all the others so that it happens only if time would 1352068SN/A * advance. When that event triggers, it calls the same function as the pause 1362068SN/A * event. 1372068SN/A */ 1382068SN/A 1392068SN/Aclass Scheduler 1402068SN/A{ 1412068SN/A public: 1422068SN/A Scheduler(); 1432068SN/A 1442068SN/A const std::string name() const { return "systemc_scheduler"; } 1452068SN/A 1462068SN/A uint64_t numCycles() { return _numCycles; } 1472068SN/A Process *current() { return _current; } 1482068SN/A 1492068SN/A // Prepare for initialization. 1502068SN/A void prepareForInit(); 1512068SN/A 1522227SN/A // Register a process with the scheduler. 1532068SN/A void reg(Process *p); 1542068SN/A 1552068SN/A // Tell the scheduler not to initialize a process. 1562068SN/A void dontInitialize(Process *p); 1572068SN/A 1582068SN/A // Run the next process, if there is one. 1592068SN/A void yield(); 1602068SN/A 1612068SN/A // Put a process on the ready list. 1622068SN/A void ready(Process *p); 1632068SN/A 1642227SN/A // Schedule an update for a given channel. 1652068SN/A void requestUpdate(Channel *c); 1662068SN/A 1672068SN/A // Run the given process immediately, preempting whatever may be running. 1682068SN/A void 1692068SN/A runNow(Process *p) 1702068SN/A { 1712068SN/A // If a process is running, schedule it/us to run again. 1722227SN/A if (_current) 1732068SN/A readyList.pushFirst(_current); 1742068SN/A // Schedule p to run first. 1752095SN/A readyList.pushFirst(p); 1762095SN/A yield(); 1772095SN/A } 1782095SN/A 1792068SN/A // Set an event queue for scheduling events. 1802068SN/A void setEventQueue(EventQueue *_eq) { eq = _eq; } 1812068SN/A 1822095SN/A // Retrieve the event queue. 1832095SN/A EventQueue &eventQueue() const { return *eq; } 1842132SN/A 1852095SN/A // Run scheduled channel updates. 1862095SN/A void update(); 1872095SN/A 1882095SN/A void setScMainFiber(Fiber *sc_main) { scMain = sc_main; } 1892623SN/A 1902623SN/A void start(Tick max_tick, bool run_to_time); 1912095SN/A 1922095SN/A void schedulePause(); 1932095SN/A void scheduleStop(bool finish_delta); 1942068SN/A 1952068SN/A bool paused() { return _paused; } 1962068SN/A bool stopped() { return _stopped; } 1972068SN/A 1982227SN/A private: 1992068SN/A typedef const EventBase::Priority Priority; 2002068SN/A static Priority DefaultPriority = EventBase::Default_Pri; 2012068SN/A 2022068SN/A static Priority StopPriority = DefaultPriority - 1; 2032068SN/A static Priority PausePriority = DefaultPriority + 1; 2042227SN/A static Priority ReadyPriority = DefaultPriority + 2; 2052068SN/A static Priority MaxTickPriority = DefaultPriority + 3; 2062068SN/A 2072068SN/A EventQueue *eq; 2082068SN/A 2092068SN/A void runReady(); 2102227SN/A EventWrapper<Scheduler, &Scheduler::runReady> readyEvent; 2112068SN/A void scheduleReadyEvent(); 2122068SN/A 2132068SN/A void pause(); 2142068SN/A void stop(); 2152068SN/A EventWrapper<Scheduler, &Scheduler::pause> pauseEvent; 2162068SN/A EventWrapper<Scheduler, &Scheduler::stop> stopEvent; 2172068SN/A Fiber *scMain; 2182068SN/A 2192068SN/A bool _started; 2202132SN/A bool _paused; 2212068SN/A bool _stopped; 2222068SN/A 2232068SN/A Tick maxTick; 2242068SN/A EventWrapper<Scheduler, &Scheduler::pause> maxTickEvent; 2252132SN/A 2262068SN/A uint64_t _numCycles; 2272068SN/A 2282068SN/A Process *_current; 2292068SN/A 2302068SN/A bool initReady; 2312068SN/A 2322090SN/A ProcessList initList; 2332068SN/A ProcessList toFinalize; 2342068SN/A ProcessList readyList; 2352068SN/A 2362068SN/A ChannelList updateList; 2372068SN/A}; 2382068SN/A 2392068SN/Aextern Scheduler scheduler; 2402068SN/A 2412069SN/A} // namespace sc_gem5 2422132SN/A 2432068SN/A#endif // __SYSTEMC_CORE_SCHEDULER_H__ 2442068SN/A