eventq.cc revision 5502
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 void
61insertBefore(Event *event, Event *curr)
62{
63    // Either way, event will be the last 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
70        // We need to create a new 'in bin' list
71        event->nextInBin = event;
72    } else {
73        // Since we're on the correct list, we need to point to the next list
74        event->nextBin = curr->nextBin;  // curr->nextBin can now become stale
75
76        // Insert event at the end of the 'nextInBin' curr is the last
77        // element on the 'in bin' list and curr->nextInBin is the first
78
79        event->nextInBin = curr->nextInBin; // event->nextInBin needs to
80                                            // point to the first
81        curr->nextInBin = event;     // curr->nextInBin is now second to last
82    }
83}
84
85void
86EventQueue::insert(Event *event)
87{
88    // Deal with the head case
89    if (!head || *event <= *head) {
90        insertBefore(event, head);
91        head = event;
92        return;
93    }
94
95    // Figure out either which 'in bin' list we are on, or where a new list
96    // needs to be inserted
97    Event *curr = head;
98    Event *next = head->nextBin;
99    while (next && *next < *event) {
100        curr = next;
101        next = next->nextBin;
102    }
103
104    insertBefore(event, next);
105    curr->nextBin = event;  // all nextBin pointers on the curr
106                            // 'in bin' list are now stale
107}
108
109inline Event *
110removeItem(Event *event, Event *last)
111{
112    Event *prev = last;
113    Event *curr = last->nextInBin;
114
115    while (event != curr) {
116        if (curr == last)
117            panic("event not found!");
118
119        prev = curr;
120        curr = curr->nextInBin;
121    }
122
123    // If this was the only item in this list, we're done.
124    if (prev == curr)
125        return NULL;
126
127    // remove curr from the 'in bin' list since it's what we're looking for
128    prev->nextInBin = curr->nextInBin;
129
130    // If we didn't remove the last item, we're done
131    if (curr != last)
132        return last;
133
134    // if we removed the last item, the new last item is prev
135    // fix it up since it might be stale and return it
136    prev->nextBin = last->nextBin;
137    return prev;
138}
139
140void
141EventQueue::remove(Event *event)
142{
143    if (head == NULL)
144        panic("event not found!");
145
146    // deal with an event on the head's 'in bin' list (event has the same
147    // time as the head)
148    if (*head == *event) {
149        head = removeItem(event, head);
150        if (!head)
151            head = event->nextBin;
152        return;
153    }
154
155    // Find the 'in bin' list that this event belongs on
156    Event *prev = head;
157    Event *curr = head->nextBin;
158    while (curr && *curr < *event) {
159        prev = curr;
160        curr = curr->nextBin;
161    }
162
163    if (!curr || *curr != *event)
164        panic("event not found!");
165
166    // curr points to the last item of the the correct 'in bin' list, when
167    // we remove an item, it returns the new last item (which may be
168    // unchanged)
169    Event *last = removeItem(event, curr);
170    if (!last) {
171        // The current item was removed, so we need to fix the bin list
172        prev->nextBin = curr->nextBin;
173    } else if (last != curr) {
174        // We have a new last item, so we need to update the bin list
175        prev->nextBin = last;
176    }
177}
178
179Event *
180EventQueue::serviceOne()
181{
182    // grab the first element
183    Event *event = head->nextInBin;
184    event->clearFlags(Event::Scheduled);
185
186    if (head == event) {
187        // this was the only element on the 'in bin' list, so get rid of
188        // the 'in bin' list and point to the next bin list
189        head = event->nextBin;
190    } else {
191        // maintain head->nextInBin as the first element
192        head->nextInBin = event->nextInBin;
193    }
194
195    // handle action
196    if (!event->squashed()) {
197        event->process();
198        if (event->isExitEvent()) {
199            assert(!event->getFlags(Event::AutoDelete)); // would be silly
200            return event;
201        }
202    } else {
203        event->clearFlags(Event::Squashed);
204    }
205
206    if (event->getFlags(Event::AutoDelete) && !event->scheduled())
207        delete event;
208
209    return NULL;
210}
211
212void
213Event::serialize(std::ostream &os)
214{
215    SERIALIZE_SCALAR(_when);
216    SERIALIZE_SCALAR(_priority);
217    SERIALIZE_ENUM(_flags);
218}
219
220void
221Event::unserialize(Checkpoint *cp, const string &section)
222{
223    if (scheduled())
224        deschedule();
225
226    UNSERIALIZE_SCALAR(_when);
227    UNSERIALIZE_SCALAR(_priority);
228
229    // need to see if original event was in a scheduled, unsquashed
230    // state, but don't want to restore those flags in the current
231    // object itself (since they aren't immediately true)
232    UNSERIALIZE_ENUM(_flags);
233    bool wasScheduled = (_flags & Scheduled) && !(_flags & Squashed);
234    _flags &= ~(Squashed | Scheduled);
235
236    if (wasScheduled) {
237        DPRINTF(Config, "rescheduling at %d\n", _when);
238        schedule(_when);
239    }
240}
241
242void
243EventQueue::serialize(ostream &os)
244{
245    std::list<Event *> eventPtrs;
246
247    int numEvents = 0;
248    Event *nextBin = head;
249    while (nextBin) {
250        Event *nextInBin = nextBin->nextInBin;
251
252        do {
253            if (nextInBin->getFlags(Event::AutoSerialize)) {
254                eventPtrs.push_back(nextInBin);
255                paramOut(os, csprintf("event%d", numEvents++),
256                         nextInBin->name());
257            }
258            nextInBin = nextInBin->nextInBin;
259        } while (nextInBin != nextBin);
260
261        nextBin = nextBin->nextBin;
262    }
263
264    SERIALIZE_SCALAR(numEvents);
265
266    for (std::list<Event *>::iterator it = eventPtrs.begin();
267         it != eventPtrs.end(); ++it) {
268        (*it)->nameOut(os);
269        (*it)->serialize(os);
270    }
271}
272
273void
274EventQueue::unserialize(Checkpoint *cp, const std::string &section)
275{
276    int numEvents;
277    UNSERIALIZE_SCALAR(numEvents);
278
279    std::string eventName;
280    for (int i = 0; i < numEvents; i++) {
281        // get the pointer value associated with the event
282        paramIn(cp, section, csprintf("event%d", i), eventName);
283
284        // create the event based on its pointer value
285        Serializable::create(cp, eventName);
286    }
287}
288
289void
290EventQueue::dump() const
291{
292    cprintf("============================================================\n");
293    cprintf("EventQueue Dump  (cycle %d)\n", curTick);
294    cprintf("------------------------------------------------------------\n");
295
296    m5::hash_map<long, bool> map;
297
298    if (empty())
299        cprintf("<No Events>\n");
300    else {
301        Event *nextBin = head;
302        while (nextBin) {
303            Event *nextInBin = nextBin;
304            if (map[reinterpret_cast<long>(nextInBin)])
305                break;
306            map[reinterpret_cast<long>(nextInBin)] = true;
307            do {
308                nextInBin = nextInBin->nextInBin;
309                nextInBin->dump();
310            } while (nextInBin != nextBin);
311
312            nextBin = nextBin->nextBin;
313        }
314    }
315
316    cprintf("============================================================\n");
317}
318
319bool
320EventQueue::debugVerify() const
321{
322    m5::hash_map<long, bool> map;
323
324    Tick time = 0;
325    short priority = 0;
326
327    Event *nextBin = head;
328    while (nextBin) {
329        Event *nextInBin = nextBin->nextInBin;
330        do {
331            if (nextInBin->when() < time) {
332                cprintf("time goes backwards!");
333                nextInBin->dump();
334                return false;
335            } else if (nextInBin->when() == time &&
336                       nextInBin->priority() < priority) {
337                cprintf("priority inverted!");
338                nextInBin->dump();
339                return false;
340            }
341
342            if (map[reinterpret_cast<long>(nextInBin)]) {
343                cprintf("Node already seen");
344                nextInBin->dump();
345                return false;
346            }
347            map[reinterpret_cast<long>(nextInBin)] = true;
348
349            time = nextInBin->when();
350            priority = nextInBin->priority();
351
352            nextInBin = nextInBin->nextInBin;
353        } while (nextInBin != nextBin);
354
355        nextBin = nextBin->nextBin;
356    }
357
358    return true;
359}
360
361void
362dumpMainQueue()
363{
364    mainEventQueue.dump();
365}
366
367
368const char *
369Event::description() const
370{
371    return "generic";
372}
373
374void
375Event::trace(const char *action)
376{
377    // This DPRINTF is unconditional because calls to this function
378    // are protected by an 'if (DTRACE(Event))' in the inlined Event
379    // methods.
380    //
381    // This is just a default implementation for derived classes where
382    // it's not worth doing anything special.  If you want to put a
383    // more informative message in the trace, override this method on
384    // the particular subclass where you have the information that
385    // needs to be printed.
386    DPRINTFN("%s event %s @ %d\n", description(), action, when());
387}
388
389void
390Event::dump() const
391{
392    cprintf("Event %s (%s)\n", name(), description());
393    cprintf("Flags: %#x\n", _flags);
394#ifdef EVENTQ_DEBUG
395    cprintf("Created: %d\n", whenCreated);
396#endif
397    if (scheduled()) {
398#ifdef EVENTQ_DEBUG
399        cprintf("Scheduled at  %d\n", whenScheduled);
400#endif
401        cprintf("Scheduled for %d, priority %d\n", when(), _priority);
402    } else {
403        cprintf("Not Scheduled\n");
404    }
405}
406