eventq.cc revision 5502
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"
435501Snate@binkert.org#include "sim/core.hh"
4456SN/A#include "sim/eventq.hh"
452SN/A
462SN/Ausing namespace std;
472SN/A
482SN/A//
492SN/A// Main Event Queue
502SN/A//
512SN/A// Events on this queue are processed at the *beginning* of each
522SN/A// cycle, before the pipeline simulation is performed.
532SN/A//
54221SN/AEventQueue mainEventQueue("MainEventQueue");
552SN/A
564017Sstever@eecs.umich.edu#ifndef NDEBUG
574016Sstever@eecs.umich.eduCounter Event::instanceCounter = 0;
584017Sstever@eecs.umich.edu#endif
594016Sstever@eecs.umich.edu
605502Snate@binkert.orginline void
615502Snate@binkert.orginsertBefore(Event *event, Event *curr)
625502Snate@binkert.org{
635502Snate@binkert.org    // Either way, event will be the last element in the 'in bin' list
645502Snate@binkert.org    // which is the pointer we need in order to look into the list, so
655502Snate@binkert.org    // we need to insert that into the bin list.
665502Snate@binkert.org    if (!curr || *event < *curr) {
675502Snate@binkert.org        // Insert the event before the current list since it is in the future.
685502Snate@binkert.org        event->nextBin = curr;
695502Snate@binkert.org
705502Snate@binkert.org        // We need to create a new 'in bin' list
715502Snate@binkert.org        event->nextInBin = event;
725502Snate@binkert.org    } else {
735502Snate@binkert.org        // Since we're on the correct list, we need to point to the next list
745502Snate@binkert.org        event->nextBin = curr->nextBin;  // curr->nextBin can now become stale
755502Snate@binkert.org
765502Snate@binkert.org        // Insert event at the end of the 'nextInBin' curr is the last
775502Snate@binkert.org        // element on the 'in bin' list and curr->nextInBin is the first
785502Snate@binkert.org
795502Snate@binkert.org        event->nextInBin = curr->nextInBin; // event->nextInBin needs to
805502Snate@binkert.org                                            // point to the first
815502Snate@binkert.org        curr->nextInBin = event;     // curr->nextInBin is now second to last
825502Snate@binkert.org    }
835502Snate@binkert.org}
845502Snate@binkert.org
852SN/Avoid
862SN/AEventQueue::insert(Event *event)
872SN/A{
885502Snate@binkert.org    // Deal with the head case
895502Snate@binkert.org    if (!head || *event <= *head) {
905502Snate@binkert.org        insertBefore(event, head);
912SN/A        head = event;
925502Snate@binkert.org        return;
935502Snate@binkert.org    }
942SN/A
955502Snate@binkert.org    // Figure out either which 'in bin' list we are on, or where a new list
965502Snate@binkert.org    // needs to be inserted
975502Snate@binkert.org    Event *curr = head;
985502Snate@binkert.org    Event *next = head->nextBin;
995502Snate@binkert.org    while (next && *next < *event) {
1005502Snate@binkert.org        curr = next;
1015502Snate@binkert.org        next = next->nextBin;
1025502Snate@binkert.org    }
1032SN/A
1045502Snate@binkert.org    insertBefore(event, next);
1055502Snate@binkert.org    curr->nextBin = event;  // all nextBin pointers on the curr
1065502Snate@binkert.org                            // 'in bin' list are now stale
1075502Snate@binkert.org}
1082SN/A
1095502Snate@binkert.orginline Event *
1105502Snate@binkert.orgremoveItem(Event *event, Event *last)
1115502Snate@binkert.org{
1125502Snate@binkert.org    Event *prev = last;
1135502Snate@binkert.org    Event *curr = last->nextInBin;
1145502Snate@binkert.org
1155502Snate@binkert.org    while (event != curr) {
1165502Snate@binkert.org        if (curr == last)
1175502Snate@binkert.org            panic("event not found!");
1185502Snate@binkert.org
1195502Snate@binkert.org        prev = curr;
1205502Snate@binkert.org        curr = curr->nextInBin;
1212SN/A    }
1225502Snate@binkert.org
1235502Snate@binkert.org    // If this was the only item in this list, we're done.
1245502Snate@binkert.org    if (prev == curr)
1255502Snate@binkert.org        return NULL;
1265502Snate@binkert.org
1275502Snate@binkert.org    // remove curr from the 'in bin' list since it's what we're looking for
1285502Snate@binkert.org    prev->nextInBin = curr->nextInBin;
1295502Snate@binkert.org
1305502Snate@binkert.org    // If we didn't remove the last item, we're done
1315502Snate@binkert.org    if (curr != last)
1325502Snate@binkert.org        return last;
1335502Snate@binkert.org
1345502Snate@binkert.org    // if we removed the last item, the new last item is prev
1355502Snate@binkert.org    // fix it up since it might be stale and return it
1365502Snate@binkert.org    prev->nextBin = last->nextBin;
1375502Snate@binkert.org    return prev;
1382SN/A}
1392SN/A
1402SN/Avoid
1412SN/AEventQueue::remove(Event *event)
1422SN/A{
1432SN/A    if (head == NULL)
1445502Snate@binkert.org        panic("event not found!");
1452SN/A
1465502Snate@binkert.org    // deal with an event on the head's 'in bin' list (event has the same
1475502Snate@binkert.org    // time as the head)
1485502Snate@binkert.org    if (*head == *event) {
1495502Snate@binkert.org        head = removeItem(event, head);
1505502Snate@binkert.org        if (!head)
1515502Snate@binkert.org            head = event->nextBin;
1522SN/A        return;
1532SN/A    }
1542SN/A
1555502Snate@binkert.org    // Find the 'in bin' list that this event belongs on
1562SN/A    Event *prev = head;
1575502Snate@binkert.org    Event *curr = head->nextBin;
1585502Snate@binkert.org    while (curr && *curr < *event) {
1592SN/A        prev = curr;
1605502Snate@binkert.org        curr = curr->nextBin;
1612SN/A    }
1622SN/A
1635502Snate@binkert.org    if (!curr || *curr != *event)
1645502Snate@binkert.org        panic("event not found!");
1655502Snate@binkert.org
1665502Snate@binkert.org    // curr points to the last item of the the correct 'in bin' list, when
1675502Snate@binkert.org    // we remove an item, it returns the new last item (which may be
1685502Snate@binkert.org    // unchanged)
1695502Snate@binkert.org    Event *last = removeItem(event, curr);
1705502Snate@binkert.org    if (!last) {
1715502Snate@binkert.org        // The current item was removed, so we need to fix the bin list
1725502Snate@binkert.org        prev->nextBin = curr->nextBin;
1735502Snate@binkert.org    } else if (last != curr) {
1745502Snate@binkert.org        // We have a new last item, so we need to update the bin list
1755502Snate@binkert.org        prev->nextBin = last;
1765502Snate@binkert.org    }
1772SN/A}
1782SN/A
1792667Sstever@eecs.umich.eduEvent *
1802SN/AEventQueue::serviceOne()
1812SN/A{
1825502Snate@binkert.org    // grab the first element
1835502Snate@binkert.org    Event *event = head->nextInBin;
1842SN/A    event->clearFlags(Event::Scheduled);
1855502Snate@binkert.org
1865502Snate@binkert.org    if (head == event) {
1875502Snate@binkert.org        // this was the only element on the 'in bin' list, so get rid of
1885502Snate@binkert.org        // the 'in bin' list and point to the next bin list
1895502Snate@binkert.org        head = event->nextBin;
1905502Snate@binkert.org    } else {
1915502Snate@binkert.org        // maintain head->nextInBin as the first element
1925502Snate@binkert.org        head->nextInBin = event->nextInBin;
1935502Snate@binkert.org    }
1942SN/A
1952SN/A    // handle action
1962667Sstever@eecs.umich.edu    if (!event->squashed()) {
1972SN/A        event->process();
1982667Sstever@eecs.umich.edu        if (event->isExitEvent()) {
1992667Sstever@eecs.umich.edu            assert(!event->getFlags(Event::AutoDelete)); // would be silly
2002667Sstever@eecs.umich.edu            return event;
2012667Sstever@eecs.umich.edu        }
2022667Sstever@eecs.umich.edu    } else {
2032SN/A        event->clearFlags(Event::Squashed);
2042667Sstever@eecs.umich.edu    }
2052SN/A
206294SN/A    if (event->getFlags(Event::AutoDelete) && !event->scheduled())
2072SN/A        delete event;
2082667Sstever@eecs.umich.edu
2092667Sstever@eecs.umich.edu    return NULL;
2102SN/A}
2112SN/A
212224SN/Avoid
213224SN/AEvent::serialize(std::ostream &os)
214224SN/A{
215224SN/A    SERIALIZE_SCALAR(_when);
216224SN/A    SERIALIZE_SCALAR(_priority);
217224SN/A    SERIALIZE_ENUM(_flags);
218224SN/A}
219224SN/A
220224SN/Avoid
221237SN/AEvent::unserialize(Checkpoint *cp, const string &section)
222224SN/A{
223224SN/A    if (scheduled())
224224SN/A        deschedule();
225224SN/A
226224SN/A    UNSERIALIZE_SCALAR(_when);
227224SN/A    UNSERIALIZE_SCALAR(_priority);
228224SN/A
229224SN/A    // need to see if original event was in a scheduled, unsquashed
230224SN/A    // state, but don't want to restore those flags in the current
231224SN/A    // object itself (since they aren't immediately true)
232224SN/A    UNSERIALIZE_ENUM(_flags);
233224SN/A    bool wasScheduled = (_flags & Scheduled) && !(_flags & Squashed);
234224SN/A    _flags &= ~(Squashed | Scheduled);
235224SN/A
236224SN/A    if (wasScheduled) {
237224SN/A        DPRINTF(Config, "rescheduling at %d\n", _when);
238224SN/A        schedule(_when);
239224SN/A    }
240224SN/A}
241224SN/A
2422SN/Avoid
243217SN/AEventQueue::serialize(ostream &os)
2442SN/A{
245265SN/A    std::list<Event *> eventPtrs;
246237SN/A
247237SN/A    int numEvents = 0;
2485502Snate@binkert.org    Event *nextBin = head;
2495502Snate@binkert.org    while (nextBin) {
2505502Snate@binkert.org        Event *nextInBin = nextBin->nextInBin;
2515502Snate@binkert.org
2525502Snate@binkert.org        do {
2535502Snate@binkert.org            if (nextInBin->getFlags(Event::AutoSerialize)) {
2545502Snate@binkert.org                eventPtrs.push_back(nextInBin);
2555502Snate@binkert.org                paramOut(os, csprintf("event%d", numEvents++),
2565502Snate@binkert.org                         nextInBin->name());
2575502Snate@binkert.org            }
2585502Snate@binkert.org            nextInBin = nextInBin->nextInBin;
2595502Snate@binkert.org        } while (nextInBin != nextBin);
2605502Snate@binkert.org
2615502Snate@binkert.org        nextBin = nextBin->nextBin;
2622SN/A    }
263237SN/A
264265SN/A    SERIALIZE_SCALAR(numEvents);
265265SN/A
2665502Snate@binkert.org    for (std::list<Event *>::iterator it = eventPtrs.begin();
267265SN/A         it != eventPtrs.end(); ++it) {
268265SN/A        (*it)->nameOut(os);
269265SN/A        (*it)->serialize(os);
270265SN/A    }
2712SN/A}
2722SN/A
273237SN/Avoid
274237SN/AEventQueue::unserialize(Checkpoint *cp, const std::string &section)
275237SN/A{
276265SN/A    int numEvents;
277265SN/A    UNSERIALIZE_SCALAR(numEvents);
278265SN/A
279270SN/A    std::string eventName;
280265SN/A    for (int i = 0; i < numEvents; i++) {
281265SN/A        // get the pointer value associated with the event
282270SN/A        paramIn(cp, section, csprintf("event%d", i), eventName);
283265SN/A
284265SN/A        // create the event based on its pointer value
285395SN/A        Serializable::create(cp, eventName);
286237SN/A    }
287237SN/A}
288237SN/A
2892SN/Avoid
2905501Snate@binkert.orgEventQueue::dump() const
2912SN/A{
2922SN/A    cprintf("============================================================\n");
2932SN/A    cprintf("EventQueue Dump  (cycle %d)\n", curTick);
2942SN/A    cprintf("------------------------------------------------------------\n");
2952SN/A
2965502Snate@binkert.org    m5::hash_map<long, bool> map;
2975502Snate@binkert.org
2982SN/A    if (empty())
2992SN/A        cprintf("<No Events>\n");
3002SN/A    else {
3015502Snate@binkert.org        Event *nextBin = head;
3025502Snate@binkert.org        while (nextBin) {
3035502Snate@binkert.org            Event *nextInBin = nextBin;
3045502Snate@binkert.org            if (map[reinterpret_cast<long>(nextInBin)])
3055502Snate@binkert.org                break;
3065502Snate@binkert.org            map[reinterpret_cast<long>(nextInBin)] = true;
3075502Snate@binkert.org            do {
3085502Snate@binkert.org                nextInBin = nextInBin->nextInBin;
3095502Snate@binkert.org                nextInBin->dump();
3105502Snate@binkert.org            } while (nextInBin != nextBin);
3115502Snate@binkert.org
3125502Snate@binkert.org            nextBin = nextBin->nextBin;
3132SN/A        }
3142SN/A    }
3152SN/A
3162SN/A    cprintf("============================================================\n");
3172SN/A}
3182SN/A
3195502Snate@binkert.orgbool
3205502Snate@binkert.orgEventQueue::debugVerify() const
3215502Snate@binkert.org{
3225502Snate@binkert.org    m5::hash_map<long, bool> map;
3235502Snate@binkert.org
3245502Snate@binkert.org    Tick time = 0;
3255502Snate@binkert.org    short priority = 0;
3265502Snate@binkert.org
3275502Snate@binkert.org    Event *nextBin = head;
3285502Snate@binkert.org    while (nextBin) {
3295502Snate@binkert.org        Event *nextInBin = nextBin->nextInBin;
3305502Snate@binkert.org        do {
3315502Snate@binkert.org            if (nextInBin->when() < time) {
3325502Snate@binkert.org                cprintf("time goes backwards!");
3335502Snate@binkert.org                nextInBin->dump();
3345502Snate@binkert.org                return false;
3355502Snate@binkert.org            } else if (nextInBin->when() == time &&
3365502Snate@binkert.org                       nextInBin->priority() < priority) {
3375502Snate@binkert.org                cprintf("priority inverted!");
3385502Snate@binkert.org                nextInBin->dump();
3395502Snate@binkert.org                return false;
3405502Snate@binkert.org            }
3415502Snate@binkert.org
3425502Snate@binkert.org            if (map[reinterpret_cast<long>(nextInBin)]) {
3435502Snate@binkert.org                cprintf("Node already seen");
3445502Snate@binkert.org                nextInBin->dump();
3455502Snate@binkert.org                return false;
3465502Snate@binkert.org            }
3475502Snate@binkert.org            map[reinterpret_cast<long>(nextInBin)] = true;
3485502Snate@binkert.org
3495502Snate@binkert.org            time = nextInBin->when();
3505502Snate@binkert.org            priority = nextInBin->priority();
3515502Snate@binkert.org
3525502Snate@binkert.org            nextInBin = nextInBin->nextInBin;
3535502Snate@binkert.org        } while (nextInBin != nextBin);
3545502Snate@binkert.org
3555502Snate@binkert.org        nextBin = nextBin->nextBin;
3565502Snate@binkert.org    }
3575502Snate@binkert.org
3585502Snate@binkert.org    return true;
3595502Snate@binkert.org}
3605502Snate@binkert.org
3611019SN/Avoid
3621019SN/AdumpMainQueue()
3631019SN/A{
3641019SN/A    mainEventQueue.dump();
3651019SN/A}
3661019SN/A
3672SN/A
3682SN/Aconst char *
3695336Shines@cs.fsu.eduEvent::description() const
3702SN/A{
3712SN/A    return "generic";
3722SN/A}
3732SN/A
3742SN/Avoid
3752SN/AEvent::trace(const char *action)
3762SN/A{
3772SN/A    // This DPRINTF is unconditional because calls to this function
3782SN/A    // are protected by an 'if (DTRACE(Event))' in the inlined Event
3792SN/A    // methods.
3802SN/A    //
3812SN/A    // This is just a default implementation for derived classes where
3822SN/A    // it's not worth doing anything special.  If you want to put a
3832SN/A    // more informative message in the trace, override this method on
3842SN/A    // the particular subclass where you have the information that
3852SN/A    // needs to be printed.
3862SN/A    DPRINTFN("%s event %s @ %d\n", description(), action, when());
3872SN/A}
3882SN/A
3892SN/Avoid
3905501Snate@binkert.orgEvent::dump() const
3912SN/A{
3925501Snate@binkert.org    cprintf("Event %s (%s)\n", name(), description());
3931019SN/A    cprintf("Flags: %#x\n", _flags);
3945501Snate@binkert.org#ifdef EVENTQ_DEBUG
3955501Snate@binkert.org    cprintf("Created: %d\n", whenCreated);
3962SN/A#endif
3972SN/A    if (scheduled()) {
3985501Snate@binkert.org#ifdef EVENTQ_DEBUG
3995501Snate@binkert.org        cprintf("Scheduled at  %d\n", whenScheduled);
4002SN/A#endif
4011019SN/A        cprintf("Scheduled for %d, priority %d\n", when(), _priority);
4025501Snate@binkert.org    } else {
4031019SN/A        cprintf("Not Scheduled\n");
4042SN/A    }
4052SN/A}
406