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