scheduler.cc revision 13329:a2d273c8e667
14486Sbinkertn@umich.edu/*
24486Sbinkertn@umich.edu * Copyright 2018 Google, Inc.
34486Sbinkertn@umich.edu *
44486Sbinkertn@umich.edu * Redistribution and use in source and binary forms, with or without
54486Sbinkertn@umich.edu * modification, are permitted provided that the following conditions are
64486Sbinkertn@umich.edu * met: redistributions of source code must retain the above copyright
74486Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer;
84486Sbinkertn@umich.edu * redistributions in binary form must reproduce the above copyright
94486Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer in the
104486Sbinkertn@umich.edu * documentation and/or other materials provided with the distribution;
114486Sbinkertn@umich.edu * neither the name of the copyright holders nor the names of its
124486Sbinkertn@umich.edu * contributors may be used to endorse or promote products derived from
134486Sbinkertn@umich.edu * this software without specific prior written permission.
144486Sbinkertn@umich.edu *
154486Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
164486Sbinkertn@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
174486Sbinkertn@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
184486Sbinkertn@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
194486Sbinkertn@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
204486Sbinkertn@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
214486Sbinkertn@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
224486Sbinkertn@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
234486Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
244486Sbinkertn@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
254486Sbinkertn@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
264486Sbinkertn@umich.edu *
274486Sbinkertn@umich.edu * Authors: Gabe Black
284486Sbinkertn@umich.edu */
293630SN/A
303630SN/A#include "systemc/core/scheduler.hh"
314104SN/A
325478Snate@binkert.org#include "base/fiber.hh"
335478Snate@binkert.org#include "base/logging.hh"
343743SN/A#include "sim/eventq.hh"
353630SN/A#include "systemc/core/kernel.hh"
363898SN/A#include "systemc/ext/core/messages.hh"
373898SN/A#include "systemc/ext/core/sc_main.hh"
383898SN/A#include "systemc/ext/utils/sc_report.hh"
399338SAndreas.Sandberg@arm.com#include "systemc/ext/utils/sc_report_handler.hh"
403898SN/A#include "systemc/utils/report.hh"
413898SN/A#include "systemc/utils/tracefile.hh"
423898SN/A
433914SN/Anamespace sc_gem5
443914SN/A{
459338SAndreas.Sandberg@arm.com
463914SN/AScheduler::Scheduler() :
473914SN/A    eq(nullptr), readyEvent(this, false, ReadyPriority),
483914SN/A    pauseEvent(this, false, PausePriority),
494104SN/A    stopEvent(this, false, StopPriority),
504104SN/A    scMain(nullptr), _throwToScMain(nullptr),
519338SAndreas.Sandberg@arm.com    starvationEvent(this, false, StarvationPriority),
528742Sgblack@eecs.umich.edu    _elaborationDone(false), _started(false), _stopNow(false),
539162Sandreas.hansson@arm.com    _status(StatusOther), maxTickEvent(this, false, MaxTickPriority),
544104SN/A    timeAdvancesEvent(this, false, TimeAdvancesPriority), _numCycles(0),
553914SN/A    _changeStamp(0), _current(nullptr), initDone(false), runOnce(false)
563630SN/A{}
573630SN/A
589338SAndreas.Sandberg@arm.comScheduler::~Scheduler()
593630SN/A{
603630SN/A    // Clear out everything that belongs to us to make sure nobody tries to
614007SN/A    // clear themselves out after the scheduler goes away.
624007SN/A    clear();
633630SN/A}
643814SN/A
654007SN/Avoid
664007SN/AScheduler::clear()
673814SN/A{
684007SN/A    // Delta notifications.
694007SN/A    while (!deltas.empty())
703814SN/A        deltas.front()->deschedule();
713814SN/A
724007SN/A    // Timed notifications.
734007SN/A    for (auto &tsp: timeSlots) {
743814SN/A        TimeSlot *&ts = tsp.second;
753814SN/A        while (!ts->events.empty())
764007SN/A            ts->events.front()->deschedule();
774007SN/A        deschedule(ts);
783814SN/A    }
793814SN/A    timeSlots.clear();
804007SN/A
814007SN/A    // gem5 events.
823814SN/A    if (readyEvent.scheduled())
833814SN/A        deschedule(&readyEvent);
844007SN/A    if (pauseEvent.scheduled())
854007SN/A        deschedule(&pauseEvent);
863814SN/A    if (stopEvent.scheduled())
873825SN/A        deschedule(&stopEvent);
884007SN/A    if (starvationEvent.scheduled())
894007SN/A        deschedule(&starvationEvent);
903825SN/A    if (maxTickEvent.scheduled())
913825SN/A        deschedule(&maxTickEvent);
924007SN/A    if (timeAdvancesEvent.scheduled())
934007SN/A        deschedule(&timeAdvancesEvent);
943825SN/A
953825SN/A    Process *p;
964007SN/A    while ((p = initList.getNext()))
974007SN/A        p->popListNode();
983825SN/A    while ((p = readyListMethods.getNext()))
993825SN/A        p->popListNode();
1004007SN/A    while ((p = readyListThreads.getNext()))
1014007SN/A        p->popListNode();
1023825SN/A
1034007SN/A    Channel *c;
1044007SN/A    while ((c = updateList.getNext()))
1053814SN/A        c->popListNode();
1065478Snate@binkert.org}
1073814SN/A
1083914SN/Avoid
1093914SN/AScheduler::initPhase()
1105478Snate@binkert.org{
1113814SN/A    for (Process *p = initList.getNext(); p; p = initList.getNext()) {
1123630SN/A        p->popListNode();
1134104SN/A
1144104SN/A        if (p->dontInitialize()) {
1154104SN/A            if (!p->hasStaticSensitivities() && !p->internal()) {
1168847Sandreas.hansson@arm.com                SC_REPORT_WARNING(sc_core::SC_ID_DISABLE_WILL_ORPHAN_PROCESS_,
1178847Sandreas.hansson@arm.com                        p->name());
1184104SN/A            }
1194104SN/A        } else {
1203630SN/A            p->ready();
1213630SN/A        }
1223630SN/A    }
1233630SN/A
12412274Sgabeblack@google.com    runUpdate();
12512274Sgabeblack@google.com    runDelta();
1268847Sandreas.hansson@arm.com
1278847Sandreas.hansson@arm.com    for (auto ets: eventsToSchedule)
1288847Sandreas.hansson@arm.com        eq->schedule(ets.first, ets.second);
1298847Sandreas.hansson@arm.com    eventsToSchedule.clear();
1308847Sandreas.hansson@arm.com
1318847Sandreas.hansson@arm.com    if (_started) {
1328847Sandreas.hansson@arm.com        if (!runToTime && starved())
1338847Sandreas.hansson@arm.com            scheduleStarvationEvent();
1348847Sandreas.hansson@arm.com        kernel->status(::sc_core::SC_RUNNING);
1358847Sandreas.hansson@arm.com    }
1368847Sandreas.hansson@arm.com
1378847Sandreas.hansson@arm.com    initDone = true;
1388847Sandreas.hansson@arm.com
1398847Sandreas.hansson@arm.com    status(StatusOther);
140
141    scheduleTimeAdvancesEvent();
142}
143
144void
145Scheduler::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        _current->scheduled(false);
169        // Switch to whatever Fiber is supposed to run this process. All
170        // Fibers which aren't running should be parked at this line.
171        _current->fiber()->run();
172        // If the current process needs to be manually started, start it.
173        if (_current && _current->needsStart()) {
174            _current->needsStart(false);
175            // If a process hasn't started yet, "resetting" it just starts it
176            // and signals its reset event.
177            if (_current->inReset())
178                _current->resetEvent().notify();
179            try {
180                _current->run();
181            } catch (...) {
182                throwToScMain();
183            }
184        }
185    }
186    if (_current && !_current->needsStart()) {
187        if (_current->excWrapper) {
188            auto ew = _current->excWrapper;
189            _current->excWrapper = nullptr;
190            ew->throw_it();
191        } else if (_current->inReset()) {
192            _current->reset(false);
193        }
194    }
195}
196
197void
198Scheduler::ready(Process *p)
199{
200    if (_stopNow)
201        return;
202
203    p->scheduled(true);
204
205    if (p->procKind() == ::sc_core::SC_METHOD_PROC_)
206        readyListMethods.pushLast(p);
207    else
208        readyListThreads.pushLast(p);
209
210    if (!inEvaluate())
211        scheduleReadyEvent();
212}
213
214void
215Scheduler::resume(Process *p)
216{
217    if (initDone)
218        ready(p);
219    else
220        initList.pushLast(p);
221}
222
223bool
224listContains(ListNode *list, ListNode *target)
225{
226    ListNode *n = list->nextListNode;
227    while (n != list)
228        if (n == target)
229            return true;
230    return false;
231}
232
233bool
234Scheduler::suspend(Process *p)
235{
236    bool was_ready;
237    if (initDone) {
238        // After initialization, check if we're on a ready list.
239        was_ready = (p->nextListNode != nullptr);
240        p->popListNode();
241    } else {
242        // Nothing is ready before init.
243        was_ready = false;
244    }
245    return was_ready;
246}
247
248void
249Scheduler::requestUpdate(Channel *c)
250{
251    updateList.pushLast(c);
252    if (!inEvaluate())
253        scheduleReadyEvent();
254}
255
256void
257Scheduler::scheduleReadyEvent()
258{
259    // Schedule the evaluate and update phases.
260    if (!readyEvent.scheduled()) {
261        schedule(&readyEvent);
262        if (starvationEvent.scheduled())
263            deschedule(&starvationEvent);
264    }
265}
266
267void
268Scheduler::scheduleStarvationEvent()
269{
270    if (!starvationEvent.scheduled()) {
271        schedule(&starvationEvent);
272        if (readyEvent.scheduled())
273            deschedule(&readyEvent);
274    }
275}
276
277void
278Scheduler::runReady()
279{
280    scheduleTimeAdvancesEvent();
281
282    bool empty = readyListMethods.empty() && readyListThreads.empty();
283    lastReadyTick = getCurTick();
284
285    // The evaluation phase.
286    status(StatusEvaluate);
287    do {
288        yield();
289    } while (getNextReady());
290    _current = nullptr;
291
292    if (!empty) {
293        _numCycles++;
294        _changeStamp++;
295    }
296
297    if (_stopNow) {
298        status(StatusOther);
299        return;
300    }
301
302    runUpdate();
303    if (!traceFiles.empty())
304        trace(true);
305    runDelta();
306
307    if (!runToTime && starved())
308        scheduleStarvationEvent();
309
310    if (runOnce)
311        schedulePause();
312
313    status(StatusOther);
314}
315
316void
317Scheduler::runUpdate()
318{
319    status(StatusUpdate);
320
321    try {
322        Channel *channel = updateList.getNext();
323        while (channel) {
324            channel->popListNode();
325            channel->update();
326            channel = updateList.getNext();
327        }
328    } catch (...) {
329        throwToScMain();
330    }
331}
332
333void
334Scheduler::runDelta()
335{
336    status(StatusDelta);
337
338    try {
339        while (!deltas.empty())
340            deltas.back()->run();
341    } catch (...) {
342        throwToScMain();
343    }
344}
345
346void
347Scheduler::pause()
348{
349    status(StatusPaused);
350    kernel->status(::sc_core::SC_PAUSED);
351    runOnce = false;
352    if (scMain && !scMain->finished())
353        scMain->run();
354}
355
356void
357Scheduler::stop()
358{
359    status(StatusStopped);
360    kernel->stop();
361
362    clear();
363
364    runOnce = false;
365    if (scMain && !scMain->finished())
366        scMain->run();
367}
368
369void
370Scheduler::start(Tick max_tick, bool run_to_time)
371{
372    // We should be running from sc_main. Keep track of that Fiber to return
373    // to later.
374    scMain = Fiber::currentFiber();
375
376    _started = true;
377    status(StatusOther);
378    runToTime = run_to_time;
379
380    maxTick = max_tick;
381    lastReadyTick = getCurTick();
382
383    if (initDone) {
384        if (!runToTime && starved())
385            scheduleStarvationEvent();
386        kernel->status(::sc_core::SC_RUNNING);
387    }
388
389    schedule(&maxTickEvent, maxTick);
390    scheduleTimeAdvancesEvent();
391
392    // Return to gem5 to let it run events, etc.
393    Fiber::primaryFiber()->run();
394
395    if (pauseEvent.scheduled())
396        deschedule(&pauseEvent);
397    if (stopEvent.scheduled())
398        deschedule(&stopEvent);
399    if (maxTickEvent.scheduled())
400        deschedule(&maxTickEvent);
401    if (starvationEvent.scheduled())
402        deschedule(&starvationEvent);
403
404    if (_throwToScMain) {
405        const ::sc_core::sc_report *to_throw = _throwToScMain;
406        _throwToScMain = nullptr;
407        throw *to_throw;
408    }
409}
410
411void
412Scheduler::oneCycle()
413{
414    runOnce = true;
415    scheduleReadyEvent();
416    start(::MaxTick, false);
417}
418
419void
420Scheduler::schedulePause()
421{
422    if (pauseEvent.scheduled())
423        return;
424
425    schedule(&pauseEvent);
426}
427
428void
429Scheduler::throwToScMain()
430{
431    ::sc_core::sc_report report = reportifyException();
432    _throwToScMain = &report;
433    status(StatusOther);
434    scMain->run();
435}
436
437void
438Scheduler::scheduleStop(bool finish_delta)
439{
440    if (stopEvent.scheduled())
441        return;
442
443    if (!finish_delta) {
444        _stopNow = true;
445        // If we're not supposed to finish the delta cycle, flush all
446        // pending activity.
447        clear();
448    }
449    schedule(&stopEvent);
450}
451
452void
453Scheduler::trace(bool delta)
454{
455    for (auto tf: traceFiles)
456        tf->trace(delta);
457}
458
459Scheduler scheduler;
460Process *getCurrentProcess() { return scheduler.current(); }
461
462namespace {
463
464void
465throwingReportHandler(const ::sc_core::sc_report &r,
466                      const ::sc_core::sc_actions &)
467{
468    throw r;
469}
470
471} // anonymous namespace
472
473const ::sc_core::sc_report
474reportifyException()
475{
476    ::sc_core::sc_report_handler_proc old_handler = reportHandlerProc;
477    ::sc_core::sc_report_handler::set_handler(&throwingReportHandler);
478
479    try {
480        try {
481            // Rethrow the current exception so we can catch it and throw an
482            // sc_report instead if it's not a type we recognize/can handle.
483            throw;
484        } catch (const ::sc_core::sc_report &) {
485            // It's already a sc_report, so nothing to do.
486            throw;
487        } catch (const ::sc_core::sc_unwind_exception &) {
488            panic("Kill/reset exception escaped a Process::run()");
489        } catch (const std::exception &e) {
490            SC_REPORT_ERROR(
491                    sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_, e.what());
492        } catch (const char *msg) {
493            SC_REPORT_ERROR(
494                    sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_, msg);
495        } catch (...) {
496            SC_REPORT_ERROR(
497                    sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_,
498                    "UNKNOWN EXCEPTION");
499        }
500    } catch (const ::sc_core::sc_report &r) {
501        ::sc_core::sc_report_handler::set_handler(old_handler);
502        return r;
503    }
504    panic("No exception thrown in reportifyException.");
505}
506
507} // namespace sc_gem5
508