eventq: Clean up the Event class so that it uses fewer bytes. This
will hopefullly allow it to fit in a cache line.
This commit is contained in:
parent
7a83c50a59
commit
93517dd90c
|
@ -30,18 +30,16 @@
|
|||
* Steve Raasch
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cpu/smt.hh"
|
||||
#include "base/misc.hh"
|
||||
|
||||
#include "sim/eventq.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "cpu/smt.hh"
|
||||
#include "sim/core.hh"
|
||||
#include "sim/eventq.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -203,7 +201,7 @@ EventQueue::unserialize(Checkpoint *cp, const std::string §ion)
|
|||
}
|
||||
|
||||
void
|
||||
EventQueue::dump()
|
||||
EventQueue::dump() const
|
||||
{
|
||||
cprintf("============================================================\n");
|
||||
cprintf("EventQueue Dump (cycle %d)\n", curTick);
|
||||
|
@ -235,7 +233,6 @@ Event::description() const
|
|||
return "generic";
|
||||
}
|
||||
|
||||
#if TRACING_ON
|
||||
void
|
||||
Event::trace(const char *action)
|
||||
{
|
||||
|
@ -250,23 +247,21 @@ Event::trace(const char *action)
|
|||
// needs to be printed.
|
||||
DPRINTFN("%s event %s @ %d\n", description(), action, when());
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
Event::dump()
|
||||
Event::dump() const
|
||||
{
|
||||
cprintf("Event (%s)\n", description());
|
||||
cprintf("Event %s (%s)\n", name(), description());
|
||||
cprintf("Flags: %#x\n", _flags);
|
||||
#if TRACING_ON
|
||||
cprintf("Created: %d\n", when_created);
|
||||
#ifdef EVENTQ_DEBUG
|
||||
cprintf("Created: %d\n", whenCreated);
|
||||
#endif
|
||||
if (scheduled()) {
|
||||
#if TRACING_ON
|
||||
cprintf("Scheduled at %d\n", when_scheduled);
|
||||
#ifdef EVENTQ_DEBUG
|
||||
cprintf("Scheduled at %d\n", whenScheduled);
|
||||
#endif
|
||||
cprintf("Scheduled for %d, priority %d\n", when(), _priority);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
cprintf("Not Scheduled\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,19 +36,17 @@
|
|||
#ifndef __SIM_EVENTQ_HH__
|
||||
#define __SIM_EVENTQ_HH__
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "sim/host.hh" // for Tick
|
||||
|
||||
#include "base/fast_alloc.hh"
|
||||
#include "base/misc.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "sim/serialize.hh"
|
||||
#include "sim/host.hh"
|
||||
|
||||
class EventQueue; // forward declaration
|
||||
|
||||
|
@ -64,17 +62,27 @@ class EventQueue; // forward declaration
|
|||
//////////////////////
|
||||
extern EventQueue mainEventQueue;
|
||||
|
||||
|
||||
/*
|
||||
* An item on an event queue. The action caused by a given
|
||||
* event is specified by deriving a subclass and overriding the
|
||||
* process() member function.
|
||||
*
|
||||
* Caution, the order of members is chosen to maximize data packing.
|
||||
*/
|
||||
class Event : public Serializable, public FastAlloc
|
||||
{
|
||||
friend class EventQueue;
|
||||
|
||||
private:
|
||||
Event *next;
|
||||
|
||||
/// queue to which this event belongs (though it may or may not be
|
||||
/// scheduled on this queue yet)
|
||||
EventQueue *_queue;
|
||||
|
||||
Tick _when; //!< timestamp when event should be processed
|
||||
short _priority; //!< event priority
|
||||
short _flags;
|
||||
|
||||
#ifndef NDEBUG
|
||||
/// Global counter to generate unique IDs for Event instances
|
||||
|
@ -84,19 +92,13 @@ class Event : public Serializable, public FastAlloc
|
|||
/// this but they're not consistent across runs making debugging
|
||||
/// more difficult. Thus we use a global counter value when
|
||||
/// debugging.
|
||||
Counter instanceId;
|
||||
#endif // NDEBUG
|
||||
|
||||
/// queue to which this event belongs (though it may or may not be
|
||||
/// scheduled on this queue yet)
|
||||
EventQueue *queue;
|
||||
|
||||
Event *next;
|
||||
|
||||
Tick _when; //!< timestamp when event should be processed
|
||||
int _priority; //!< event priority
|
||||
char _flags;
|
||||
Counter instance;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_EVENTQ
|
||||
Tick whenCreated; //!< time created
|
||||
Tick whenScheduled; //!< time scheduled
|
||||
#endif
|
||||
protected:
|
||||
enum Flags {
|
||||
None = 0x0,
|
||||
|
@ -112,26 +114,20 @@ class Event : public Serializable, public FastAlloc
|
|||
void clearFlags(Flags f) { _flags &= ~f; }
|
||||
|
||||
protected:
|
||||
EventQueue *theQueue() const { return queue; }
|
||||
|
||||
#if TRACING_ON
|
||||
Tick when_created; //!< Keep track of creation time For debugging
|
||||
Tick when_scheduled; //!< Keep track of creation time For debugging
|
||||
EventQueue *queue() const { return _queue; }
|
||||
|
||||
// This function isn't really useful if TRACING_ON is not defined
|
||||
virtual void trace(const char *action); //!< trace event activity
|
||||
#else
|
||||
void trace(const char *) {}
|
||||
#endif
|
||||
|
||||
unsigned annotated_value;
|
||||
|
||||
public:
|
||||
|
||||
/// Event priorities, to provide tie-breakers for events scheduled
|
||||
/// at the same cycle. Most events are scheduled at the default
|
||||
/// priority; these values are used to control events that need to
|
||||
/// be ordered within a cycle.
|
||||
enum Priority {
|
||||
/// Minimum priority
|
||||
Minimum_Pri = SHRT_MIN,
|
||||
|
||||
/// If we enable tracing on a particular cycle, do that as the
|
||||
/// very first thing so we don't miss any of the events on
|
||||
/// that cycle (even if we enter the debugger).
|
||||
|
@ -174,7 +170,10 @@ class Event : public Serializable, public FastAlloc
|
|||
|
||||
/// If we want to exit on this cycle, it's the very last thing
|
||||
/// we do.
|
||||
Sim_Exit_Pri = 100
|
||||
Sim_Exit_Pri = 100,
|
||||
|
||||
/// Maximum priority
|
||||
Maximum_Pri = SHRT_MAX
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -182,27 +181,53 @@ class Event : public Serializable, public FastAlloc
|
|||
* @param queue that the event gets scheduled on
|
||||
*/
|
||||
Event(EventQueue *q, Priority p = Default_Pri)
|
||||
: queue(q), next(NULL), _priority(p), _flags(None),
|
||||
#if TRACING_ON
|
||||
when_created(curTick), when_scheduled(0),
|
||||
#endif
|
||||
annotated_value(0)
|
||||
: next(NULL), _queue(q), _priority(p), _flags(None)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
instanceId = ++instanceCounter;
|
||||
instance = ++instanceCounter;
|
||||
#endif
|
||||
#ifdef EVENTQ_DEBUG
|
||||
whenCreated = curTick;
|
||||
whenScheduled = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
~Event() {}
|
||||
virtual
|
||||
~Event()
|
||||
{
|
||||
}
|
||||
|
||||
virtual const std::string name() const {
|
||||
virtual const std::string
|
||||
name() const
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
return csprintf("Event_%d", instanceId);
|
||||
return csprintf("Event_%d", instance);
|
||||
#else
|
||||
return csprintf("Event_%x", (uintptr_t)this);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Return a C string describing the event. This string should
|
||||
/// *not* be dynamically allocated; just a const char array
|
||||
/// describing the event class.
|
||||
virtual const char *description() const;
|
||||
|
||||
/// Dump the current event data
|
||||
void dump() const;
|
||||
|
||||
public:
|
||||
/*
|
||||
* This member function is invoked when the event is processed
|
||||
* (occurs). There is no default implementation; each subclass
|
||||
* must provide its own implementation. The event is not
|
||||
* automatically deleted after it is processed (to allow for
|
||||
* statically allocated event objects).
|
||||
*
|
||||
* If the AutoDestroy flag is set, the object is deleted once it
|
||||
* is processed.
|
||||
*/
|
||||
virtual void process() = 0;
|
||||
|
||||
/// Determine if the current event is scheduled
|
||||
bool scheduled() const { return getFlags(Scheduled); }
|
||||
|
||||
|
@ -216,37 +241,14 @@ class Event : public Serializable, public FastAlloc
|
|||
/// Remove the event from the current schedule
|
||||
void deschedule();
|
||||
|
||||
/// Return a C string describing the event. This string should
|
||||
/// *not* be dynamically allocated; just a const char array
|
||||
/// describing the event class.
|
||||
virtual const char *description() const;
|
||||
|
||||
/// Dump the current event data
|
||||
void dump();
|
||||
|
||||
/*
|
||||
* This member function is invoked when the event is processed
|
||||
* (occurs). There is no default implementation; each subclass
|
||||
* must provide its own implementation. The event is not
|
||||
* automatically deleted after it is processed (to allow for
|
||||
* statically allocated event objects).
|
||||
*
|
||||
* If the AutoDestroy flag is set, the object is deleted once it
|
||||
* is processed.
|
||||
*/
|
||||
virtual void process() = 0;
|
||||
|
||||
void annotate(unsigned value) { annotated_value = value; };
|
||||
unsigned annotation() { return annotated_value; }
|
||||
|
||||
/// Squash the current event
|
||||
void squash() { setFlags(Squashed); }
|
||||
|
||||
/// Check whether the event is squashed
|
||||
bool squashed() { return getFlags(Squashed); }
|
||||
bool squashed() const { return getFlags(Squashed); }
|
||||
|
||||
/// See if this is a SimExitEvent (without resorting to RTTI)
|
||||
bool isExitEvent() { return getFlags(IsExitEvent); }
|
||||
bool isExitEvent() const { return getFlags(IsExitEvent); }
|
||||
|
||||
/// Get the time that the event is scheduled
|
||||
Tick when() const { return _when; }
|
||||
|
@ -254,10 +256,12 @@ class Event : public Serializable, public FastAlloc
|
|||
/// Get the event priority
|
||||
int priority() const { return _priority; }
|
||||
|
||||
struct priority_compare :
|
||||
public std::binary_function<Event *, Event *, bool>
|
||||
struct priority_compare
|
||||
: public std::binary_function<Event *, Event *, bool>
|
||||
{
|
||||
bool operator()(const Event *l, const Event *r) const {
|
||||
bool
|
||||
operator()(const Event *l, const Event *r) const
|
||||
{
|
||||
return l->when() >= r->when() || l->priority() >= r->priority();
|
||||
}
|
||||
};
|
||||
|
@ -343,13 +347,15 @@ class EventQueue : public Serializable
|
|||
void deschedule(Event *ev);
|
||||
void reschedule(Event *ev);
|
||||
|
||||
Tick nextTick() { return head->when(); }
|
||||
Tick nextTick() const { return head->when(); }
|
||||
Event *serviceOne();
|
||||
|
||||
// process all events up to the given timestamp. we inline a
|
||||
// quick test to see if there are any events to process; if so,
|
||||
// call the internal out-of-line version to process them all.
|
||||
void serviceEvents(Tick when) {
|
||||
void
|
||||
serviceEvents(Tick when)
|
||||
{
|
||||
while (!empty()) {
|
||||
if (nextTick() > when)
|
||||
break;
|
||||
|
@ -367,9 +373,9 @@ class EventQueue : public Serializable
|
|||
void serviceEvents() { serviceEvents(curTick); }
|
||||
|
||||
// return true if no events are queued
|
||||
bool empty() { return head == NULL; }
|
||||
bool empty() const { return head == NULL; }
|
||||
|
||||
void dump();
|
||||
void dump() const;
|
||||
|
||||
Tick nextEventTime() { return empty() ? curTick : head->when(); }
|
||||
|
||||
|
@ -393,15 +399,14 @@ inline void
|
|||
Event::schedule(Tick t)
|
||||
{
|
||||
assert(!scheduled());
|
||||
// if (t < curTick)
|
||||
// warn("t is less than curTick, ensure you don't want cycles");
|
||||
assert(t >= curTick);
|
||||
|
||||
setFlags(Scheduled);
|
||||
#if TRACING_ON
|
||||
when_scheduled = curTick;
|
||||
#ifdef DEBUG_EVENTQ
|
||||
whenScheduled = curTick;
|
||||
#endif
|
||||
_when = t;
|
||||
queue->schedule(this);
|
||||
_queue->schedule(this);
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -411,25 +416,26 @@ Event::deschedule()
|
|||
|
||||
clearFlags(Squashed);
|
||||
clearFlags(Scheduled);
|
||||
queue->deschedule(this);
|
||||
_queue->deschedule(this);
|
||||
}
|
||||
|
||||
inline void
|
||||
Event::reschedule(Tick t, bool always)
|
||||
{
|
||||
assert(scheduled() || always);
|
||||
assert(t >= curTick);
|
||||
|
||||
#if TRACING_ON
|
||||
when_scheduled = curTick;
|
||||
#ifdef DEBUG_EVENTQ
|
||||
whenScheduled = curTick;
|
||||
#endif
|
||||
_when = t;
|
||||
|
||||
if (scheduled()) {
|
||||
clearFlags(Squashed);
|
||||
queue->reschedule(this);
|
||||
_queue->reschedule(this);
|
||||
} else {
|
||||
setFlags(Scheduled);
|
||||
queue->schedule(this);
|
||||
_queue->schedule(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -447,6 +453,9 @@ EventQueue::deschedule(Event *event)
|
|||
remove(event);
|
||||
if (DTRACE(Event))
|
||||
event->trace("descheduled");
|
||||
|
||||
if (event->getFlags(Event::AutoDelete))
|
||||
delete event;
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -458,6 +467,4 @@ EventQueue::reschedule(Event *event)
|
|||
event->trace("rescheduled");
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // __SIM_EVENTQ_HH__
|
||||
|
|
|
@ -49,7 +49,7 @@ SimLoopExitEvent::process()
|
|||
// if this got scheduled on a different queue (e.g. the committed
|
||||
// instruction queue) then make a corresponding event on the main
|
||||
// queue.
|
||||
if (theQueue() != &mainEventQueue) {
|
||||
if (queue() != &mainEventQueue) {
|
||||
exitSimLoop(cause, code);
|
||||
delete this;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue