scheduler.cc revision 13133
112953Sgabeblack@google.com/*
212953Sgabeblack@google.com * Copyright 2018 Google, Inc.
312953Sgabeblack@google.com *
412953Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
512953Sgabeblack@google.com * modification, are permitted provided that the following conditions are
612953Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
712953Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
812953Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
912953Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
1012953Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
1112953Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
1212953Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
1312953Sgabeblack@google.com * this software without specific prior written permission.
1412953Sgabeblack@google.com *
1512953Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1612953Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1712953Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1812953Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1912953Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2012953Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2112953Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2212953Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2312953Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2412953Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2512953Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2612953Sgabeblack@google.com *
2712953Sgabeblack@google.com * Authors: Gabe Black
2812953Sgabeblack@google.com */
2912953Sgabeblack@google.com
3012953Sgabeblack@google.com#include "systemc/core/scheduler.hh"
3112953Sgabeblack@google.com
3212953Sgabeblack@google.com#include "base/fiber.hh"
3312954Sgabeblack@google.com#include "base/logging.hh"
3412954Sgabeblack@google.com#include "sim/eventq.hh"
3512982Sgabeblack@google.com#include "systemc/core/kernel.hh"
3612982Sgabeblack@google.com#include "systemc/ext/core/sc_main.hh"
3712953Sgabeblack@google.com
3812953Sgabeblack@google.comnamespace sc_gem5
3912953Sgabeblack@google.com{
4012953Sgabeblack@google.com
4112954Sgabeblack@google.comScheduler::Scheduler() :
4212962Sgabeblack@google.com    eq(nullptr), readyEvent(this, false, ReadyPriority),
4312961Sgabeblack@google.com    pauseEvent(this, false, PausePriority),
4412961Sgabeblack@google.com    stopEvent(this, false, StopPriority),
4512987Sgabeblack@google.com    scMain(nullptr),
4612987Sgabeblack@google.com    starvationEvent(this, false, StarvationPriority),
4712987Sgabeblack@google.com    _started(false), _paused(false), _stopped(false),
4812961Sgabeblack@google.com    maxTickEvent(this, false, MaxTickPriority),
4913067Sgabeblack@google.com    _numCycles(0), _current(nullptr), initDone(false),
5013061Sgabeblack@google.com    runOnce(false)
5112954Sgabeblack@google.com{}
5212953Sgabeblack@google.com
5313072Sgabeblack@google.comScheduler::~Scheduler()
5413072Sgabeblack@google.com{
5513072Sgabeblack@google.com    // Clear out everything that belongs to us to make sure nobody tries to
5613072Sgabeblack@google.com    // clear themselves out after the scheduler goes away.
5713076Sgabeblack@google.com    clear();
5813076Sgabeblack@google.com}
5913072Sgabeblack@google.com
6013076Sgabeblack@google.comvoid
6113076Sgabeblack@google.comScheduler::clear()
6213076Sgabeblack@google.com{
6313072Sgabeblack@google.com    // Delta notifications.
6413072Sgabeblack@google.com    for (auto &e: deltas)
6513072Sgabeblack@google.com        e->deschedule();
6613076Sgabeblack@google.com    deltas.clear();
6713072Sgabeblack@google.com
6813072Sgabeblack@google.com    // Timed notifications.
6913076Sgabeblack@google.com    for (auto &tsp: timeSlots) {
7013076Sgabeblack@google.com        TimeSlot *&ts = tsp.second;
7113076Sgabeblack@google.com        for (auto &e: ts->events)
7213072Sgabeblack@google.com            e->deschedule();
7313088Sgabeblack@google.com        deschedule(ts);
7413072Sgabeblack@google.com    }
7513076Sgabeblack@google.com    timeSlots.clear();
7613072Sgabeblack@google.com
7713072Sgabeblack@google.com    // gem5 events.
7813072Sgabeblack@google.com    if (readyEvent.scheduled())
7913088Sgabeblack@google.com        deschedule(&readyEvent);
8013072Sgabeblack@google.com    if (pauseEvent.scheduled())
8113088Sgabeblack@google.com        deschedule(&pauseEvent);
8213072Sgabeblack@google.com    if (stopEvent.scheduled())
8313088Sgabeblack@google.com        deschedule(&stopEvent);
8413072Sgabeblack@google.com    if (starvationEvent.scheduled())
8513088Sgabeblack@google.com        deschedule(&starvationEvent);
8613072Sgabeblack@google.com    if (maxTickEvent.scheduled())
8713088Sgabeblack@google.com        deschedule(&maxTickEvent);
8813072Sgabeblack@google.com
8913072Sgabeblack@google.com    Process *p;
9013072Sgabeblack@google.com    while ((p = toFinalize.getNext()))
9113072Sgabeblack@google.com        p->popListNode();
9213072Sgabeblack@google.com    while ((p = initList.getNext()))
9313072Sgabeblack@google.com        p->popListNode();
9413072Sgabeblack@google.com    while ((p = readyList.getNext()))
9513072Sgabeblack@google.com        p->popListNode();
9613072Sgabeblack@google.com
9713072Sgabeblack@google.com    Channel *c;
9813072Sgabeblack@google.com    while ((c = updateList.getNext()))
9913072Sgabeblack@google.com        c->popListNode();
10013072Sgabeblack@google.com}
10113072Sgabeblack@google.com
10212953Sgabeblack@google.comvoid
10313067Sgabeblack@google.comScheduler::initPhase()
10412953Sgabeblack@google.com{
10512957Sgabeblack@google.com    for (Process *p = toFinalize.getNext(); p; p = toFinalize.getNext()) {
10612957Sgabeblack@google.com        p->finalize();
10712957Sgabeblack@google.com        p->popListNode();
10812957Sgabeblack@google.com    }
10912957Sgabeblack@google.com
11012957Sgabeblack@google.com    for (Process *p = initList.getNext(); p; p = initList.getNext()) {
11112957Sgabeblack@google.com        p->finalize();
11212996Sgabeblack@google.com        p->popListNode();
11312959Sgabeblack@google.com        p->ready();
11412957Sgabeblack@google.com    }
11512957Sgabeblack@google.com
11613067Sgabeblack@google.com    update();
11713067Sgabeblack@google.com
11813067Sgabeblack@google.com    for (auto &e: deltas)
11913067Sgabeblack@google.com        e->run();
12013067Sgabeblack@google.com    deltas.clear();
12113067Sgabeblack@google.com
12212985Sgabeblack@google.com    for (auto ets: eventsToSchedule)
12312985Sgabeblack@google.com        eq->schedule(ets.first, ets.second);
12412985Sgabeblack@google.com    eventsToSchedule.clear();
12512985Sgabeblack@google.com
12613068Sgabeblack@google.com    if (_started) {
12713096Sgabeblack@google.com        if (!runToTime && starved())
12813068Sgabeblack@google.com            scheduleStarvationEvent();
12913069Sgabeblack@google.com        kernel->status(::sc_core::SC_RUNNING);
13013068Sgabeblack@google.com    }
13112961Sgabeblack@google.com
13213067Sgabeblack@google.com    initDone = true;
13312957Sgabeblack@google.com}
13412957Sgabeblack@google.com
13512957Sgabeblack@google.comvoid
13612957Sgabeblack@google.comScheduler::reg(Process *p)
13712957Sgabeblack@google.com{
13813067Sgabeblack@google.com    if (initDone) {
13912957Sgabeblack@google.com        // If we're past initialization, finalize static sensitivity.
14012957Sgabeblack@google.com        p->finalize();
14112957Sgabeblack@google.com        // Mark the process as ready.
14212959Sgabeblack@google.com        p->ready();
14312957Sgabeblack@google.com    } else {
14412957Sgabeblack@google.com        // Otherwise, record that this process should be initialized once we
14512957Sgabeblack@google.com        // get there.
14612957Sgabeblack@google.com        initList.pushLast(p);
14712957Sgabeblack@google.com    }
14812957Sgabeblack@google.com}
14912957Sgabeblack@google.com
15012957Sgabeblack@google.comvoid
15112957Sgabeblack@google.comScheduler::dontInitialize(Process *p)
15212957Sgabeblack@google.com{
15313067Sgabeblack@google.com    if (initDone) {
15412957Sgabeblack@google.com        // Pop this process off of the ready list.
15512957Sgabeblack@google.com        p->popListNode();
15612957Sgabeblack@google.com    } else {
15712957Sgabeblack@google.com        // Push this process onto the list of processes which still need
15812957Sgabeblack@google.com        // their static sensitivity to be finalized. That implicitly pops it
15912957Sgabeblack@google.com        // off the list of processes to be initialized/marked ready.
16012957Sgabeblack@google.com        toFinalize.pushLast(p);
16112957Sgabeblack@google.com    }
16212953Sgabeblack@google.com}
16312953Sgabeblack@google.com
16412953Sgabeblack@google.comvoid
16512953Sgabeblack@google.comScheduler::yield()
16612953Sgabeblack@google.com{
16712953Sgabeblack@google.com    _current = readyList.getNext();
16812953Sgabeblack@google.com    if (!_current) {
16912953Sgabeblack@google.com        // There are no more processes, so return control to evaluate.
17012953Sgabeblack@google.com        Fiber::primaryFiber()->run();
17112953Sgabeblack@google.com    } else {
17212953Sgabeblack@google.com        _current->popListNode();
17312953Sgabeblack@google.com        // Switch to whatever Fiber is supposed to run this process. All
17412953Sgabeblack@google.com        // Fibers which aren't running should be parked at this line.
17512953Sgabeblack@google.com        _current->fiber()->run();
17612961Sgabeblack@google.com        // If the current process needs to be manually started, start it.
17713093Sgabeblack@google.com        if (_current && _current->needsStart()) {
17813093Sgabeblack@google.com            _current->needsStart(false);
17912953Sgabeblack@google.com            _current->run();
18013093Sgabeblack@google.com        }
18112953Sgabeblack@google.com    }
18212995Sgabeblack@google.com    if (_current && _current->excWrapper) {
18312995Sgabeblack@google.com        // Make sure this isn't a method process.
18412995Sgabeblack@google.com        assert(!_current->needsStart());
18512995Sgabeblack@google.com        auto ew = _current->excWrapper;
18612995Sgabeblack@google.com        _current->excWrapper = nullptr;
18712995Sgabeblack@google.com        ew->throw_it();
18812995Sgabeblack@google.com    }
18912953Sgabeblack@google.com}
19012953Sgabeblack@google.com
19112953Sgabeblack@google.comvoid
19212954Sgabeblack@google.comScheduler::ready(Process *p)
19312953Sgabeblack@google.com{
19412954Sgabeblack@google.com    // Clump methods together to minimize context switching.
19512954Sgabeblack@google.com    if (p->procKind() == ::sc_core::SC_METHOD_PROC_)
19612954Sgabeblack@google.com        readyList.pushFirst(p);
19712954Sgabeblack@google.com    else
19812954Sgabeblack@google.com        readyList.pushLast(p);
19912953Sgabeblack@google.com
20012954Sgabeblack@google.com    scheduleReadyEvent();
20112954Sgabeblack@google.com}
20212954Sgabeblack@google.com
20312954Sgabeblack@google.comvoid
20413133Sgabeblack@google.comScheduler::resume(Process *p)
20513133Sgabeblack@google.com{
20613133Sgabeblack@google.com    if (initDone)
20713133Sgabeblack@google.com        ready(p);
20813133Sgabeblack@google.com    else
20913133Sgabeblack@google.com        initList.pushLast(p);
21013133Sgabeblack@google.com}
21113133Sgabeblack@google.com
21213133Sgabeblack@google.combool
21313133Sgabeblack@google.comScheduler::suspend(Process *p)
21413133Sgabeblack@google.com{
21513133Sgabeblack@google.com    if (initDone) {
21613133Sgabeblack@google.com        // After initialization, the only list we can be on is the ready list.
21713133Sgabeblack@google.com        bool was_ready = (p->nextListNode != nullptr);
21813133Sgabeblack@google.com        p->popListNode();
21913133Sgabeblack@google.com        return was_ready;
22013133Sgabeblack@google.com    } else {
22113133Sgabeblack@google.com        bool was_ready = false;
22213133Sgabeblack@google.com        // Check the ready list to see if we find this process.
22313133Sgabeblack@google.com        ListNode *n = readyList.nextListNode;
22413133Sgabeblack@google.com        while (n != &readyList) {
22513133Sgabeblack@google.com            if (n == p) {
22613133Sgabeblack@google.com                was_ready = true;
22713133Sgabeblack@google.com                break;
22813133Sgabeblack@google.com            }
22913133Sgabeblack@google.com        }
23013133Sgabeblack@google.com        if (was_ready)
23113133Sgabeblack@google.com            toFinalize.pushLast(p);
23213133Sgabeblack@google.com        return was_ready;
23313133Sgabeblack@google.com    }
23413133Sgabeblack@google.com}
23513133Sgabeblack@google.com
23613133Sgabeblack@google.comvoid
23712954Sgabeblack@google.comScheduler::requestUpdate(Channel *c)
23812954Sgabeblack@google.com{
23912954Sgabeblack@google.com    updateList.pushLast(c);
24013069Sgabeblack@google.com    scheduleReadyEvent();
24112954Sgabeblack@google.com}
24212954Sgabeblack@google.com
24312954Sgabeblack@google.comvoid
24412954Sgabeblack@google.comScheduler::scheduleReadyEvent()
24512954Sgabeblack@google.com{
24612954Sgabeblack@google.com    // Schedule the evaluate and update phases.
24712954Sgabeblack@google.com    if (!readyEvent.scheduled()) {
24813069Sgabeblack@google.com        schedule(&readyEvent);
24912987Sgabeblack@google.com        if (starvationEvent.scheduled())
25013069Sgabeblack@google.com            deschedule(&starvationEvent);
25112987Sgabeblack@google.com    }
25212987Sgabeblack@google.com}
25312987Sgabeblack@google.com
25412987Sgabeblack@google.comvoid
25512987Sgabeblack@google.comScheduler::scheduleStarvationEvent()
25612987Sgabeblack@google.com{
25712987Sgabeblack@google.com    if (!starvationEvent.scheduled()) {
25813069Sgabeblack@google.com        schedule(&starvationEvent);
25912987Sgabeblack@google.com        if (readyEvent.scheduled())
26013069Sgabeblack@google.com            deschedule(&readyEvent);
26112954Sgabeblack@google.com    }
26212954Sgabeblack@google.com}
26312954Sgabeblack@google.com
26412954Sgabeblack@google.comvoid
26512954Sgabeblack@google.comScheduler::runReady()
26612954Sgabeblack@google.com{
26712954Sgabeblack@google.com    bool empty = readyList.empty();
26812954Sgabeblack@google.com
26912954Sgabeblack@google.com    // The evaluation phase.
27012953Sgabeblack@google.com    do {
27112953Sgabeblack@google.com        yield();
27212953Sgabeblack@google.com    } while (!readyList.empty());
27312954Sgabeblack@google.com
27412954Sgabeblack@google.com    if (!empty)
27512954Sgabeblack@google.com        _numCycles++;
27612954Sgabeblack@google.com
27712954Sgabeblack@google.com    // The update phase.
27812954Sgabeblack@google.com    update();
27912954Sgabeblack@google.com
28013063Sgabeblack@google.com    // The delta phase.
28113063Sgabeblack@google.com    for (auto &e: deltas)
28213063Sgabeblack@google.com        e->run();
28313063Sgabeblack@google.com    deltas.clear();
28413061Sgabeblack@google.com
28513096Sgabeblack@google.com    if (!runToTime && starved())
28613096Sgabeblack@google.com        scheduleStarvationEvent();
28713096Sgabeblack@google.com
28813064Sgabeblack@google.com    if (runOnce)
28913064Sgabeblack@google.com        schedulePause();
29012953Sgabeblack@google.com}
29112953Sgabeblack@google.com
29212953Sgabeblack@google.comvoid
29312953Sgabeblack@google.comScheduler::update()
29412953Sgabeblack@google.com{
29512954Sgabeblack@google.com    Channel *channel = updateList.getNext();
29612954Sgabeblack@google.com    while (channel) {
29712954Sgabeblack@google.com        channel->popListNode();
29812954Sgabeblack@google.com        channel->update();
29912954Sgabeblack@google.com        channel = updateList.getNext();
30012954Sgabeblack@google.com    }
30112953Sgabeblack@google.com}
30212953Sgabeblack@google.com
30312961Sgabeblack@google.comvoid
30412961Sgabeblack@google.comScheduler::pause()
30512961Sgabeblack@google.com{
30612961Sgabeblack@google.com    _paused = true;
30712982Sgabeblack@google.com    kernel->status(::sc_core::SC_PAUSED);
30813061Sgabeblack@google.com    runOnce = false;
30912961Sgabeblack@google.com    scMain->run();
31012961Sgabeblack@google.com}
31112961Sgabeblack@google.com
31212961Sgabeblack@google.comvoid
31312961Sgabeblack@google.comScheduler::stop()
31412961Sgabeblack@google.com{
31512961Sgabeblack@google.com    _stopped = true;
31612982Sgabeblack@google.com    kernel->stop();
31713074Sgabeblack@google.com
31813076Sgabeblack@google.com    clear();
31913074Sgabeblack@google.com
32013061Sgabeblack@google.com    runOnce = false;
32112961Sgabeblack@google.com    scMain->run();
32212961Sgabeblack@google.com}
32312961Sgabeblack@google.com
32412961Sgabeblack@google.comvoid
32512961Sgabeblack@google.comScheduler::start(Tick max_tick, bool run_to_time)
32612961Sgabeblack@google.com{
32712961Sgabeblack@google.com    // We should be running from sc_main. Keep track of that Fiber to return
32812961Sgabeblack@google.com    // to later.
32912961Sgabeblack@google.com    scMain = Fiber::currentFiber();
33012961Sgabeblack@google.com
33112961Sgabeblack@google.com    _started = true;
33212961Sgabeblack@google.com    _paused = false;
33312961Sgabeblack@google.com    _stopped = false;
33412987Sgabeblack@google.com    runToTime = run_to_time;
33512961Sgabeblack@google.com
33612961Sgabeblack@google.com    maxTick = max_tick;
33712961Sgabeblack@google.com
33813067Sgabeblack@google.com    if (initDone) {
33913096Sgabeblack@google.com        if (!runToTime && starved())
34013068Sgabeblack@google.com            scheduleStarvationEvent();
34112982Sgabeblack@google.com        kernel->status(::sc_core::SC_RUNNING);
34212982Sgabeblack@google.com    }
34312961Sgabeblack@google.com
34413069Sgabeblack@google.com    schedule(&maxTickEvent, maxTick);
34513069Sgabeblack@google.com
34612961Sgabeblack@google.com    // Return to gem5 to let it run events, etc.
34712961Sgabeblack@google.com    Fiber::primaryFiber()->run();
34812961Sgabeblack@google.com
34912961Sgabeblack@google.com    if (pauseEvent.scheduled())
35013088Sgabeblack@google.com        deschedule(&pauseEvent);
35112961Sgabeblack@google.com    if (stopEvent.scheduled())
35213088Sgabeblack@google.com        deschedule(&stopEvent);
35312961Sgabeblack@google.com    if (maxTickEvent.scheduled())
35413088Sgabeblack@google.com        deschedule(&maxTickEvent);
35512987Sgabeblack@google.com    if (starvationEvent.scheduled())
35613088Sgabeblack@google.com        deschedule(&starvationEvent);
35712961Sgabeblack@google.com}
35812961Sgabeblack@google.com
35912961Sgabeblack@google.comvoid
36013061Sgabeblack@google.comScheduler::oneCycle()
36113061Sgabeblack@google.com{
36213061Sgabeblack@google.com    runOnce = true;
36313095Sgabeblack@google.com    scheduleReadyEvent();
36413061Sgabeblack@google.com    start(::MaxTick, false);
36513061Sgabeblack@google.com}
36613061Sgabeblack@google.com
36713061Sgabeblack@google.comvoid
36812961Sgabeblack@google.comScheduler::schedulePause()
36912961Sgabeblack@google.com{
37012961Sgabeblack@google.com    if (pauseEvent.scheduled())
37112961Sgabeblack@google.com        return;
37212961Sgabeblack@google.com
37313088Sgabeblack@google.com    schedule(&pauseEvent);
37412961Sgabeblack@google.com}
37512961Sgabeblack@google.com
37612961Sgabeblack@google.comvoid
37712961Sgabeblack@google.comScheduler::scheduleStop(bool finish_delta)
37812961Sgabeblack@google.com{
37912961Sgabeblack@google.com    if (stopEvent.scheduled())
38012961Sgabeblack@google.com        return;
38112961Sgabeblack@google.com
38212961Sgabeblack@google.com    if (!finish_delta) {
38313076Sgabeblack@google.com        // If we're not supposed to finish the delta cycle, flush all
38413076Sgabeblack@google.com        // pending activity.
38513076Sgabeblack@google.com        clear();
38612961Sgabeblack@google.com    }
38713088Sgabeblack@google.com    schedule(&stopEvent);
38812961Sgabeblack@google.com}
38912961Sgabeblack@google.com
39012953Sgabeblack@google.comScheduler scheduler;
39112953Sgabeblack@google.com
39212953Sgabeblack@google.com} // namespace sc_gem5
393