scheduler.cc revision 12995:3421144dd03e
12391SN/A/*
28931Sandreas.hansson@arm.com * Copyright 2018 Google, Inc.
38931Sandreas.hansson@arm.com *
48931Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
58931Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
68931Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
78931Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
88931Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
98931Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
108931Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
118931Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
128931Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
132391SN/A * this software without specific prior written permission.
142391SN/A *
152391SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
162391SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
172391SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
182391SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
192391SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
202391SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
212391SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
222391SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
232391SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
242391SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
252391SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
262391SN/A *
272391SN/A * Authors: Gabe Black
282391SN/A */
292391SN/A
302391SN/A#include "systemc/core/scheduler.hh"
312391SN/A
322391SN/A#include "base/fiber.hh"
332391SN/A#include "base/logging.hh"
342391SN/A#include "sim/eventq.hh"
352391SN/A#include "systemc/core/kernel.hh"
362665Ssaidi@eecs.umich.edu#include "systemc/ext/core/sc_main.hh"
378931Sandreas.hansson@arm.com
382391SN/Anamespace sc_gem5
392391SN/A{
402391SN/A
412391SN/AScheduler::Scheduler() :
422391SN/A    eq(nullptr), readyEvent(this, false, ReadyPriority),
439235Sandreas.hansson@arm.com    pauseEvent(this, false, PausePriority),
449293Sandreas.hansson@arm.com    stopEvent(this, false, StopPriority),
459293Sandreas.hansson@arm.com    scMain(nullptr),
469293Sandreas.hansson@arm.com    starvationEvent(this, false, StarvationPriority),
479293Sandreas.hansson@arm.com    _started(false), _paused(false), _stopped(false),
489293Sandreas.hansson@arm.com    maxTickEvent(this, false, MaxTickPriority),
499293Sandreas.hansson@arm.com    _numCycles(0), _current(nullptr), initReady(false)
504762Snate@binkert.org{}
518931Sandreas.hansson@arm.com
528931Sandreas.hansson@arm.comvoid
538931Sandreas.hansson@arm.comScheduler::prepareForInit()
548931Sandreas.hansson@arm.com{
559293Sandreas.hansson@arm.com    for (Process *p = toFinalize.getNext(); p; p = toFinalize.getNext()) {
569293Sandreas.hansson@arm.com        p->finalize();
579293Sandreas.hansson@arm.com        p->popListNode();
589293Sandreas.hansson@arm.com    }
599293Sandreas.hansson@arm.com
609293Sandreas.hansson@arm.com    for (Process *p = initList.getNext(); p; p = initList.getNext()) {
619293Sandreas.hansson@arm.com        p->finalize();
629293Sandreas.hansson@arm.com        p->ready();
639293Sandreas.hansson@arm.com    }
649293Sandreas.hansson@arm.com
659293Sandreas.hansson@arm.com    for (auto ets: eventsToSchedule)
668931Sandreas.hansson@arm.com        eq->schedule(ets.first, ets.second);
679293Sandreas.hansson@arm.com    eventsToSchedule.clear();
682391SN/A
692413SN/A    if (_started)
702391SN/A        eq->schedule(&maxTickEvent, maxTick);
712391SN/A
729293Sandreas.hansson@arm.com    initReady = true;
739293Sandreas.hansson@arm.com}
749293Sandreas.hansson@arm.com
758931Sandreas.hansson@arm.comvoid
769235Sandreas.hansson@arm.comScheduler::reg(Process *p)
773170Sstever@eecs.umich.edu{
788931Sandreas.hansson@arm.com    if (initReady) {
799235Sandreas.hansson@arm.com        // If we're past initialization, finalize static sensitivity.
803170Sstever@eecs.umich.edu        p->finalize();
818931Sandreas.hansson@arm.com        // Mark the process as ready.
828931Sandreas.hansson@arm.com        p->ready();
833170Sstever@eecs.umich.edu    } else {
848931Sandreas.hansson@arm.com        // Otherwise, record that this process should be initialized once we
858931Sandreas.hansson@arm.com        // get there.
863170Sstever@eecs.umich.edu        initList.pushLast(p);
879293Sandreas.hansson@arm.com    }
889293Sandreas.hansson@arm.com}
899293Sandreas.hansson@arm.com
909293Sandreas.hansson@arm.comvoid
918931Sandreas.hansson@arm.comScheduler::dontInitialize(Process *p)
928931Sandreas.hansson@arm.com{
933170Sstever@eecs.umich.edu    if (initReady) {
948931Sandreas.hansson@arm.com        // Pop this process off of the ready list.
958931Sandreas.hansson@arm.com        p->popListNode();
968719SAli.Saidi@ARM.com    } else {
979293Sandreas.hansson@arm.com        // Push this process onto the list of processes which still need
989293Sandreas.hansson@arm.com        // their static sensitivity to be finalized. That implicitly pops it
999293Sandreas.hansson@arm.com        // off the list of processes to be initialized/marked ready.
1009293Sandreas.hansson@arm.com        toFinalize.pushLast(p);
1019293Sandreas.hansson@arm.com    }
1029293Sandreas.hansson@arm.com}
1039293Sandreas.hansson@arm.com
1049293Sandreas.hansson@arm.comvoid
1059293Sandreas.hansson@arm.comScheduler::yield()
1069293Sandreas.hansson@arm.com{
1079293Sandreas.hansson@arm.com    _current = readyList.getNext();
1082391SN/A    if (!_current) {
1092391SN/A        // There are no more processes, so return control to evaluate.
1108931Sandreas.hansson@arm.com        Fiber::primaryFiber()->run();
1118931Sandreas.hansson@arm.com    } else {
1128931Sandreas.hansson@arm.com        _current->popListNode();
1139293Sandreas.hansson@arm.com        // Switch to whatever Fiber is supposed to run this process. All
1149293Sandreas.hansson@arm.com        // Fibers which aren't running should be parked at this line.
1152391SN/A        _current->fiber()->run();
1168931Sandreas.hansson@arm.com        // If the current process needs to be manually started, start it.
1179293Sandreas.hansson@arm.com        if (_current && _current->needsStart())
1188931Sandreas.hansson@arm.com            _current->run();
1199293Sandreas.hansson@arm.com    }
1209293Sandreas.hansson@arm.com    if (_current && _current->excWrapper) {
1219293Sandreas.hansson@arm.com        // Make sure this isn't a method process.
1229293Sandreas.hansson@arm.com        assert(!_current->needsStart());
1239293Sandreas.hansson@arm.com        auto ew = _current->excWrapper;
1249293Sandreas.hansson@arm.com        _current->excWrapper = nullptr;
1259293Sandreas.hansson@arm.com        ew->throw_it();
1264762Snate@binkert.org    }
1278931Sandreas.hansson@arm.com}
1288931Sandreas.hansson@arm.com
1298931Sandreas.hansson@arm.comvoid
1308931Sandreas.hansson@arm.comScheduler::ready(Process *p)
1318931Sandreas.hansson@arm.com{
1328931Sandreas.hansson@arm.com    // Clump methods together to minimize context switching.
1338931Sandreas.hansson@arm.com    if (p->procKind() == ::sc_core::SC_METHOD_PROC_)
1348931Sandreas.hansson@arm.com        readyList.pushFirst(p);
1352391SN/A    else
1368931Sandreas.hansson@arm.com        readyList.pushLast(p);
1378931Sandreas.hansson@arm.com
1389413Sandreas.hansson@arm.com    scheduleReadyEvent();
1399413Sandreas.hansson@arm.com}
1409413Sandreas.hansson@arm.com
1418931Sandreas.hansson@arm.comvoid
1428931Sandreas.hansson@arm.comScheduler::requestUpdate(Channel *c)
1438931Sandreas.hansson@arm.com{
1448931Sandreas.hansson@arm.com    updateList.pushLast(c);
1458923Sandreas.hansson@arm.com    scheduleReadyEvent();
1468931Sandreas.hansson@arm.com}
1478931Sandreas.hansson@arm.com
1488931Sandreas.hansson@arm.comvoid
1498931Sandreas.hansson@arm.comScheduler::scheduleReadyEvent()
1508931Sandreas.hansson@arm.com{
1518931Sandreas.hansson@arm.com    // Schedule the evaluate and update phases.
1528923Sandreas.hansson@arm.com    if (!readyEvent.scheduled()) {
1539293Sandreas.hansson@arm.com        panic_if(!eq, "Need to schedule ready, but no event manager.\n");
1549293Sandreas.hansson@arm.com        eq->schedule(&readyEvent, eq->getCurTick());
1559293Sandreas.hansson@arm.com        if (starvationEvent.scheduled())
1569293Sandreas.hansson@arm.com            eq->deschedule(&starvationEvent);
1579293Sandreas.hansson@arm.com    }
1589293Sandreas.hansson@arm.com}
1599293Sandreas.hansson@arm.com
1609293Sandreas.hansson@arm.comvoid
1619293Sandreas.hansson@arm.comScheduler::scheduleStarvationEvent()
1629293Sandreas.hansson@arm.com{
1639293Sandreas.hansson@arm.com    if (!starvationEvent.scheduled()) {
1649293Sandreas.hansson@arm.com        panic_if(!eq, "Need to schedule starvation event, "
1659293Sandreas.hansson@arm.com                "but no event manager.\n");
1669293Sandreas.hansson@arm.com        eq->schedule(&starvationEvent, eq->getCurTick());
1679293Sandreas.hansson@arm.com        if (readyEvent.scheduled())
1688931Sandreas.hansson@arm.com            eq->deschedule(&readyEvent);
1699293Sandreas.hansson@arm.com    }
1709293Sandreas.hansson@arm.com}
1719293Sandreas.hansson@arm.com
1728931Sandreas.hansson@arm.comvoid
1739293Sandreas.hansson@arm.comScheduler::runReady()
1748719SAli.Saidi@ARM.com{
1758931Sandreas.hansson@arm.com    bool empty = readyList.empty();
1769293Sandreas.hansson@arm.com
1779293Sandreas.hansson@arm.com    // The evaluation phase.
1789293Sandreas.hansson@arm.com    do {
1799293Sandreas.hansson@arm.com        yield();
1809293Sandreas.hansson@arm.com    } while (!readyList.empty());
1819293Sandreas.hansson@arm.com
1829293Sandreas.hansson@arm.com    if (!empty)
1839293Sandreas.hansson@arm.com        _numCycles++;
1849293Sandreas.hansson@arm.com
1858931Sandreas.hansson@arm.com    // The update phase.
1869293Sandreas.hansson@arm.com    update();
1879293Sandreas.hansson@arm.com
1889293Sandreas.hansson@arm.com    if (starved() && !runToTime)
1899293Sandreas.hansson@arm.com        scheduleStarvationEvent();
1909293Sandreas.hansson@arm.com
1919293Sandreas.hansson@arm.com    // The delta phase will happen naturally through the event queue.
1929293Sandreas.hansson@arm.com}
1939293Sandreas.hansson@arm.com
1949293Sandreas.hansson@arm.comvoid
1959293Sandreas.hansson@arm.comScheduler::update()
1969293Sandreas.hansson@arm.com{
1979293Sandreas.hansson@arm.com    Channel *channel = updateList.getNext();
1989293Sandreas.hansson@arm.com    while (channel) {
1999293Sandreas.hansson@arm.com        channel->popListNode();
2009293Sandreas.hansson@arm.com        channel->update();
2019293Sandreas.hansson@arm.com        channel = updateList.getNext();
2029293Sandreas.hansson@arm.com    }
2039293Sandreas.hansson@arm.com}
2049293Sandreas.hansson@arm.com
2059293Sandreas.hansson@arm.comvoid
2069293Sandreas.hansson@arm.comScheduler::pause()
2079293Sandreas.hansson@arm.com{
2089293Sandreas.hansson@arm.com    _paused = true;
2099293Sandreas.hansson@arm.com    kernel->status(::sc_core::SC_PAUSED);
2109293Sandreas.hansson@arm.com    scMain->run();
2119293Sandreas.hansson@arm.com}
2129293Sandreas.hansson@arm.com
2139293Sandreas.hansson@arm.comvoid
2149293Sandreas.hansson@arm.comScheduler::stop()
2159293Sandreas.hansson@arm.com{
2169293Sandreas.hansson@arm.com    _stopped = true;
2179293Sandreas.hansson@arm.com    kernel->stop();
2189293Sandreas.hansson@arm.com    scMain->run();
2192391SN/A}
2202391SN/A
2212391SN/Avoid
222Scheduler::start(Tick max_tick, bool run_to_time)
223{
224    // We should be running from sc_main. Keep track of that Fiber to return
225    // to later.
226    scMain = Fiber::currentFiber();
227
228    _started = true;
229    _paused = false;
230    _stopped = false;
231    runToTime = run_to_time;
232
233    maxTick = max_tick;
234
235    if (starved() && !runToTime)
236        return;
237
238    if (initReady) {
239        kernel->status(::sc_core::SC_RUNNING);
240        eq->schedule(&maxTickEvent, maxTick);
241    }
242
243    // Return to gem5 to let it run events, etc.
244    Fiber::primaryFiber()->run();
245
246    if (pauseEvent.scheduled())
247        eq->deschedule(&pauseEvent);
248    if (stopEvent.scheduled())
249        eq->deschedule(&stopEvent);
250    if (maxTickEvent.scheduled())
251        eq->deschedule(&maxTickEvent);
252    if (starvationEvent.scheduled())
253        eq->deschedule(&starvationEvent);
254}
255
256void
257Scheduler::schedulePause()
258{
259    if (pauseEvent.scheduled())
260        return;
261
262    eq->schedule(&pauseEvent, eq->getCurTick());
263}
264
265void
266Scheduler::scheduleStop(bool finish_delta)
267{
268    if (stopEvent.scheduled())
269        return;
270
271    if (!finish_delta) {
272        // If we're not supposed to finish the delta cycle, flush the list
273        // of ready processes and scheduled updates.
274        Process *p;
275        while ((p = readyList.getNext()))
276            p->popListNode();
277        Channel *c;
278        while ((c = updateList.getNext()))
279            c->popListNode();
280    }
281    eq->schedule(&stopEvent, eq->getCurTick());
282}
283
284Scheduler scheduler;
285
286} // namespace sc_gem5
287