eventq.cc revision 9356
12SN/A/*
21762SN/A * Copyright (c) 2000-2005 The Regents of The University of Michigan
35502Snate@binkert.org * Copyright (c) 2008 The Hewlett-Packard Development Company
42SN/A * All rights reserved.
52SN/A *
62SN/A * Redistribution and use in source and binary forms, with or without
72SN/A * modification, are permitted provided that the following conditions are
82SN/A * met: redistributions of source code must retain the above copyright
92SN/A * notice, this list of conditions and the following disclaimer;
102SN/A * redistributions in binary form must reproduce the above copyright
112SN/A * notice, this list of conditions and the following disclaimer in the
122SN/A * documentation and/or other materials provided with the distribution;
132SN/A * neither the name of the copyright holders nor the names of its
142SN/A * contributors may be used to endorse or promote products derived from
152SN/A * this software without specific prior written permission.
162SN/A *
172SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
182SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
192SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
202SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
212SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
222SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
232SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
242SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
252SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
262SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
272SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282665Ssaidi@eecs.umich.edu *
292665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt
302665Ssaidi@eecs.umich.edu *          Nathan Binkert
312665Ssaidi@eecs.umich.edu *          Steve Raasch
322SN/A */
332SN/A
345501Snate@binkert.org#include <cassert>
352SN/A#include <iostream>
362SN/A#include <string>
372SN/A#include <vector>
382SN/A
395502Snate@binkert.org#include "base/hashmap.hh"
405501Snate@binkert.org#include "base/misc.hh"
415501Snate@binkert.org#include "base/trace.hh"
421717SN/A#include "cpu/smt.hh"
438232Snate@binkert.org#include "debug/Config.hh"
445501Snate@binkert.org#include "sim/core.hh"
459356Snilay@cs.wisc.edu#include "sim/eventq_impl.hh"
462SN/A
472SN/Ausing namespace std;
482SN/A
492SN/A//
502SN/A// Main Event Queue
512SN/A//
522SN/A// Events on this queue are processed at the *beginning* of each
532SN/A// cycle, before the pipeline simulation is performed.
542SN/A//
555605Snate@binkert.orgEventQueue mainEventQueue("Main Event Queue");
562SN/A
574017Sstever@eecs.umich.edu#ifndef NDEBUG
584016Sstever@eecs.umich.eduCounter Event::instanceCounter = 0;
594017Sstever@eecs.umich.edu#endif
604016Sstever@eecs.umich.edu
615768Snate@binkert.orgEvent::~Event()
625768Snate@binkert.org{
635774Snate@binkert.org    assert(!scheduled());
647059Snate@binkert.org    flags = 0;
655768Snate@binkert.org}
665768Snate@binkert.org
675768Snate@binkert.orgconst std::string
685768Snate@binkert.orgEvent::name() const
695768Snate@binkert.org{
705768Snate@binkert.org#ifndef NDEBUG
715768Snate@binkert.org    return csprintf("Event_%d", instance);
725768Snate@binkert.org#else
735768Snate@binkert.org    return csprintf("Event_%x", (uintptr_t)this);
745768Snate@binkert.org#endif
755768Snate@binkert.org}
765768Snate@binkert.org
775768Snate@binkert.org
785602Snate@binkert.orgEvent *
795602Snate@binkert.orgEvent::insertBefore(Event *event, Event *curr)
805502Snate@binkert.org{
815503Snate@binkert.org    // Either way, event will be the top element in the 'in bin' list
825502Snate@binkert.org    // which is the pointer we need in order to look into the list, so
835502Snate@binkert.org    // we need to insert that into the bin list.
845502Snate@binkert.org    if (!curr || *event < *curr) {
855502Snate@binkert.org        // Insert the event before the current list since it is in the future.
865502Snate@binkert.org        event->nextBin = curr;
875503Snate@binkert.org        event->nextInBin = NULL;
885502Snate@binkert.org    } else {
895502Snate@binkert.org        // Since we're on the correct list, we need to point to the next list
905502Snate@binkert.org        event->nextBin = curr->nextBin;  // curr->nextBin can now become stale
915502Snate@binkert.org
925503Snate@binkert.org        // Insert event at the top of the stack
935503Snate@binkert.org        event->nextInBin = curr;
945503Snate@binkert.org    }
955502Snate@binkert.org
965503Snate@binkert.org    return event;
975502Snate@binkert.org}
985502Snate@binkert.org
992SN/Avoid
1002SN/AEventQueue::insert(Event *event)
1012SN/A{
1025502Snate@binkert.org    // Deal with the head case
1035502Snate@binkert.org    if (!head || *event <= *head) {
1045602Snate@binkert.org        head = Event::insertBefore(event, head);
1055502Snate@binkert.org        return;
1065502Snate@binkert.org    }
1072SN/A
1085502Snate@binkert.org    // Figure out either which 'in bin' list we are on, or where a new list
1095502Snate@binkert.org    // needs to be inserted
1105503Snate@binkert.org    Event *prev = head;
1115503Snate@binkert.org    Event *curr = head->nextBin;
1125503Snate@binkert.org    while (curr && *curr < *event) {
1135503Snate@binkert.org        prev = curr;
1145503Snate@binkert.org        curr = curr->nextBin;
1155502Snate@binkert.org    }
1162SN/A
1175503Snate@binkert.org    // Note: this operation may render all nextBin pointers on the
1185503Snate@binkert.org    // prev 'in bin' list stale (except for the top one)
1195602Snate@binkert.org    prev->nextBin = Event::insertBefore(event, curr);
1205502Snate@binkert.org}
1212SN/A
1225602Snate@binkert.orgEvent *
1235602Snate@binkert.orgEvent::removeItem(Event *event, Event *top)
1245502Snate@binkert.org{
1255503Snate@binkert.org    Event *curr = top;
1265503Snate@binkert.org    Event *next = top->nextInBin;
1275502Snate@binkert.org
1285503Snate@binkert.org    // if we removed the top item, we need to handle things specially
1295503Snate@binkert.org    // and just remove the top item, fixing up the next bin pointer of
1305503Snate@binkert.org    // the new top item
1315503Snate@binkert.org    if (event == top) {
1325503Snate@binkert.org        if (!next)
1335503Snate@binkert.org            return top->nextBin;
1345503Snate@binkert.org        next->nextBin = top->nextBin;
1355503Snate@binkert.org        return next;
1365503Snate@binkert.org    }
1375503Snate@binkert.org
1385503Snate@binkert.org    // Since we already checked the current element, we're going to
1395503Snate@binkert.org    // keep checking event against the next element.
1405503Snate@binkert.org    while (event != next) {
1415503Snate@binkert.org        if (!next)
1425502Snate@binkert.org            panic("event not found!");
1435502Snate@binkert.org
1445503Snate@binkert.org        curr = next;
1455503Snate@binkert.org        next = next->nextInBin;
1462SN/A    }
1475502Snate@binkert.org
1485503Snate@binkert.org    // remove next from the 'in bin' list since it's what we're looking for
1495503Snate@binkert.org    curr->nextInBin = next->nextInBin;
1505503Snate@binkert.org    return top;
1512SN/A}
1522SN/A
1532SN/Avoid
1542SN/AEventQueue::remove(Event *event)
1552SN/A{
1562SN/A    if (head == NULL)
1575502Snate@binkert.org        panic("event not found!");
1582SN/A
1595502Snate@binkert.org    // deal with an event on the head's 'in bin' list (event has the same
1605502Snate@binkert.org    // time as the head)
1615502Snate@binkert.org    if (*head == *event) {
1625602Snate@binkert.org        head = Event::removeItem(event, head);
1632SN/A        return;
1642SN/A    }
1652SN/A
1665502Snate@binkert.org    // Find the 'in bin' list that this event belongs on
1672SN/A    Event *prev = head;
1685502Snate@binkert.org    Event *curr = head->nextBin;
1695502Snate@binkert.org    while (curr && *curr < *event) {
1702SN/A        prev = curr;
1715502Snate@binkert.org        curr = curr->nextBin;
1722SN/A    }
1732SN/A
1745502Snate@binkert.org    if (!curr || *curr != *event)
1755502Snate@binkert.org        panic("event not found!");
1765502Snate@binkert.org
1775503Snate@binkert.org    // curr points to the top item of the the correct 'in bin' list, when
1785503Snate@binkert.org    // we remove an item, it returns the new top item (which may be
1795502Snate@binkert.org    // unchanged)
1805602Snate@binkert.org    prev->nextBin = Event::removeItem(event, curr);
1812SN/A}
1822SN/A
1832667Sstever@eecs.umich.eduEvent *
1842SN/AEventQueue::serviceOne()
1852SN/A{
1865503Snate@binkert.org    Event *event = head;
1875503Snate@binkert.org    Event *next = head->nextInBin;
1885769Snate@binkert.org    event->flags.clear(Event::Scheduled);
1895502Snate@binkert.org
1905503Snate@binkert.org    if (next) {
1915503Snate@binkert.org        // update the next bin pointer since it could be stale
1925503Snate@binkert.org        next->nextBin = head->nextBin;
1935503Snate@binkert.org
1945503Snate@binkert.org        // pop the stack
1955503Snate@binkert.org        head = next;
1965503Snate@binkert.org    } else {
1975502Snate@binkert.org        // this was the only element on the 'in bin' list, so get rid of
1985502Snate@binkert.org        // the 'in bin' list and point to the next bin list
1995503Snate@binkert.org        head = head->nextBin;
2005502Snate@binkert.org    }
2012SN/A
2022SN/A    // handle action
2032667Sstever@eecs.umich.edu    if (!event->squashed()) {
2049356Snilay@cs.wisc.edu        // forward current cycle to the time when this event occurs.
2059356Snilay@cs.wisc.edu        setCurTick(event->when());
2069356Snilay@cs.wisc.edu
2072SN/A        event->process();
2082667Sstever@eecs.umich.edu        if (event->isExitEvent()) {
2099328SAli.Saidi@ARM.com            assert(!event->flags.isSet(Event::AutoDelete) ||
2109328SAli.Saidi@ARM.com                   !event->flags.isSet(Event::IsMainQueue)); // would be silly
2112667Sstever@eecs.umich.edu            return event;
2122667Sstever@eecs.umich.edu        }
2132667Sstever@eecs.umich.edu    } else {
2145769Snate@binkert.org        event->flags.clear(Event::Squashed);
2152667Sstever@eecs.umich.edu    }
2162SN/A
2175769Snate@binkert.org    if (event->flags.isSet(Event::AutoDelete) && !event->scheduled())
2182SN/A        delete event;
2192667Sstever@eecs.umich.edu
2202667Sstever@eecs.umich.edu    return NULL;
2212SN/A}
2222SN/A
223224SN/Avoid
224224SN/AEvent::serialize(std::ostream &os)
225224SN/A{
226224SN/A    SERIALIZE_SCALAR(_when);
227224SN/A    SERIALIZE_SCALAR(_priority);
2285769Snate@binkert.org    short _flags = flags;
2295769Snate@binkert.org    SERIALIZE_SCALAR(_flags);
230224SN/A}
231224SN/A
232224SN/Avoid
233237SN/AEvent::unserialize(Checkpoint *cp, const string &section)
234224SN/A{
2355695Snate@binkert.org    if (scheduled())
2365695Snate@binkert.org        mainEventQueue.deschedule(this);
237224SN/A
238224SN/A    UNSERIALIZE_SCALAR(_when);
239224SN/A    UNSERIALIZE_SCALAR(_priority);
240224SN/A
2415769Snate@binkert.org    short _flags;
2425769Snate@binkert.org    UNSERIALIZE_SCALAR(_flags);
2437452SLisa.Hsu@amd.com
2447452SLisa.Hsu@amd.com    // Old checkpoints had no concept of the Initialized flag
2457452SLisa.Hsu@amd.com    // so restoring from old checkpoints always fail.
2467452SLisa.Hsu@amd.com    // Events are initialized on construction but original code
2477452SLisa.Hsu@amd.com    // "flags = _flags" would just overwrite the initialization.
2487452SLisa.Hsu@amd.com    // So, read in the checkpoint flags, but then set the Initialized
2497452SLisa.Hsu@amd.com    // flag on top of it in order to avoid failures.
2507451SLisa.Hsu@amd.com    assert(initialized());
2515769Snate@binkert.org    flags = _flags;
2527451SLisa.Hsu@amd.com    flags.set(Initialized);
2535769Snate@binkert.org
2547452SLisa.Hsu@amd.com    // need to see if original event was in a scheduled, unsquashed
2557452SLisa.Hsu@amd.com    // state, but don't want to restore those flags in the current
2567452SLisa.Hsu@amd.com    // object itself (since they aren't immediately true)
2575769Snate@binkert.org    bool wasScheduled = flags.isSet(Scheduled) && !flags.isSet(Squashed);
2585769Snate@binkert.org    flags.clear(Squashed | Scheduled);
259224SN/A
260224SN/A    if (wasScheduled) {
261224SN/A        DPRINTF(Config, "rescheduling at %d\n", _when);
2625695Snate@binkert.org        mainEventQueue.schedule(this, _when);
263224SN/A    }
264224SN/A}
265224SN/A
2662SN/Avoid
267217SN/AEventQueue::serialize(ostream &os)
2682SN/A{
269265SN/A    std::list<Event *> eventPtrs;
270237SN/A
271237SN/A    int numEvents = 0;
2725502Snate@binkert.org    Event *nextBin = head;
2735502Snate@binkert.org    while (nextBin) {
2745503Snate@binkert.org        Event *nextInBin = nextBin;
2755502Snate@binkert.org
2765503Snate@binkert.org        while (nextInBin) {
2775769Snate@binkert.org            if (nextInBin->flags.isSet(Event::AutoSerialize)) {
2785502Snate@binkert.org                eventPtrs.push_back(nextInBin);
2795502Snate@binkert.org                paramOut(os, csprintf("event%d", numEvents++),
2805502Snate@binkert.org                         nextInBin->name());
2815502Snate@binkert.org            }
2825502Snate@binkert.org            nextInBin = nextInBin->nextInBin;
2835503Snate@binkert.org        }
2845502Snate@binkert.org
2855502Snate@binkert.org        nextBin = nextBin->nextBin;
2862SN/A    }
287237SN/A
288265SN/A    SERIALIZE_SCALAR(numEvents);
289265SN/A
2905502Snate@binkert.org    for (std::list<Event *>::iterator it = eventPtrs.begin();
291265SN/A         it != eventPtrs.end(); ++it) {
292265SN/A        (*it)->nameOut(os);
293265SN/A        (*it)->serialize(os);
294265SN/A    }
2952SN/A}
2962SN/A
297237SN/Avoid
298237SN/AEventQueue::unserialize(Checkpoint *cp, const std::string &section)
299237SN/A{
300265SN/A    int numEvents;
301265SN/A    UNSERIALIZE_SCALAR(numEvents);
302265SN/A
303270SN/A    std::string eventName;
304265SN/A    for (int i = 0; i < numEvents; i++) {
305265SN/A        // get the pointer value associated with the event
306270SN/A        paramIn(cp, section, csprintf("event%d", i), eventName);
307265SN/A
308265SN/A        // create the event based on its pointer value
309395SN/A        Serializable::create(cp, eventName);
310237SN/A    }
311237SN/A}
312237SN/A
3132SN/Avoid
3145501Snate@binkert.orgEventQueue::dump() const
3152SN/A{
3162SN/A    cprintf("============================================================\n");
3177823Ssteve.reinhardt@amd.com    cprintf("EventQueue Dump  (cycle %d)\n", curTick());
3182SN/A    cprintf("------------------------------------------------------------\n");
3192SN/A
3202SN/A    if (empty())
3212SN/A        cprintf("<No Events>\n");
3222SN/A    else {
3235502Snate@binkert.org        Event *nextBin = head;
3245502Snate@binkert.org        while (nextBin) {
3255502Snate@binkert.org            Event *nextInBin = nextBin;
3265503Snate@binkert.org            while (nextInBin) {
3275503Snate@binkert.org                nextInBin->dump();
3285502Snate@binkert.org                nextInBin = nextInBin->nextInBin;
3295503Snate@binkert.org            }
3305502Snate@binkert.org
3315502Snate@binkert.org            nextBin = nextBin->nextBin;
3322SN/A        }
3332SN/A    }
3342SN/A
3352SN/A    cprintf("============================================================\n");
3362SN/A}
3372SN/A
3385502Snate@binkert.orgbool
3395502Snate@binkert.orgEventQueue::debugVerify() const
3405502Snate@binkert.org{
3415502Snate@binkert.org    m5::hash_map<long, bool> map;
3425502Snate@binkert.org
3435502Snate@binkert.org    Tick time = 0;
3445502Snate@binkert.org    short priority = 0;
3455502Snate@binkert.org
3465502Snate@binkert.org    Event *nextBin = head;
3475502Snate@binkert.org    while (nextBin) {
3485503Snate@binkert.org        Event *nextInBin = nextBin;
3495503Snate@binkert.org        while (nextInBin) {
3505502Snate@binkert.org            if (nextInBin->when() < time) {
3515502Snate@binkert.org                cprintf("time goes backwards!");
3525502Snate@binkert.org                nextInBin->dump();
3535502Snate@binkert.org                return false;
3545502Snate@binkert.org            } else if (nextInBin->when() == time &&
3555502Snate@binkert.org                       nextInBin->priority() < priority) {
3565502Snate@binkert.org                cprintf("priority inverted!");
3575502Snate@binkert.org                nextInBin->dump();
3585502Snate@binkert.org                return false;
3595502Snate@binkert.org            }
3605502Snate@binkert.org
3615502Snate@binkert.org            if (map[reinterpret_cast<long>(nextInBin)]) {
3625502Snate@binkert.org                cprintf("Node already seen");
3635502Snate@binkert.org                nextInBin->dump();
3645502Snate@binkert.org                return false;
3655502Snate@binkert.org            }
3665502Snate@binkert.org            map[reinterpret_cast<long>(nextInBin)] = true;
3675502Snate@binkert.org
3685502Snate@binkert.org            time = nextInBin->when();
3695502Snate@binkert.org            priority = nextInBin->priority();
3705502Snate@binkert.org
3715502Snate@binkert.org            nextInBin = nextInBin->nextInBin;
3725503Snate@binkert.org        }
3735502Snate@binkert.org
3745502Snate@binkert.org        nextBin = nextBin->nextBin;
3755502Snate@binkert.org    }
3765502Snate@binkert.org
3775502Snate@binkert.org    return true;
3785502Snate@binkert.org}
3795502Snate@binkert.org
3808648Snilay@cs.wisc.eduEvent*
3818648Snilay@cs.wisc.eduEventQueue::replaceHead(Event* s)
3828648Snilay@cs.wisc.edu{
3838648Snilay@cs.wisc.edu    Event* t = head;
3848648Snilay@cs.wisc.edu    head = s;
3858648Snilay@cs.wisc.edu    return t;
3868648Snilay@cs.wisc.edu}
3878648Snilay@cs.wisc.edu
3881019SN/Avoid
3891019SN/AdumpMainQueue()
3901019SN/A{
3911019SN/A    mainEventQueue.dump();
3921019SN/A}
3931019SN/A
3942SN/A
3952SN/Aconst char *
3965336Shines@cs.fsu.eduEvent::description() const
3972SN/A{
3982SN/A    return "generic";
3992SN/A}
4002SN/A
4012SN/Avoid
4022SN/AEvent::trace(const char *action)
4032SN/A{
4042SN/A    // This DPRINTF is unconditional because calls to this function
4052SN/A    // are protected by an 'if (DTRACE(Event))' in the inlined Event
4062SN/A    // methods.
4072SN/A    //
4082SN/A    // This is just a default implementation for derived classes where
4092SN/A    // it's not worth doing anything special.  If you want to put a
4102SN/A    // more informative message in the trace, override this method on
4112SN/A    // the particular subclass where you have the information that
4122SN/A    // needs to be printed.
4132SN/A    DPRINTFN("%s event %s @ %d\n", description(), action, when());
4142SN/A}
4152SN/A
4162SN/Avoid
4175501Snate@binkert.orgEvent::dump() const
4182SN/A{
4195501Snate@binkert.org    cprintf("Event %s (%s)\n", name(), description());
4205769Snate@binkert.org    cprintf("Flags: %#x\n", flags);
4215501Snate@binkert.org#ifdef EVENTQ_DEBUG
4225501Snate@binkert.org    cprintf("Created: %d\n", whenCreated);
4232SN/A#endif
4242SN/A    if (scheduled()) {
4255501Snate@binkert.org#ifdef EVENTQ_DEBUG
4265501Snate@binkert.org        cprintf("Scheduled at  %d\n", whenScheduled);
4272SN/A#endif
4281019SN/A        cprintf("Scheduled for %d, priority %d\n", when(), _priority);
4295501Snate@binkert.org    } else {
4301019SN/A        cprintf("Not Scheduled\n");
4312SN/A    }
4322SN/A}
4337063Snate@binkert.org
4347063Snate@binkert.orgEventQueue::EventQueue(const string &n)
4359356Snilay@cs.wisc.edu    : objName(n), head(NULL), _curTick(0)
4367063Snate@binkert.org{}
437