scheduler.cc revision 13308
112626Sodanrc@yahoo.com.br/*
212626Sodanrc@yahoo.com.br * Copyright 2018 Google, Inc.
312626Sodanrc@yahoo.com.br *
412626Sodanrc@yahoo.com.br * Redistribution and use in source and binary forms, with or without
512626Sodanrc@yahoo.com.br * modification, are permitted provided that the following conditions are
612626Sodanrc@yahoo.com.br * met: redistributions of source code must retain the above copyright
712626Sodanrc@yahoo.com.br * notice, this list of conditions and the following disclaimer;
812626Sodanrc@yahoo.com.br * redistributions in binary form must reproduce the above copyright
912626Sodanrc@yahoo.com.br * notice, this list of conditions and the following disclaimer in the
1012626Sodanrc@yahoo.com.br * documentation and/or other materials provided with the distribution;
1112626Sodanrc@yahoo.com.br * neither the name of the copyright holders nor the names of its
1212626Sodanrc@yahoo.com.br * contributors may be used to endorse or promote products derived from
1312626Sodanrc@yahoo.com.br * this software without specific prior written permission.
1412626Sodanrc@yahoo.com.br *
1512626Sodanrc@yahoo.com.br * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1612626Sodanrc@yahoo.com.br * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1712626Sodanrc@yahoo.com.br * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1812626Sodanrc@yahoo.com.br * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1912626Sodanrc@yahoo.com.br * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2012626Sodanrc@yahoo.com.br * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2112626Sodanrc@yahoo.com.br * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2212626Sodanrc@yahoo.com.br * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2312626Sodanrc@yahoo.com.br * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2412626Sodanrc@yahoo.com.br * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2512626Sodanrc@yahoo.com.br * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2612626Sodanrc@yahoo.com.br *
2712626Sodanrc@yahoo.com.br * Authors: Gabe Black
2812626Sodanrc@yahoo.com.br */
2912626Sodanrc@yahoo.com.br
3012626Sodanrc@yahoo.com.br#include "systemc/core/scheduler.hh"
3112626Sodanrc@yahoo.com.br
3212626Sodanrc@yahoo.com.br#include "base/fiber.hh"
3312727Snikos.nikoleris@arm.com#include "base/logging.hh"
3412684Sodanrc@yahoo.com.br#include "sim/eventq.hh"
3512684Sodanrc@yahoo.com.br#include "systemc/core/kernel.hh"
3612684Sodanrc@yahoo.com.br#include "systemc/ext/core/sc_main.hh"
3712626Sodanrc@yahoo.com.br#include "systemc/ext/utils/sc_report.hh"
3812727Snikos.nikoleris@arm.com#include "systemc/ext/utils/sc_report_handler.hh"
3912626Sodanrc@yahoo.com.br#include "systemc/utils/tracefile.hh"
4012626Sodanrc@yahoo.com.br
4112626Sodanrc@yahoo.com.brnamespace sc_gem5
4212626Sodanrc@yahoo.com.br{
4312626Sodanrc@yahoo.com.br
4412684Sodanrc@yahoo.com.brScheduler::Scheduler() :
4512684Sodanrc@yahoo.com.br    eq(nullptr), readyEvent(this, false, ReadyPriority),
4612684Sodanrc@yahoo.com.br    pauseEvent(this, false, PausePriority),
4712684Sodanrc@yahoo.com.br    stopEvent(this, false, StopPriority),
4812684Sodanrc@yahoo.com.br    scMain(nullptr), _throwToScMain(nullptr),
4912684Sodanrc@yahoo.com.br    starvationEvent(this, false, StarvationPriority),
5012684Sodanrc@yahoo.com.br    _elaborationDone(false), _started(false), _stopNow(false),
5112684Sodanrc@yahoo.com.br    _status(StatusOther), maxTickEvent(this, false, MaxTickPriority),
5212684Sodanrc@yahoo.com.br    timeAdvancesEvent(this, false, TimeAdvancesPriority), _numCycles(0),
5312684Sodanrc@yahoo.com.br    _changeStamp(0), _current(nullptr), initDone(false), runOnce(false)
5412684Sodanrc@yahoo.com.br{}
5512684Sodanrc@yahoo.com.br
5612684Sodanrc@yahoo.com.brScheduler::~Scheduler()
5712684Sodanrc@yahoo.com.br{
5812684Sodanrc@yahoo.com.br    // Clear out everything that belongs to us to make sure nobody tries to
5912684Sodanrc@yahoo.com.br    // clear themselves out after the scheduler goes away.
6012684Sodanrc@yahoo.com.br    clear();
6112684Sodanrc@yahoo.com.br}
6212684Sodanrc@yahoo.com.br
6312684Sodanrc@yahoo.com.brvoid
6412684Sodanrc@yahoo.com.brScheduler::clear()
6512684Sodanrc@yahoo.com.br{
6612684Sodanrc@yahoo.com.br    // Delta notifications.
6712684Sodanrc@yahoo.com.br    while (!deltas.empty())
6812684Sodanrc@yahoo.com.br        deltas.front()->deschedule();
6912684Sodanrc@yahoo.com.br
7012684Sodanrc@yahoo.com.br    // Timed notifications.
7112626Sodanrc@yahoo.com.br    for (auto &tsp: timeSlots) {
7212626Sodanrc@yahoo.com.br        TimeSlot *&ts = tsp.second;
7312626Sodanrc@yahoo.com.br        while (!ts->events.empty())
7412626Sodanrc@yahoo.com.br            ts->events.front()->deschedule();
7512684Sodanrc@yahoo.com.br        deschedule(ts);
7612626Sodanrc@yahoo.com.br    }
7712684Sodanrc@yahoo.com.br    timeSlots.clear();
7812684Sodanrc@yahoo.com.br
7912626Sodanrc@yahoo.com.br    // gem5 events.
8012684Sodanrc@yahoo.com.br    if (readyEvent.scheduled())
8112684Sodanrc@yahoo.com.br        deschedule(&readyEvent);
8212684Sodanrc@yahoo.com.br    if (pauseEvent.scheduled())
8312684Sodanrc@yahoo.com.br        deschedule(&pauseEvent);
8412684Sodanrc@yahoo.com.br    if (stopEvent.scheduled())
8512684Sodanrc@yahoo.com.br        deschedule(&stopEvent);
8612684Sodanrc@yahoo.com.br    if (starvationEvent.scheduled())
8712626Sodanrc@yahoo.com.br        deschedule(&starvationEvent);
8812626Sodanrc@yahoo.com.br    if (maxTickEvent.scheduled())
8912626Sodanrc@yahoo.com.br        deschedule(&maxTickEvent);
9012684Sodanrc@yahoo.com.br    if (timeAdvancesEvent.scheduled())
9112684Sodanrc@yahoo.com.br        deschedule(&timeAdvancesEvent);
9212626Sodanrc@yahoo.com.br
9312626Sodanrc@yahoo.com.br    Process *p;
9412626Sodanrc@yahoo.com.br    while ((p = initList.getNext()))
9512626Sodanrc@yahoo.com.br        p->popListNode();
9612684Sodanrc@yahoo.com.br    while ((p = readyListMethods.getNext()))
9712684Sodanrc@yahoo.com.br        p->popListNode();
9812684Sodanrc@yahoo.com.br    while ((p = readyListThreads.getNext()))
9912684Sodanrc@yahoo.com.br        p->popListNode();
10012684Sodanrc@yahoo.com.br
10112684Sodanrc@yahoo.com.br    Channel *c;
10212684Sodanrc@yahoo.com.br    while ((c = updateList.getNext()))
10312684Sodanrc@yahoo.com.br        c->popListNode();
10412626Sodanrc@yahoo.com.br}
10512684Sodanrc@yahoo.com.br
10612684Sodanrc@yahoo.com.brvoid
10712684Sodanrc@yahoo.com.brScheduler::initPhase()
10812684Sodanrc@yahoo.com.br{
10912684Sodanrc@yahoo.com.br    for (Process *p = initList.getNext(); p; p = initList.getNext()) {
11012684Sodanrc@yahoo.com.br        p->popListNode();
11112684Sodanrc@yahoo.com.br
11212684Sodanrc@yahoo.com.br        if (p->dontInitialize()) {
11312684Sodanrc@yahoo.com.br            if (!p->hasStaticSensitivities() && !p->internal()) {
11412684Sodanrc@yahoo.com.br                SC_REPORT_WARNING(
11512684Sodanrc@yahoo.com.br                        "(W558) disable() or dont_initialize() called on "
11612626Sodanrc@yahoo.com.br                        "process with no static sensitivity, it will be "
11712626Sodanrc@yahoo.com.br                        "orphaned", p->name());
11812626Sodanrc@yahoo.com.br            }
11912684Sodanrc@yahoo.com.br        } else {
12012684Sodanrc@yahoo.com.br            p->ready();
12112684Sodanrc@yahoo.com.br        }
12212626Sodanrc@yahoo.com.br    }
12312626Sodanrc@yahoo.com.br
12412626Sodanrc@yahoo.com.br    runUpdate();
12512626Sodanrc@yahoo.com.br    runDelta();
12612626Sodanrc@yahoo.com.br
12712684Sodanrc@yahoo.com.br    for (auto ets: eventsToSchedule)
12812684Sodanrc@yahoo.com.br        eq->schedule(ets.first, ets.second);
12912626Sodanrc@yahoo.com.br    eventsToSchedule.clear();
13012626Sodanrc@yahoo.com.br
13112626Sodanrc@yahoo.com.br    if (_started) {
13212684Sodanrc@yahoo.com.br        if (!runToTime && starved())
13312684Sodanrc@yahoo.com.br            scheduleStarvationEvent();
13412626Sodanrc@yahoo.com.br        kernel->status(::sc_core::SC_RUNNING);
13512684Sodanrc@yahoo.com.br    }
13612684Sodanrc@yahoo.com.br
13712684Sodanrc@yahoo.com.br    initDone = true;
13812684Sodanrc@yahoo.com.br
13912626Sodanrc@yahoo.com.br    status(StatusOther);
14012626Sodanrc@yahoo.com.br
14112626Sodanrc@yahoo.com.br    scheduleTimeAdvancesEvent();
14212626Sodanrc@yahoo.com.br}
14312626Sodanrc@yahoo.com.br
14412626Sodanrc@yahoo.com.brvoid
14512626Sodanrc@yahoo.com.brScheduler::reg(Process *p)
146{
147    if (initDone) {
148        // If not marked as dontInitialize, mark as ready.
149        if (!p->dontInitialize())
150            p->ready();
151    } else {
152        // Otherwise, record that this process should be initialized once we
153        // get there.
154        initList.pushLast(p);
155    }
156}
157
158void
159Scheduler::yield()
160{
161    // Pull a process from the active list.
162    _current = getNextReady();
163    if (!_current) {
164        // There are no more processes, so return control to evaluate.
165        Fiber::primaryFiber()->run();
166    } else {
167        _current->popListNode();
168        // Switch to whatever Fiber is supposed to run this process. All
169        // Fibers which aren't running should be parked at this line.
170        _current->fiber()->run();
171        // If the current process needs to be manually started, start it.
172        if (_current && _current->needsStart()) {
173            _current->needsStart(false);
174            // If a process hasn't started yet, "resetting" it just starts it
175            // and signals its reset event.
176            if (_current->inReset())
177                _current->resetEvent().notify();
178            try {
179                _current->run();
180            } catch (...) {
181                throwToScMain();
182            }
183        }
184    }
185    if (_current && !_current->needsStart()) {
186        if (_current->excWrapper) {
187            auto ew = _current->excWrapper;
188            _current->excWrapper = nullptr;
189            ew->throw_it();
190        } else if (_current->inReset()) {
191            _current->reset(false);
192        }
193    }
194}
195
196void
197Scheduler::ready(Process *p)
198{
199    if (_stopNow)
200        return;
201
202    if (p->procKind() == ::sc_core::SC_METHOD_PROC_)
203        readyListMethods.pushLast(p);
204    else
205        readyListThreads.pushLast(p);
206
207    if (!inEvaluate())
208        scheduleReadyEvent();
209}
210
211void
212Scheduler::resume(Process *p)
213{
214    if (initDone)
215        ready(p);
216    else
217        initList.pushLast(p);
218}
219
220bool
221listContains(ListNode *list, ListNode *target)
222{
223    ListNode *n = list->nextListNode;
224    while (n != list)
225        if (n == target)
226            return true;
227    return false;
228}
229
230bool
231Scheduler::suspend(Process *p)
232{
233    bool was_ready;
234    if (initDone) {
235        // After initialization, check if we're on a ready list.
236        was_ready = (p->nextListNode != nullptr);
237        p->popListNode();
238    } else {
239        // Nothing is ready before init.
240        was_ready = false;
241    }
242    return was_ready;
243}
244
245void
246Scheduler::requestUpdate(Channel *c)
247{
248    updateList.pushLast(c);
249    if (!inEvaluate())
250        scheduleReadyEvent();
251}
252
253void
254Scheduler::scheduleReadyEvent()
255{
256    // Schedule the evaluate and update phases.
257    if (!readyEvent.scheduled()) {
258        schedule(&readyEvent);
259        if (starvationEvent.scheduled())
260            deschedule(&starvationEvent);
261    }
262}
263
264void
265Scheduler::scheduleStarvationEvent()
266{
267    if (!starvationEvent.scheduled()) {
268        schedule(&starvationEvent);
269        if (readyEvent.scheduled())
270            deschedule(&readyEvent);
271    }
272}
273
274void
275Scheduler::runReady()
276{
277    scheduleTimeAdvancesEvent();
278
279    bool empty = readyListMethods.empty() && readyListThreads.empty();
280    lastReadyTick = getCurTick();
281
282    // The evaluation phase.
283    status(StatusEvaluate);
284    do {
285        yield();
286    } while (getNextReady());
287    _current = nullptr;
288
289    if (!empty) {
290        _numCycles++;
291        _changeStamp++;
292    }
293
294    if (_stopNow) {
295        status(StatusOther);
296        return;
297    }
298
299    runUpdate();
300    if (!traceFiles.empty())
301        trace(true);
302    runDelta();
303
304    if (!runToTime && starved())
305        scheduleStarvationEvent();
306
307    if (runOnce)
308        schedulePause();
309
310    status(StatusOther);
311}
312
313void
314Scheduler::runUpdate()
315{
316    status(StatusUpdate);
317
318    try {
319        Channel *channel = updateList.getNext();
320        while (channel) {
321            channel->popListNode();
322            channel->update();
323            channel = updateList.getNext();
324        }
325    } catch (...) {
326        throwToScMain();
327    }
328}
329
330void
331Scheduler::runDelta()
332{
333    status(StatusDelta);
334
335    try {
336        while (!deltas.empty())
337            deltas.back()->run();
338    } catch (...) {
339        throwToScMain();
340    }
341}
342
343void
344Scheduler::pause()
345{
346    status(StatusPaused);
347    kernel->status(::sc_core::SC_PAUSED);
348    runOnce = false;
349    if (scMain && !scMain->finished())
350        scMain->run();
351}
352
353void
354Scheduler::stop()
355{
356    status(StatusStopped);
357    kernel->stop();
358
359    clear();
360
361    runOnce = false;
362    if (scMain && !scMain->finished())
363        scMain->run();
364}
365
366void
367Scheduler::start(Tick max_tick, bool run_to_time)
368{
369    // We should be running from sc_main. Keep track of that Fiber to return
370    // to later.
371    scMain = Fiber::currentFiber();
372
373    _started = true;
374    status(StatusOther);
375    runToTime = run_to_time;
376
377    maxTick = max_tick;
378    lastReadyTick = getCurTick();
379
380    if (initDone) {
381        if (!runToTime && starved())
382            scheduleStarvationEvent();
383        kernel->status(::sc_core::SC_RUNNING);
384    }
385
386    schedule(&maxTickEvent, maxTick);
387    scheduleTimeAdvancesEvent();
388
389    // Return to gem5 to let it run events, etc.
390    Fiber::primaryFiber()->run();
391
392    if (pauseEvent.scheduled())
393        deschedule(&pauseEvent);
394    if (stopEvent.scheduled())
395        deschedule(&stopEvent);
396    if (maxTickEvent.scheduled())
397        deschedule(&maxTickEvent);
398    if (starvationEvent.scheduled())
399        deschedule(&starvationEvent);
400
401    if (_throwToScMain) {
402        const ::sc_core::sc_report *to_throw = _throwToScMain;
403        _throwToScMain = nullptr;
404        throw *to_throw;
405    }
406}
407
408void
409Scheduler::oneCycle()
410{
411    runOnce = true;
412    scheduleReadyEvent();
413    start(::MaxTick, false);
414}
415
416void
417Scheduler::schedulePause()
418{
419    if (pauseEvent.scheduled())
420        return;
421
422    schedule(&pauseEvent);
423}
424
425void
426Scheduler::throwToScMain()
427{
428    ::sc_core::sc_report report = reportifyException();
429    _throwToScMain = &report;
430    status(StatusOther);
431    scMain->run();
432}
433
434void
435Scheduler::scheduleStop(bool finish_delta)
436{
437    if (stopEvent.scheduled())
438        return;
439
440    if (!finish_delta) {
441        _stopNow = true;
442        // If we're not supposed to finish the delta cycle, flush all
443        // pending activity.
444        clear();
445    }
446    schedule(&stopEvent);
447}
448
449void
450Scheduler::trace(bool delta)
451{
452    for (auto tf: traceFiles)
453        tf->trace(delta);
454}
455
456Scheduler scheduler;
457
458namespace {
459
460void
461throwingReportHandler(const ::sc_core::sc_report &r,
462                      const ::sc_core::sc_actions &)
463{
464    throw r;
465}
466
467} // anonymous namespace
468
469const ::sc_core::sc_report
470reportifyException()
471{
472    ::sc_core::sc_report_handler_proc old_handler =
473        ::sc_core::sc_report_handler::get_handler();
474    ::sc_core::sc_report_handler::set_handler(&throwingReportHandler);
475
476    try {
477        try {
478            // Rethrow the current exception so we can catch it and throw an
479            // sc_report instead if it's not a type we recognize/can handle.
480            throw;
481        } catch (const ::sc_core::sc_report &) {
482            // It's already a sc_report, so nothing to do.
483            throw;
484        } catch (const ::sc_core::sc_unwind_exception &) {
485            panic("Kill/reset exception escaped a Process::run()");
486        } catch (const std::exception &e) {
487            SC_REPORT_ERROR("uncaught exception", e.what());
488        } catch (const char *msg) {
489            SC_REPORT_ERROR("uncaught exception", msg);
490        } catch (...) {
491            SC_REPORT_ERROR("uncaught exception", "UNKNOWN EXCEPTION");
492        }
493    } catch (const ::sc_core::sc_report &r) {
494        ::sc_core::sc_report_handler::set_handler(old_handler);
495        return r;
496    }
497    panic("No exception thrown in reportifyException.");
498}
499
500} // namespace sc_gem5
501