eventq.hh revision 5577
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 <algorithm> 40#include <cassert> 41#include <climits> 42#include <map> 43#include <string> 44#include <vector> 45 46#include "base/fast_alloc.hh" 47#include "base/misc.hh" 48#include "base/trace.hh" 49#include "sim/serialize.hh" 50#include "sim/host.hh" 51 52class EventQueue; // forward declaration 53 54////////////////////// 55// 56// Main Event Queue 57// 58// Events on this queue are processed at the *beginning* of each 59// cycle, before the pipeline simulation is performed. 60// 61// defined in eventq.cc 62// 63////////////////////// 64extern EventQueue mainEventQueue; 65 66/* 67 * An item on an event queue. The action caused by a given 68 * event is specified by deriving a subclass and overriding the 69 * process() member function. 70 * 71 * Caution, the order of members is chosen to maximize data packing. 72 */ 73class Event : public Serializable, public FastAlloc 74{ 75 friend class EventQueue; 76 77 private: 78 // The event queue is now a linked list of linked lists. The 79 // 'nextBin' pointer is to find the bin, where a bin is defined as 80 // when+priority. All events in the same bin will be stored in a 81 // second linked list (a stack) maintained by the 'nextInBin' 82 // pointer. The list will be accessed in LIFO order. The end 83 // result is that the insert/removal in 'nextBin' is 84 // linear/constant, and the lookup/removal in 'nextInBin' is 85 // constant/constant. Hopefully this is a significant improvement 86 // over the current fully linear insertion. 87 Event *nextBin; 88 Event *nextInBin; 89 90 friend Event *insertBefore(Event *event, Event *curr); 91 friend Event *removeItem(Event *event, Event *last); 92 93 /// queue to which this event belongs (though it may or may not be 94 /// scheduled on this queue yet) 95 EventQueue *_queue; 96 97 Tick _when; //!< timestamp when event should be processed 98 short _priority; //!< event priority 99 short _flags; 100 101#ifndef NDEBUG 102 /// Global counter to generate unique IDs for Event instances 103 static Counter instanceCounter; 104 105 /// This event's unique ID. We can also use pointer values for 106 /// this but they're not consistent across runs making debugging 107 /// more difficult. Thus we use a global counter value when 108 /// debugging. 109 Counter instance; 110#endif 111 112#ifdef EVENTQ_DEBUG 113 Tick whenCreated; //!< time created 114 Tick whenScheduled; //!< time scheduled 115#endif 116 117 protected: 118 void 119 setWhen(Tick when) 120 { 121 _when = when; 122#ifdef EVENTQ_DEBUG 123 whenScheduled = curTick; 124#endif 125 } 126 127 protected: 128 enum Flags { 129 None = 0x0, 130 Squashed = 0x1, 131 Scheduled = 0x2, 132 AutoDelete = 0x4, 133 AutoSerialize = 0x8, 134 IsExitEvent = 0x10 135 }; 136 137 bool getFlags(Flags f) const { return (_flags & f) == f; } 138 void setFlags(Flags f) { _flags |= f; } 139 void clearFlags(Flags f) { _flags &= ~f; } 140 141 protected: 142 EventQueue *queue() const { return _queue; } 143 144 // This function isn't really useful if TRACING_ON is not defined 145 virtual void trace(const char *action); //!< trace event activity 146 147 public: 148 /// Event priorities, to provide tie-breakers for events scheduled 149 /// at the same cycle. Most events are scheduled at the default 150 /// priority; these values are used to control events that need to 151 /// be ordered within a cycle. 152 enum Priority { 153 /// Minimum priority 154 Minimum_Pri = SHRT_MIN, 155 156 /// If we enable tracing on a particular cycle, do that as the 157 /// very first thing so we don't miss any of the events on 158 /// that cycle (even if we enter the debugger). 159 Trace_Enable_Pri = -101, 160 161 /// Breakpoints should happen before anything else (except 162 /// enabling trace output), so we don't miss any action when 163 /// debugging. 164 Debug_Break_Pri = -100, 165 166 /// CPU switches schedule the new CPU's tick event for the 167 /// same cycle (after unscheduling the old CPU's tick event). 168 /// The switch needs to come before any tick events to make 169 /// sure we don't tick both CPUs in the same cycle. 170 CPU_Switch_Pri = -31, 171 172 /// For some reason "delayed" inter-cluster writebacks are 173 /// scheduled before regular writebacks (which have default 174 /// priority). Steve? 175 Delayed_Writeback_Pri = -1, 176 177 /// Default is zero for historical reasons. 178 Default_Pri = 0, 179 180 /// Serailization needs to occur before tick events also, so 181 /// that a serialize/unserialize is identical to an on-line 182 /// CPU switch. 183 Serialize_Pri = 32, 184 185 /// CPU ticks must come after other associated CPU events 186 /// (such as writebacks). 187 CPU_Tick_Pri = 50, 188 189 /// Statistics events (dump, reset, etc.) come after 190 /// everything else, but before exit. 191 Stat_Event_Pri = 90, 192 193 /// Progress events come at the end. 194 Progress_Event_Pri = 95, 195 196 /// If we want to exit on this cycle, it's the very last thing 197 /// we do. 198 Sim_Exit_Pri = 100, 199 200 /// Maximum priority 201 Maximum_Pri = SHRT_MAX 202 }; 203 204 /* 205 * Event constructor 206 * @param queue that the event gets scheduled on 207 */ 208 Event(EventQueue *q, Priority p = Default_Pri) 209 : nextBin(NULL), nextInBin(NULL), _queue(q), _priority(p), _flags(None) 210 { 211#ifndef NDEBUG 212 instance = ++instanceCounter; 213#endif 214#ifdef EVENTQ_DEBUG 215 whenCreated = curTick; 216 whenScheduled = 0; 217#endif 218 } 219 220 virtual 221 ~Event() 222 { 223 } 224 225 virtual const std::string 226 name() const 227 { 228#ifndef NDEBUG 229 return csprintf("Event_%d", instance); 230#else 231 return csprintf("Event_%x", (uintptr_t)this); 232#endif 233 } 234 235 /// Return a C string describing the event. This string should 236 /// *not* be dynamically allocated; just a const char array 237 /// describing the event class. 238 virtual const char *description() const; 239 240 /// Dump the current event data 241 void dump() const; 242 243 public: 244 /* 245 * This member function is invoked when the event is processed 246 * (occurs). There is no default implementation; each subclass 247 * must provide its own implementation. The event is not 248 * automatically deleted after it is processed (to allow for 249 * statically allocated event objects). 250 * 251 * If the AutoDestroy flag is set, the object is deleted once it 252 * is processed. 253 */ 254 virtual void process() = 0; 255 256 /// Determine if the current event is scheduled 257 bool scheduled() const { return getFlags(Scheduled); } 258 259 /// Schedule the event with the current priority or default priority 260 void schedule(Tick t); 261 262 /// Reschedule the event with the current priority 263 // always parameter means to schedule if not already scheduled 264 void reschedule(Tick t, bool always = false); 265 266 /// Remove the event from the current schedule 267 void deschedule(); 268 269 /// Squash the current event 270 void squash() { setFlags(Squashed); } 271 272 /// Check whether the event is squashed 273 bool squashed() const { return getFlags(Squashed); } 274 275 /// See if this is a SimExitEvent (without resorting to RTTI) 276 bool isExitEvent() const { return getFlags(IsExitEvent); } 277 278 /// Get the time that the event is scheduled 279 Tick when() const { return _when; } 280 281 /// Get the event priority 282 int priority() const { return _priority; } 283 284 struct priority_compare 285 : public std::binary_function<Event *, Event *, bool> 286 { 287 bool 288 operator()(const Event *l, const Event *r) const 289 { 290 return l->when() >= r->when() || l->priority() >= r->priority(); 291 } 292 }; 293 294 virtual void serialize(std::ostream &os); 295 virtual void unserialize(Checkpoint *cp, const std::string §ion); 296}; 297 298template <class T, void (T::* F)()> 299void 300DelayFunction(Tick when, T *object) 301{ 302 class DelayEvent : public Event 303 { 304 private: 305 T *object; 306 307 public: 308 DelayEvent(Tick when, T *o) 309 : Event(&mainEventQueue), object(o) 310 { setFlags(this->AutoDestroy); schedule(when); } 311 void process() { (object->*F)(); } 312 const char *description() const { return "delay"; } 313 }; 314 315 new DelayEvent(when, object); 316} 317 318template <class T, void (T::* F)()> 319class EventWrapper : public Event 320{ 321 private: 322 T *object; 323 324 public: 325 EventWrapper(T *obj, bool del = false, 326 EventQueue *q = &mainEventQueue, 327 Priority p = Default_Pri) 328 : Event(q, p), object(obj) 329 { 330 if (del) 331 setFlags(AutoDelete); 332 } 333 334 EventWrapper(T *obj, Tick t, bool del = false, 335 EventQueue *q = &mainEventQueue, 336 Priority p = Default_Pri) 337 : Event(q, p), object(obj) 338 { 339 if (del) 340 setFlags(AutoDelete); 341 schedule(t); 342 } 343 344 void process() { (object->*F)(); } 345}; 346 347/* 348 * Queue of events sorted in time order 349 */ 350class EventQueue : public Serializable 351{ 352 protected: 353 std::string objName; 354 355 private: 356 Event *head; 357 358 void insert(Event *event); 359 void remove(Event *event); 360 361 public: 362 363 // constructor 364 EventQueue(const std::string &n) 365 : objName(n), head(NULL) 366 {} 367 368 virtual const std::string name() const { return objName; } 369 370 // schedule the given event on this queue 371 void schedule(Event *ev, Tick when); 372 void deschedule(Event *ev); 373 void reschedule(Event *ev, Tick when); 374 375 Tick nextTick() const { return head->when(); } 376 Event *serviceOne(); 377 378 // process all events up to the given timestamp. we inline a 379 // quick test to see if there are any events to process; if so, 380 // call the internal out-of-line version to process them all. 381 void 382 serviceEvents(Tick when) 383 { 384 while (!empty()) { 385 if (nextTick() > when) 386 break; 387 388 /** 389 * @todo this assert is a good bug catcher. I need to 390 * make it true again. 391 */ 392 //assert(head->when() >= when && "event scheduled in the past"); 393 serviceOne(); 394 } 395 } 396 397 // default: process all events up to 'now' (curTick) 398 void serviceEvents() { serviceEvents(curTick); } 399 400 // return true if no events are queued 401 bool empty() const { return head == NULL; } 402 403 void dump() const; 404 405 Tick nextEventTime() { return empty() ? curTick : head->when(); } 406 407 bool debugVerify() const; 408 409 virtual void serialize(std::ostream &os); 410 virtual void unserialize(Checkpoint *cp, const std::string §ion); 411}; 412 413 414////////////////////// 415// 416// inline functions 417// 418// can't put these inside declaration due to circular dependence 419// between Event and EventQueue classes. 420// 421////////////////////// 422 423// schedule at specified time (place on event queue specified via 424// constructor) 425inline void 426Event::schedule(Tick when) 427{ 428 _queue->schedule(this, when); 429} 430 431inline void 432Event::deschedule() 433{ 434 _queue->deschedule(this); 435} 436 437inline void 438Event::reschedule(Tick when, bool always) 439{ 440 if (scheduled()) { 441 _queue->reschedule(this, when); 442 } else { 443 assert(always); 444 _queue->schedule(this, when); 445 } 446} 447 448inline bool 449operator<(const Event &l, const Event &r) 450{ 451 return l.when() < r.when() || 452 (l.when() == r.when() && l.priority() < r.priority()); 453} 454 455inline bool 456operator>(const Event &l, const Event &r) 457{ 458 return l.when() > r.when() || 459 (l.when() == r.when() && l.priority() > r.priority()); 460} 461 462inline bool 463operator<=(const Event &l, const Event &r) 464{ 465 return l.when() < r.when() || 466 (l.when() == r.when() && l.priority() <= r.priority()); 467} 468inline bool 469operator>=(const Event &l, const Event &r) 470{ 471 return l.when() > r.when() || 472 (l.when() == r.when() && l.priority() >= r.priority()); 473} 474 475inline bool 476operator==(const Event &l, const Event &r) 477{ 478 return l.when() == r.when() && l.priority() == r.priority(); 479} 480 481inline bool 482operator!=(const Event &l, const Event &r) 483{ 484 return l.when() != r.when() || l.priority() != r.priority(); 485} 486 487inline void 488EventQueue::schedule(Event *event, Tick when) 489{ 490 assert(when >= curTick); 491 assert(!event->scheduled()); 492 493 event->setWhen(when); 494 insert(event); 495 event->setFlags(Event::Scheduled); 496 497 if (DTRACE(Event)) 498 event->trace("scheduled"); 499} 500 501inline void 502EventQueue::deschedule(Event *event) 503{ 504 assert(event->scheduled()); 505 506 remove(event); 507 508 event->clearFlags(Event::Squashed); 509 event->clearFlags(Event::Scheduled); 510 511 if (event->getFlags(Event::AutoDelete)) 512 delete event; 513 514 if (DTRACE(Event)) 515 event->trace("descheduled"); 516} 517 518inline void 519EventQueue::reschedule(Event *event, Tick when) 520{ 521 assert(when >= curTick); 522 assert(event->scheduled()); 523 524 remove(event); 525 event->setWhen(when); 526 insert(event); 527 event->clearFlags(Event::Squashed); 528 529 if (DTRACE(Event)) 530 event->trace("rescheduled"); 531} 532 533#endif // __SIM_EVENTQ_HH__ 534