eventq.hh revision 4437:b6e304245729
1/* 2 * Copyright (c) 2000-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Reinhardt 29 * Nathan Binkert 30 */ 31 32/* @file 33 * EventQueue interfaces 34 */ 35 36#ifndef __SIM_EVENTQ_HH__ 37#define __SIM_EVENTQ_HH__ 38 39#include <assert.h> 40 41#include <algorithm> 42#include <map> 43#include <string> 44#include <vector> 45 46#include "sim/host.hh" // for Tick 47 48#include "base/fast_alloc.hh" 49#include "base/misc.hh" 50#include "base/trace.hh" 51#include "sim/serialize.hh" 52 53class EventQueue; // forward declaration 54 55////////////////////// 56// 57// Main Event Queue 58// 59// Events on this queue are processed at the *beginning* of each 60// cycle, before the pipeline simulation is performed. 61// 62// defined in eventq.cc 63// 64////////////////////// 65extern EventQueue mainEventQueue; 66 67 68/* 69 * An item on an event queue. The action caused by a given 70 * event is specified by deriving a subclass and overriding the 71 * process() member function. 72 */ 73class Event : public Serializable, public FastAlloc 74{ 75 friend class EventQueue; 76 77 private: 78 79#ifndef NDEBUG 80 /// Global counter to generate unique IDs for Event instances 81 static Counter instanceCounter; 82 83 /// This event's unique ID. We can also use pointer values for 84 /// this but they're not consistent across runs making debugging 85 /// more difficult. Thus we use a global counter value when 86 /// debugging. 87 Counter instanceId; 88#endif // NDEBUG 89 90 /// queue to which this event belongs (though it may or may not be 91 /// scheduled on this queue yet) 92 EventQueue *queue; 93 94 Event *next; 95 96 Tick _when; //!< timestamp when event should be processed 97 int _priority; //!< event priority 98 char _flags; 99 100 protected: 101 enum Flags { 102 None = 0x0, 103 Squashed = 0x1, 104 Scheduled = 0x2, 105 AutoDelete = 0x4, 106 AutoSerialize = 0x8, 107 IsExitEvent = 0x10 108 }; 109 110 bool getFlags(Flags f) const { return (_flags & f) == f; } 111 void setFlags(Flags f) { _flags |= f; } 112 void clearFlags(Flags f) { _flags &= ~f; } 113 114 protected: 115 EventQueue *theQueue() const { return queue; } 116 117#if TRACING_ON 118 Tick when_created; //!< Keep track of creation time For debugging 119 Tick when_scheduled; //!< Keep track of creation time For debugging 120 121 virtual void trace(const char *action); //!< trace event activity 122#else 123 void trace(const char *) {} 124#endif 125 126 unsigned annotated_value; 127 128 public: 129 130 /// Event priorities, to provide tie-breakers for events scheduled 131 /// at the same cycle. Most events are scheduled at the default 132 /// priority; these values are used to control events that need to 133 /// be ordered within a cycle. 134 enum Priority { 135 /// If we enable tracing on a particular cycle, do that as the 136 /// very first thing so we don't miss any of the events on 137 /// that cycle (even if we enter the debugger). 138 Trace_Enable_Pri = -101, 139 140 /// Breakpoints should happen before anything else (except 141 /// enabling trace output), so we don't miss any action when 142 /// debugging. 143 Debug_Break_Pri = -100, 144 145 /// CPU switches schedule the new CPU's tick event for the 146 /// same cycle (after unscheduling the old CPU's tick event). 147 /// The switch needs to come before any tick events to make 148 /// sure we don't tick both CPUs in the same cycle. 149 CPU_Switch_Pri = -31, 150 151 /// For some reason "delayed" inter-cluster writebacks are 152 /// scheduled before regular writebacks (which have default 153 /// priority). Steve? 154 Delayed_Writeback_Pri = -1, 155 156 /// Default is zero for historical reasons. 157 Default_Pri = 0, 158 159 /// Serailization needs to occur before tick events also, so 160 /// that a serialize/unserialize is identical to an on-line 161 /// CPU switch. 162 Serialize_Pri = 32, 163 164 /// CPU ticks must come after other associated CPU events 165 /// (such as writebacks). 166 CPU_Tick_Pri = 50, 167 168 /// Statistics events (dump, reset, etc.) come after 169 /// everything else, but before exit. 170 Stat_Event_Pri = 90, 171 172 /// Progress events come at the end. 173 Progress_Event_Pri = 95, 174 175 /// If we want to exit on this cycle, it's the very last thing 176 /// we do. 177 Sim_Exit_Pri = 100 178 }; 179 180 /* 181 * Event constructor 182 * @param queue that the event gets scheduled on 183 */ 184 Event(EventQueue *q, Priority p = Default_Pri) 185 : queue(q), next(NULL), _priority(p), _flags(None), 186#if TRACING_ON 187 when_created(curTick), when_scheduled(0), 188#endif 189 annotated_value(0) 190 { 191#ifndef NDEBUG 192 instanceId = ++instanceCounter; 193#endif 194 } 195 196 ~Event() {} 197 198 virtual const std::string name() const { 199#ifndef NDEBUG 200 return csprintf("Event_%d", instanceId); 201#else 202 return csprintf("Event_%x", (uintptr_t)this); 203#endif 204 } 205 206 /// Determine if the current event is scheduled 207 bool scheduled() const { return getFlags(Scheduled); } 208 209 /// Schedule the event with the current priority or default priority 210 void schedule(Tick t); 211 212 /// Reschedule the event with the current priority 213 // always parameter means to schedule if not already scheduled 214 void reschedule(Tick t, bool always = false); 215 216 /// Remove the event from the current schedule 217 void deschedule(); 218 219 /// Return a C string describing the event. This string should 220 /// *not* be dynamically allocated; just a const char array 221 /// describing the event class. 222 virtual const char *description(); 223 224 /// Dump the current event data 225 void dump(); 226 227 /* 228 * This member function is invoked when the event is processed 229 * (occurs). There is no default implementation; each subclass 230 * must provide its own implementation. The event is not 231 * automatically deleted after it is processed (to allow for 232 * statically allocated event objects). 233 * 234 * If the AutoDestroy flag is set, the object is deleted once it 235 * is processed. 236 */ 237 virtual void process() = 0; 238 239 void annotate(unsigned value) { annotated_value = value; }; 240 unsigned annotation() { return annotated_value; } 241 242 /// Squash the current event 243 void squash() { setFlags(Squashed); } 244 245 /// Check whether the event is squashed 246 bool squashed() { return getFlags(Squashed); } 247 248 /// See if this is a SimExitEvent (without resorting to RTTI) 249 bool isExitEvent() { return getFlags(IsExitEvent); } 250 251 /// Get the time that the event is scheduled 252 Tick when() const { return _when; } 253 254 /// Get the event priority 255 int priority() const { return _priority; } 256 257 struct priority_compare : 258 public std::binary_function<Event *, Event *, bool> 259 { 260 bool operator()(const Event *l, const Event *r) const { 261 return l->when() >= r->when() || l->priority() >= r->priority(); 262 } 263 }; 264 265 virtual void serialize(std::ostream &os); 266 virtual void unserialize(Checkpoint *cp, const std::string §ion); 267}; 268 269template <class T, void (T::* F)()> 270void 271DelayFunction(Tick when, T *object) 272{ 273 class DelayEvent : public Event 274 { 275 private: 276 T *object; 277 278 public: 279 DelayEvent(Tick when, T *o) 280 : Event(&mainEventQueue), object(o) 281 { setFlags(this->AutoDestroy); schedule(when); } 282 void process() { (object->*F)(); } 283 const char *description() { return "delay"; } 284 }; 285 286 new DelayEvent(when, object); 287} 288 289template <class T, void (T::* F)()> 290class EventWrapper : public Event 291{ 292 private: 293 T *object; 294 295 public: 296 EventWrapper(T *obj, bool del = false, EventQueue *q = &mainEventQueue, 297 Priority p = Default_Pri) 298 : Event(q, p), object(obj) 299 { 300 if (del) 301 setFlags(AutoDelete); 302 } 303 void process() { (object->*F)(); } 304}; 305 306/* 307 * Queue of events sorted in time order 308 */ 309class EventQueue : public Serializable 310{ 311 protected: 312 std::string objName; 313 314 private: 315 Event *head; 316 317 void insert(Event *event); 318 void remove(Event *event); 319 320 public: 321 322 // constructor 323 EventQueue(const std::string &n) 324 : objName(n), head(NULL) 325 {} 326 327 virtual const std::string name() const { return objName; } 328 329 // schedule the given event on this queue 330 void schedule(Event *ev); 331 void deschedule(Event *ev); 332 void reschedule(Event *ev); 333 334 Tick nextTick() { return head->when(); } 335 Event *serviceOne(); 336 337 // process all events up to the given timestamp. we inline a 338 // quick test to see if there are any events to process; if so, 339 // call the internal out-of-line version to process them all. 340 void serviceEvents(Tick when) { 341 while (!empty()) { 342 if (nextTick() > when) 343 break; 344 345 /** 346 * @todo this assert is a good bug catcher. I need to 347 * make it true again. 348 */ 349 //assert(head->when() >= when && "event scheduled in the past"); 350 serviceOne(); 351 } 352 } 353 354 // default: process all events up to 'now' (curTick) 355 void serviceEvents() { serviceEvents(curTick); } 356 357 // return true if no events are queued 358 bool empty() { return head == NULL; } 359 360 void dump(); 361 362 Tick nextEventTime() { return empty() ? curTick : head->when(); } 363 364 virtual void serialize(std::ostream &os); 365 virtual void unserialize(Checkpoint *cp, const std::string §ion); 366}; 367 368 369////////////////////// 370// 371// inline functions 372// 373// can't put these inside declaration due to circular dependence 374// between Event and EventQueue classes. 375// 376////////////////////// 377 378// schedule at specified time (place on event queue specified via 379// constructor) 380inline void 381Event::schedule(Tick t) 382{ 383 assert(!scheduled()); 384// if (t < curTick) 385// warn("t is less than curTick, ensure you don't want cycles"); 386 387 setFlags(Scheduled); 388#if TRACING_ON 389 when_scheduled = curTick; 390#endif 391 _when = t; 392 queue->schedule(this); 393} 394 395inline void 396Event::deschedule() 397{ 398 assert(scheduled()); 399 400 clearFlags(Squashed); 401 clearFlags(Scheduled); 402 queue->deschedule(this); 403} 404 405inline void 406Event::reschedule(Tick t, bool always) 407{ 408 assert(scheduled() || always); 409 410#if TRACING_ON 411 when_scheduled = curTick; 412#endif 413 _when = t; 414 415 if (scheduled()) { 416 clearFlags(Squashed); 417 queue->reschedule(this); 418 } else { 419 setFlags(Scheduled); 420 queue->schedule(this); 421 } 422} 423 424inline void 425EventQueue::schedule(Event *event) 426{ 427 insert(event); 428 if (DTRACE(Event)) 429 event->trace("scheduled"); 430} 431 432inline void 433EventQueue::deschedule(Event *event) 434{ 435 remove(event); 436 if (DTRACE(Event)) 437 event->trace("descheduled"); 438} 439 440inline void 441EventQueue::reschedule(Event *event) 442{ 443 remove(event); 444 insert(event); 445 if (DTRACE(Event)) 446 event->trace("rescheduled"); 447} 448 449 450 451#endif // __SIM_EVENTQ_HH__ 452