eventq.cc revision 5503:cf464d02bc57
1/*
2 * Copyright (c) 2000-2005 The Regents of The University of Michigan
3 * Copyright (c) 2008 The Hewlett-Packard Development Company
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Authors: Steve Reinhardt
30 *          Nathan Binkert
31 *          Steve Raasch
32 */
33
34#include <cassert>
35#include <iostream>
36#include <string>
37#include <vector>
38
39#include "base/hashmap.hh"
40#include "base/misc.hh"
41#include "base/trace.hh"
42#include "cpu/smt.hh"
43#include "sim/core.hh"
44#include "sim/eventq.hh"
45
46using namespace std;
47
48//
49// Main Event Queue
50//
51// Events on this queue are processed at the *beginning* of each
52// cycle, before the pipeline simulation is performed.
53//
54EventQueue mainEventQueue("MainEventQueue");
55
56#ifndef NDEBUG
57Counter Event::instanceCounter = 0;
58#endif
59
60inline Event *
61insertBefore(Event *event, Event *curr)
62{
63    // Either way, event will be the top element in the 'in bin' list
64    // which is the pointer we need in order to look into the list, so
65    // we need to insert that into the bin list.
66    if (!curr || *event < *curr) {
67        // Insert the event before the current list since it is in the future.
68        event->nextBin = curr;
69        event->nextInBin = NULL;
70    } else {
71        // Since we're on the correct list, we need to point to the next list
72        event->nextBin = curr->nextBin;  // curr->nextBin can now become stale
73
74        // Insert event at the top of the stack
75        event->nextInBin = curr;
76    }
77
78    return event;
79}
80
81void
82EventQueue::insert(Event *event)
83{
84    // Deal with the head case
85    if (!head || *event <= *head) {
86        head = insertBefore(event, head);
87        return;
88    }
89
90    // Figure out either which 'in bin' list we are on, or where a new list
91    // needs to be inserted
92    Event *prev = head;
93    Event *curr = head->nextBin;
94    while (curr && *curr < *event) {
95        prev = curr;
96        curr = curr->nextBin;
97    }
98
99    // Note: this operation may render all nextBin pointers on the
100    // prev 'in bin' list stale (except for the top one)
101    prev->nextBin = insertBefore(event, curr);
102}
103
104inline Event *
105removeItem(Event *event, Event *top)
106{
107    Event *curr = top;
108    Event *next = top->nextInBin;
109
110    // if we removed the top item, we need to handle things specially
111    // and just remove the top item, fixing up the next bin pointer of
112    // the new top item
113    if (event == top) {
114        if (!next)
115            return top->nextBin;
116        next->nextBin = top->nextBin;
117        return next;
118    }
119
120    // Since we already checked the current element, we're going to
121    // keep checking event against the next element.
122    while (event != next) {
123        if (!next)
124            panic("event not found!");
125
126        curr = next;
127        next = next->nextInBin;
128    }
129
130    // remove next from the 'in bin' list since it's what we're looking for
131    curr->nextInBin = next->nextInBin;
132    return top;
133}
134
135void
136EventQueue::remove(Event *event)
137{
138    if (head == NULL)
139        panic("event not found!");
140
141    // deal with an event on the head's 'in bin' list (event has the same
142    // time as the head)
143    if (*head == *event) {
144        head = removeItem(event, head);
145        return;
146    }
147
148    // Find the 'in bin' list that this event belongs on
149    Event *prev = head;
150    Event *curr = head->nextBin;
151    while (curr && *curr < *event) {
152        prev = curr;
153        curr = curr->nextBin;
154    }
155
156    if (!curr || *curr != *event)
157        panic("event not found!");
158
159    // curr points to the top item of the the correct 'in bin' list, when
160    // we remove an item, it returns the new top item (which may be
161    // unchanged)
162    prev->nextBin = removeItem(event, curr);
163}
164
165Event *
166EventQueue::serviceOne()
167{
168    Event *event = head;
169    Event *next = head->nextInBin;
170    event->clearFlags(Event::Scheduled);
171
172    if (next) {
173        // update the next bin pointer since it could be stale
174        next->nextBin = head->nextBin;
175
176        // pop the stack
177        head = next;
178    } else {
179        // this was the only element on the 'in bin' list, so get rid of
180        // the 'in bin' list and point to the next bin list
181        head = head->nextBin;
182    }
183
184    // handle action
185    if (!event->squashed()) {
186        event->process();
187        if (event->isExitEvent()) {
188            assert(!event->getFlags(Event::AutoDelete)); // would be silly
189            return event;
190        }
191    } else {
192        event->clearFlags(Event::Squashed);
193    }
194
195    if (event->getFlags(Event::AutoDelete) && !event->scheduled())
196        delete event;
197
198    return NULL;
199}
200
201void
202Event::serialize(std::ostream &os)
203{
204    SERIALIZE_SCALAR(_when);
205    SERIALIZE_SCALAR(_priority);
206    SERIALIZE_ENUM(_flags);
207}
208
209void
210Event::unserialize(Checkpoint *cp, const string &section)
211{
212    if (scheduled())
213        deschedule();
214
215    UNSERIALIZE_SCALAR(_when);
216    UNSERIALIZE_SCALAR(_priority);
217
218    // need to see if original event was in a scheduled, unsquashed
219    // state, but don't want to restore those flags in the current
220    // object itself (since they aren't immediately true)
221    UNSERIALIZE_ENUM(_flags);
222    bool wasScheduled = (_flags & Scheduled) && !(_flags & Squashed);
223    _flags &= ~(Squashed | Scheduled);
224
225    if (wasScheduled) {
226        DPRINTF(Config, "rescheduling at %d\n", _when);
227        schedule(_when);
228    }
229}
230
231void
232EventQueue::serialize(ostream &os)
233{
234    std::list<Event *> eventPtrs;
235
236    int numEvents = 0;
237    Event *nextBin = head;
238    while (nextBin) {
239        Event *nextInBin = nextBin;
240
241        while (nextInBin) {
242            if (nextInBin->getFlags(Event::AutoSerialize)) {
243                eventPtrs.push_back(nextInBin);
244                paramOut(os, csprintf("event%d", numEvents++),
245                         nextInBin->name());
246            }
247            nextInBin = nextInBin->nextInBin;
248        }
249
250        nextBin = nextBin->nextBin;
251    }
252
253    SERIALIZE_SCALAR(numEvents);
254
255    for (std::list<Event *>::iterator it = eventPtrs.begin();
256         it != eventPtrs.end(); ++it) {
257        (*it)->nameOut(os);
258        (*it)->serialize(os);
259    }
260}
261
262void
263EventQueue::unserialize(Checkpoint *cp, const std::string &section)
264{
265    int numEvents;
266    UNSERIALIZE_SCALAR(numEvents);
267
268    std::string eventName;
269    for (int i = 0; i < numEvents; i++) {
270        // get the pointer value associated with the event
271        paramIn(cp, section, csprintf("event%d", i), eventName);
272
273        // create the event based on its pointer value
274        Serializable::create(cp, eventName);
275    }
276}
277
278void
279EventQueue::dump() const
280{
281    cprintf("============================================================\n");
282    cprintf("EventQueue Dump  (cycle %d)\n", curTick);
283    cprintf("------------------------------------------------------------\n");
284
285    if (empty())
286        cprintf("<No Events>\n");
287    else {
288        Event *nextBin = head;
289        while (nextBin) {
290            Event *nextInBin = nextBin;
291            while (nextInBin) {
292                nextInBin->dump();
293                nextInBin = nextInBin->nextInBin;
294            }
295
296            nextBin = nextBin->nextBin;
297        }
298    }
299
300    cprintf("============================================================\n");
301}
302
303bool
304EventQueue::debugVerify() const
305{
306    m5::hash_map<long, bool> map;
307
308    Tick time = 0;
309    short priority = 0;
310
311    Event *nextBin = head;
312    while (nextBin) {
313        Event *nextInBin = nextBin;
314        while (nextInBin) {
315            if (nextInBin->when() < time) {
316                cprintf("time goes backwards!");
317                nextInBin->dump();
318                return false;
319            } else if (nextInBin->when() == time &&
320                       nextInBin->priority() < priority) {
321                cprintf("priority inverted!");
322                nextInBin->dump();
323                return false;
324            }
325
326            if (map[reinterpret_cast<long>(nextInBin)]) {
327                cprintf("Node already seen");
328                nextInBin->dump();
329                return false;
330            }
331            map[reinterpret_cast<long>(nextInBin)] = true;
332
333            time = nextInBin->when();
334            priority = nextInBin->priority();
335
336            nextInBin = nextInBin->nextInBin;
337        }
338
339        nextBin = nextBin->nextBin;
340    }
341
342    return true;
343}
344
345void
346dumpMainQueue()
347{
348    mainEventQueue.dump();
349}
350
351
352const char *
353Event::description() const
354{
355    return "generic";
356}
357
358void
359Event::trace(const char *action)
360{
361    // This DPRINTF is unconditional because calls to this function
362    // are protected by an 'if (DTRACE(Event))' in the inlined Event
363    // methods.
364    //
365    // This is just a default implementation for derived classes where
366    // it's not worth doing anything special.  If you want to put a
367    // more informative message in the trace, override this method on
368    // the particular subclass where you have the information that
369    // needs to be printed.
370    DPRINTFN("%s event %s @ %d\n", description(), action, when());
371}
372
373void
374Event::dump() const
375{
376    cprintf("Event %s (%s)\n", name(), description());
377    cprintf("Flags: %#x\n", _flags);
378#ifdef EVENTQ_DEBUG
379    cprintf("Created: %d\n", whenCreated);
380#endif
381    if (scheduled()) {
382#ifdef EVENTQ_DEBUG
383        cprintf("Scheduled at  %d\n", whenScheduled);
384#endif
385        cprintf("Scheduled for %d, priority %d\n", when(), _priority);
386    } else {
387        cprintf("Not Scheduled\n");
388    }
389}
390