X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsim%2Feventq.hh;h=e28c43bb774b8630bb68d470f0dbbe6dc13d7300;hb=a368fba7d4fa01b58d5c2d9b3cafd56e1102287c;hp=d172c73dad68a33778a4654dfcde614a0f3c9f3a;hpb=befae3c0b025593657e52ba24c872184d17be132;p=gem5.git diff --git a/src/sim/eventq.hh b/src/sim/eventq.hh index d172c73da..e28c43bb7 100644 --- a/src/sim/eventq.hh +++ b/src/sim/eventq.hh @@ -39,28 +39,18 @@ #include #include #include -#include +#include #include -#include #include "base/fast_alloc.hh" +#include "base/flags.hh" #include "base/misc.hh" #include "base/trace.hh" +#include "base/types.hh" #include "sim/serialize.hh" -#include "sim/host.hh" class EventQueue; // forward declaration -////////////////////// -// -// Main Event Queue -// -// Events on this queue are processed at the *beginning* of each -// cycle, before the pipeline simulation is performed. -// -// defined in eventq.cc -// -////////////////////// extern EventQueue mainEventQueue; /* @@ -74,6 +64,30 @@ class Event : public Serializable, public FastAlloc { friend class EventQueue; + protected: + typedef short FlagsType; + typedef ::Flags Flags; + + static const FlagsType PublicRead = 0x003f; // public readable flags + static const FlagsType PublicWrite = 0x001d; // public writable flags + static const FlagsType Squashed = 0x0001; // has been squashed + static const FlagsType Scheduled = 0x0002; // has been scheduled + static const FlagsType AutoDelete = 0x0004; // delete after dispatch + static const FlagsType AutoSerialize = 0x0008; // must be serialized + static const FlagsType IsExitEvent = 0x0010; // special exit event + static const FlagsType IsMainQueue = 0x0020; // on main event queue + static const FlagsType Initialized = 0x7a40; // somewhat random bits + static const FlagsType InitMask = 0xffc0; // mask for init bits + + bool + initialized() const + { + return this && (flags & InitMask) == Initialized; + } + + public: + typedef int8_t Priority; + private: // The event queue is now a linked list of linked lists. The // 'nextBin' pointer is to find the bin, where a bin is defined as @@ -87,16 +101,12 @@ class Event : public Serializable, public FastAlloc Event *nextBin; Event *nextInBin; - friend Event *insertBefore(Event *event, Event *curr); - friend Event *removeItem(Event *event, Event *last); - - /// queue to which this event belongs (though it may or may not be - /// scheduled on this queue yet) - EventQueue *_queue; + static Event *insertBefore(Event *event, Event *curr); + static Event *removeItem(Event *event, Event *last); Tick _when; //!< timestamp when event should be processed - short _priority; //!< event priority - short _flags; + Priority _priority; //!< event priority + Flags flags; #ifndef NDEBUG /// Global counter to generate unique IDs for Event instances @@ -107,39 +117,71 @@ class Event : public Serializable, public FastAlloc /// more difficult. Thus we use a global counter value when /// debugging. Counter instance; + + /// queue to which this event belongs (though it may or may not be + /// scheduled on this queue yet) + EventQueue *queue; #endif -#ifdef DEBUG_EVENTQ +#ifdef EVENTQ_DEBUG Tick whenCreated; //!< time created Tick whenScheduled; //!< time scheduled #endif - protected: void - setWhen(Tick when) + setWhen(Tick when, EventQueue *q) { _when = when; -#ifdef DEBUG_EVENTQ - whenScheduled = curTick; +#ifndef NDEBUG + queue = q; +#endif +#ifdef EVENTQ_DEBUG + whenScheduled = curTick(); #endif } protected: - enum Flags { - None = 0x0, - Squashed = 0x1, - Scheduled = 0x2, - AutoDelete = 0x4, - AutoSerialize = 0x8, - IsExitEvent = 0x10 - }; + /// Accessor for flags. + Flags + getFlags() const + { + return flags & PublicRead; + } - bool getFlags(Flags f) const { return (_flags & f) == f; } - void setFlags(Flags f) { _flags |= f; } - void clearFlags(Flags f) { _flags &= ~f; } + Flags + getFlags(Flags _flags) const + { + assert(_flags.noneSet(~PublicRead)); + return flags.isSet(_flags); + } - protected: - EventQueue *queue() const { return _queue; } + Flags + allFlags(Flags _flags) const + { + assert(_flags.noneSet(~PublicRead)); + return flags.allSet(_flags); + } + + /// Accessor for flags. + void + setFlags(Flags _flags) + { + assert(_flags.noneSet(~PublicWrite)); + flags.set(_flags); + } + + void + clearFlags(Flags _flags) + { + assert(_flags.noneSet(~PublicWrite)); + flags.clear(_flags); + } + + void + clearFlags() + { + flags.clear(PublicWrite); + } // This function isn't really useful if TRACING_ON is not defined virtual void trace(const char *action); //!< trace event activity @@ -149,88 +191,76 @@ class Event : public Serializable, public FastAlloc /// 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). - Trace_Enable_Pri = -101, - - /// Breakpoints should happen before anything else (except - /// enabling trace output), so we don't miss any action when - /// debugging. - Debug_Break_Pri = -100, - - /// CPU switches schedule the new CPU's tick event for the - /// same cycle (after unscheduling the old CPU's tick event). - /// The switch needs to come before any tick events to make - /// sure we don't tick both CPUs in the same cycle. - CPU_Switch_Pri = -31, - - /// For some reason "delayed" inter-cluster writebacks are - /// scheduled before regular writebacks (which have default - /// priority). Steve? - Delayed_Writeback_Pri = -1, - - /// Default is zero for historical reasons. - Default_Pri = 0, - - /// Serailization needs to occur before tick events also, so - /// that a serialize/unserialize is identical to an on-line - /// CPU switch. - Serialize_Pri = 32, - - /// CPU ticks must come after other associated CPU events - /// (such as writebacks). - CPU_Tick_Pri = 50, - - /// Statistics events (dump, reset, etc.) come after - /// everything else, but before exit. - Stat_Event_Pri = 90, - - /// Progress events come at the end. - Progress_Event_Pri = 95, - - /// If we want to exit on this cycle, it's the very last thing - /// we do. - Sim_Exit_Pri = 100, - - /// Maximum priority - Maximum_Pri = SHRT_MAX - }; + + /// Minimum priority + static const Priority Minimum_Pri = SCHAR_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). + static const Priority Trace_Enable_Pri = -101; + + /// Breakpoints should happen before anything else (except + /// enabling trace output), so we don't miss any action when + /// debugging. + static const Priority Debug_Break_Pri = -100; + + /// CPU switches schedule the new CPU's tick event for the + /// same cycle (after unscheduling the old CPU's tick event). + /// The switch needs to come before any tick events to make + /// sure we don't tick both CPUs in the same cycle. + static const Priority CPU_Switch_Pri = -31; + + /// For some reason "delayed" inter-cluster writebacks are + /// scheduled before regular writebacks (which have default + /// priority). Steve? + static const Priority Delayed_Writeback_Pri = -1; + + /// Default is zero for historical reasons. + static const Priority Default_Pri = 0; + + /// Serailization needs to occur before tick events also, so + /// that a serialize/unserialize is identical to an on-line + /// CPU switch. + static const Priority Serialize_Pri = 32; + + /// CPU ticks must come after other associated CPU events + /// (such as writebacks). + static const Priority CPU_Tick_Pri = 50; + + /// Statistics events (dump, reset, etc.) come after + /// everything else, but before exit. + static const Priority Stat_Event_Pri = 90; + + /// Progress events come at the end. + static const Priority Progress_Event_Pri = 95; + + /// If we want to exit on this cycle, it's the very last thing + /// we do. + static const Priority Sim_Exit_Pri = 100; + + /// Maximum priority + static const Priority Maximum_Pri = SCHAR_MAX; /* * Event constructor * @param queue that the event gets scheduled on */ - Event(EventQueue *q, Priority p = Default_Pri) - : nextBin(NULL), nextInBin(NULL), _queue(q), _priority(p), _flags(None) + Event(Priority p = Default_Pri) + : nextBin(NULL), nextInBin(NULL), _priority(p), flags(Initialized) { #ifndef NDEBUG instance = ++instanceCounter; + queue = NULL; #endif #ifdef EVENTQ_DEBUG - whenCreated = curTick; + whenCreated = curTick(); whenScheduled = 0; #endif } - virtual - ~Event() - { - } - - virtual const std::string - name() const - { -#ifndef NDEBUG - return csprintf("Event_%d", instance); -#else - return csprintf("Event_%x", (uintptr_t)this); -#endif - } + virtual ~Event(); + virtual const std::string name() const; /// Return a C string describing the event. This string should /// *not* be dynamically allocated; just a const char array @@ -254,33 +284,24 @@ class Event : public Serializable, public FastAlloc virtual void process() = 0; /// Determine if the current event is scheduled - bool scheduled() const { return getFlags(Scheduled); } - - /// Schedule the event with the current priority or default priority - void schedule(Tick t); - - /// Reschedule the event with the current priority - // always parameter means to schedule if not already scheduled - void reschedule(Tick t, bool always = false); - - /// Remove the event from the current schedule - void deschedule(); + bool scheduled() const { return flags.isSet(Scheduled); } /// Squash the current event - void squash() { setFlags(Squashed); } + void squash() { flags.set(Squashed); } /// Check whether the event is squashed - bool squashed() const { return getFlags(Squashed); } + bool squashed() const { return flags.isSet(Squashed); } /// See if this is a SimExitEvent (without resorting to RTTI) - bool isExitEvent() const { return getFlags(IsExitEvent); } + bool isExitEvent() const { return flags.isSet(IsExitEvent); } /// Get the time that the event is scheduled Tick when() const { return _when; } /// Get the event priority - int priority() const { return _priority; } + Priority priority() const { return _priority; } +#ifndef SWIG struct priority_compare : public std::binary_function { @@ -293,84 +314,74 @@ class Event : public Serializable, public FastAlloc virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); +#endif }; -template -void -DelayFunction(Tick when, T *object) +#ifndef SWIG +inline bool +operator<(const Event &l, const Event &r) { - class DelayEvent : public Event - { - private: - T *object; - - public: - DelayEvent(Tick when, T *o) - : Event(&mainEventQueue), object(o) - { setFlags(this->AutoDestroy); schedule(when); } - void process() { (object->*F)(); } - const char *description() const { return "delay"; } - }; - - new DelayEvent(when, object); + return l.when() < r.when() || + (l.when() == r.when() && l.priority() < r.priority()); } -template -class EventWrapper : public Event +inline bool +operator>(const Event &l, const Event &r) { - private: - T *object; + return l.when() > r.when() || + (l.when() == r.when() && l.priority() > r.priority()); +} - public: - EventWrapper(T *obj, bool del = false, - EventQueue *q = &mainEventQueue, - Priority p = Default_Pri) - : Event(q, p), object(obj) - { - if (del) - setFlags(AutoDelete); - } +inline bool +operator<=(const Event &l, const Event &r) +{ + return l.when() < r.when() || + (l.when() == r.when() && l.priority() <= r.priority()); +} +inline bool +operator>=(const Event &l, const Event &r) +{ + return l.when() > r.when() || + (l.when() == r.when() && l.priority() >= r.priority()); +} - EventWrapper(T *obj, Tick t, bool del = false, - EventQueue *q = &mainEventQueue, - Priority p = Default_Pri) - : Event(q, p), object(obj) - { - if (del) - setFlags(AutoDelete); - schedule(t); - } +inline bool +operator==(const Event &l, const Event &r) +{ + return l.when() == r.when() && l.priority() == r.priority(); +} - void process() { (object->*F)(); } -}; +inline bool +operator!=(const Event &l, const Event &r) +{ + return l.when() != r.when() || l.priority() != r.priority(); +} +#endif /* * Queue of events sorted in time order */ class EventQueue : public Serializable { - protected: - std::string objName; - private: + std::string objName; Event *head; void insert(Event *event); void remove(Event *event); - public: + EventQueue(const EventQueue &); + const EventQueue &operator=(const EventQueue &); - // constructor - EventQueue(const std::string &n) - : objName(n), head(NULL) - {} + public: + EventQueue(const std::string &n); virtual const std::string name() const { return objName; } // schedule the given event on this queue - void schedule(Event *ev, Tick when); - void deschedule(Event *ev); - void reschedule(Event *ev, Tick when); + void schedule(Event *event, Tick when); + void deschedule(Event *event); + void reschedule(Event *event, Tick when, bool always = false); Tick nextTick() const { return head->when(); } Event *serviceOne(); @@ -394,105 +405,98 @@ class EventQueue : public Serializable } } - // default: process all events up to 'now' (curTick) - void serviceEvents() { serviceEvents(curTick); } + // default: process all events up to 'now' (curTick()) + void serviceEvents() { serviceEvents(curTick()); } // return true if no events are queued bool empty() const { return head == NULL; } void dump() const; - Tick nextEventTime() { return empty() ? curTick : head->when(); } + Tick nextEventTime() { return empty() ? curTick() : head->when(); } bool debugVerify() const; +#ifndef SWIG virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); +#endif }; +#ifndef SWIG +class EventManager +{ + protected: + /** A pointer to this object's event queue */ + EventQueue *eventq; -////////////////////// -// -// inline functions -// -// can't put these inside declaration due to circular dependence -// between Event and EventQueue classes. -// -////////////////////// + public: + EventManager(EventManager &em) : eventq(em.queue()) {} + EventManager(EventManager *em) : eventq(em ? em->queue() : NULL) {} + EventManager(EventQueue *eq) : eventq(eq) {} -// schedule at specified time (place on event queue specified via -// constructor) -inline void -Event::schedule(Tick when) -{ - _queue->schedule(this, when); -} + EventQueue * + queue() const + { + return eventq; + } -inline void -Event::deschedule() -{ - _queue->deschedule(this); -} + operator EventQueue *() const + { + return eventq; + } -inline void -Event::reschedule(Tick when, bool always) -{ - if (scheduled()) { - _queue->reschedule(this, when); - } else { - assert(always); - _queue->schedule(this, when); + void + schedule(Event &event, Tick when) + { + eventq->schedule(&event, when); } -} -inline bool -operator<(const Event &l, const Event &r) -{ - return l.when() < r.when() || - (l.when() == r.when() && l.priority() < r.priority()); -} + void + deschedule(Event &event) + { + eventq->deschedule(&event); + } -inline bool -operator>(const Event &l, const Event &r) -{ - return l.when() > r.when() || - (l.when() == r.when() && l.priority() > r.priority()); -} + void + reschedule(Event &event, Tick when, bool always = false) + { + eventq->reschedule(&event, when, always); + } -inline bool -operator<=(const Event &l, const Event &r) -{ - return l.when() < r.when() || - (l.when() == r.when() && l.priority() <= r.priority()); -} -inline bool -operator>=(const Event &l, const Event &r) -{ - return l.when() > r.when() || - (l.when() == r.when() && l.priority() >= r.priority()); -} + void + schedule(Event *event, Tick when) + { + eventq->schedule(event, when); + } -inline bool -operator==(const Event &l, const Event &r) -{ - return l.when() == r.when() && l.priority() == r.priority(); -} + void + deschedule(Event *event) + { + eventq->deschedule(event); + } -inline bool -operator!=(const Event &l, const Event &r) -{ - return l.when() != r.when() || l.priority() != r.priority(); -} + void + reschedule(Event *event, Tick when, bool always = false) + { + eventq->reschedule(event, when, always); + } +}; inline void EventQueue::schedule(Event *event, Tick when) { - assert(when >= curTick); + assert((UTick)when >= (UTick)curTick()); assert(!event->scheduled()); + assert(event->initialized()); - event->setWhen(when); + event->setWhen(when, this); insert(event); - event->setFlags(Event::Scheduled); + event->flags.set(Event::Scheduled); + if (this == &mainEventQueue) + event->flags.set(Event::IsMainQueue); + else + event->flags.clear(Event::IsMainQueue); if (DTRACE(Event)) event->trace("scheduled"); @@ -502,13 +506,14 @@ inline void EventQueue::deschedule(Event *event) { assert(event->scheduled()); + assert(event->initialized()); remove(event); - event->clearFlags(Event::Squashed); - event->clearFlags(Event::Scheduled); + event->flags.clear(Event::Squashed); + event->flags.clear(Event::Scheduled); - if (event->getFlags(Event::AutoDelete)) + if (event->flags.isSet(Event::AutoDelete)) delete event; if (DTRACE(Event)) @@ -516,18 +521,79 @@ EventQueue::deschedule(Event *event) } inline void -EventQueue::reschedule(Event *event, Tick when) +EventQueue::reschedule(Event *event, Tick when, bool always) { - assert(when >= curTick); - assert(event->scheduled()); - - remove(event); - event->setWhen(when); + assert(when >= curTick()); + assert(always || event->scheduled()); + assert(event->initialized()); + + if (event->scheduled()) + remove(event); + + event->setWhen(when, this); insert(event); - event->clearFlags(Event::Squashed); + event->flags.clear(Event::Squashed); + event->flags.set(Event::Scheduled); + if (this == &mainEventQueue) + event->flags.set(Event::IsMainQueue); + else + event->flags.clear(Event::IsMainQueue); if (DTRACE(Event)) event->trace("rescheduled"); } +template +void +DelayFunction(EventQueue *eventq, Tick when, T *object) +{ + class DelayEvent : public Event + { + private: + T *object; + + public: + DelayEvent(T *o) + : object(o) + { this->setFlags(AutoDelete); } + void process() { (object->*F)(); } + const char *description() const { return "delay"; } + }; + + eventq->schedule(new DelayEvent(object), when); +} + +template +class EventWrapper : public Event +{ + private: + T *object; + + public: + EventWrapper(T *obj, bool del = false, Priority p = Default_Pri) + : Event(p), object(obj) + { + if (del) + setFlags(AutoDelete); + } + + EventWrapper(T &obj, bool del = false, Priority p = Default_Pri) + : Event(p), object(&obj) + { + if (del) + setFlags(AutoDelete); + } + + void process() { (object->*F)(); } + + const std::string + name() const + { + return object->name() + ".wrapped_event"; + } + + const char *description() const { return "EventWrapped"; } +}; +#endif + #endif // __SIM_EVENTQ_HH__