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