eventq.hh revision 4075
16899SN/A/* 26899SN/A * Copyright (c) 2000-2005 The Regents of The University of Michigan 36899SN/A * All rights reserved. 46899SN/A * 56899SN/A * Redistribution and use in source and binary forms, with or without 66899SN/A * modification, are permitted provided that the following conditions are 76899SN/A * met: redistributions of source code must retain the above copyright 86899SN/A * notice, this list of conditions and the following disclaimer; 96899SN/A * redistributions in binary form must reproduce the above copyright 106899SN/A * notice, this list of conditions and the following disclaimer in the 116899SN/A * documentation and/or other materials provided with the distribution; 126899SN/A * neither the name of the copyright holders nor the names of its 136899SN/A * contributors may be used to endorse or promote products derived from 146899SN/A * this software without specific prior written permission. 156899SN/A * 166899SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176899SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186899SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196899SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206899SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216899SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226899SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236899SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246899SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256899SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266899SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276899SN/A * 286899SN/A * Authors: Steve Reinhardt 296899SN/A * Nathan Binkert 306899SN/A */ 316899SN/A 326899SN/A/* @file 336899SN/A * EventQueue interfaces 346899SN/A */ 356899SN/A 366899SN/A#ifndef __SIM_EVENTQ_HH__ 376899SN/A#define __SIM_EVENTQ_HH__ 386899SN/A 396899SN/A#include <assert.h> 406899SN/A 416899SN/A#include <algorithm> 426899SN/A#include <map> 436899SN/A#include <string> 446899SN/A#include <vector> 456899SN/A 466899SN/A#include "sim/host.hh" // for Tick 476899SN/A 486899SN/A#include "base/fast_alloc.hh" 496899SN/A#include "base/misc.hh" 506899SN/A#include "base/trace.hh" 517553SN/A#include "sim/serialize.hh" 527553SN/A 536899SN/Aclass EventQueue; // forward declaration 546899SN/A 557553SN/A////////////////////// 567553SN/A// 576899SN/A// Main Event Queue 586899SN/A// 597538SN/A// Events on this queue are processed at the *beginning* of each 606899SN/A// cycle, before the pipeline simulation is performed. 617538SN/A// 626899SN/A// defined in eventq.cc 636899SN/A// 646899SN/A////////////////////// 656899SN/Aextern EventQueue mainEventQueue; 666899SN/A 676899SN/A 686899SN/A/* 696899SN/A * An item on an event queue. The action caused by a given 706899SN/A * event is specified by deriving a subclass and overriding the 716899SN/A * process() member function. 727632SBrad.Beckmann@amd.com */ 736899SN/Aclass Event : public Serializable, public FastAlloc 747553SN/A{ 757553SN/A friend class EventQueue; 767553SN/A 777553SN/A private: 787553SN/A 797553SN/A#ifndef NDEBUG 807553SN/A /// Global counter to generate unique IDs for Event instances 817553SN/A static Counter instanceCounter; 827553SN/A 837632SBrad.Beckmann@amd.com /// This event's unique ID. We can also use pointer values for 847553SN/A /// this but they're not consistent across runs making debugging 856899SN/A /// more difficult. Thus we use a global counter value when 866899SN/A /// debugging. 876899SN/A Counter instanceId; 886899SN/A#endif // NDEBUG 896899SN/A 906899SN/A /// queue to which this event belongs (though it may or may not be 916899SN/A /// scheduled on this queue yet) 926899SN/A EventQueue *queue; 937553SN/A 947553SN/A Event *next; 957553SN/A 967553SN/A Tick _when; //!< timestamp when event should be processed 977553SN/A int _priority; //!< event priority 987632SBrad.Beckmann@amd.com char _flags; 997553SN/A 1007541SN/A protected: 1016899SN/A enum Flags { 1028322Ssteve.reinhardt@amd.com None = 0x0, 1036899SN/A Squashed = 0x1, 1048322Ssteve.reinhardt@amd.com Scheduled = 0x2, 1056899SN/A AutoDelete = 0x4, 1066899SN/A AutoSerialize = 0x8, 1076899SN/A IsExitEvent = 0x10 1087553SN/A }; 1096899SN/A 1106899SN/A bool getFlags(Flags f) const { return (_flags & f) == f; } 1116899SN/A void setFlags(Flags f) { _flags |= f; } 1126899SN/A void clearFlags(Flags f) { _flags &= ~f; } 1136899SN/A 1146899SN/A protected: 1156899SN/A EventQueue *theQueue() const { return queue; } 1166899SN/A 1176899SN/A#if TRACING_ON 1186899SN/A Tick when_created; //!< Keep track of creation time For debugging 1196899SN/A Tick when_scheduled; //!< Keep track of creation time For debugging 1206899SN/A 1217525SN/A virtual void trace(const char *action); //!< trace event activity 1226899SN/A#else 1236899SN/A void trace(const char *) {} 1246899SN/A#endif 1256899SN/A 1266899SN/A 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 void reschedule(Tick t); 214 215 /// Remove the event from the current schedule 216 void deschedule(); 217 218 /// Return a C string describing the event. This string should 219 /// *not* be dynamically allocated; just a const char array 220 /// describing the event class. 221 virtual const char *description(); 222 223 /// Dump the current event data 224 void dump(); 225 226 /* 227 * This member function is invoked when the event is processed 228 * (occurs). There is no default implementation; each subclass 229 * must provide its own implementation. The event is not 230 * automatically deleted after it is processed (to allow for 231 * statically allocated event objects). 232 * 233 * If the AutoDestroy flag is set, the object is deleted once it 234 * is processed. 235 */ 236 virtual void process() = 0; 237 238 void annotate(unsigned value) { annotated_value = value; }; 239 unsigned annotation() { return annotated_value; } 240 241 /// Squash the current event 242 void squash() { setFlags(Squashed); } 243 244 /// Check whether the event is squashed 245 bool squashed() { return getFlags(Squashed); } 246 247 /// See if this is a SimExitEvent (without resorting to RTTI) 248 bool isExitEvent() { return getFlags(IsExitEvent); } 249 250 /// Get the time that the event is scheduled 251 Tick when() const { return _when; } 252 253 /// Get the event priority 254 int priority() const { return _priority; } 255 256 struct priority_compare : 257 public std::binary_function<Event *, Event *, bool> 258 { 259 bool operator()(const Event *l, const Event *r) const { 260 return l->when() >= r->when() || l->priority() >= r->priority(); 261 } 262 }; 263 264 virtual void serialize(std::ostream &os); 265 virtual void unserialize(Checkpoint *cp, const std::string §ion); 266}; 267 268template <class T, void (T::* F)()> 269void 270DelayFunction(Tick when, T *object) 271{ 272 class DelayEvent : public Event 273 { 274 private: 275 T *object; 276 277 public: 278 DelayEvent(Tick when, T *o) 279 : Event(&mainEventQueue), object(o) 280 { setFlags(this->AutoDestroy); schedule(when); } 281 void process() { (object->*F)(); } 282 const char *description() { return "delay"; } 283 }; 284 285 new DelayEvent(when, object); 286} 287 288template <class T, void (T::* F)()> 289class EventWrapper : public Event 290{ 291 private: 292 T *object; 293 294 public: 295 EventWrapper(T *obj, bool del = false, EventQueue *q = &mainEventQueue, 296 Priority p = Default_Pri) 297 : Event(q, p), object(obj) 298 { 299 if (del) 300 setFlags(AutoDelete); 301 } 302 void process() { (object->*F)(); } 303}; 304 305/* 306 * Queue of events sorted in time order 307 */ 308class EventQueue : public Serializable 309{ 310 protected: 311 std::string objName; 312 313 private: 314 Event *head; 315 316 void insert(Event *event); 317 void remove(Event *event); 318 319 public: 320 321 // constructor 322 EventQueue(const std::string &n) 323 : objName(n), head(NULL) 324 {} 325 326 virtual const std::string name() const { return objName; } 327 328 // schedule the given event on this queue 329 void schedule(Event *ev); 330 void deschedule(Event *ev); 331 void reschedule(Event *ev); 332 333 Tick nextTick() { return head->when(); } 334 Event *serviceOne(); 335 336 // process all events up to the given timestamp. we inline a 337 // quick test to see if there are any events to process; if so, 338 // call the internal out-of-line version to process them all. 339 void serviceEvents(Tick when) { 340 while (!empty()) { 341 if (nextTick() > when) 342 break; 343 344 /** 345 * @todo this assert is a good bug catcher. I need to 346 * make it true again. 347 */ 348 //assert(head->when() >= when && "event scheduled in the past"); 349 serviceOne(); 350 } 351 } 352 353 // default: process all events up to 'now' (curTick) 354 void serviceEvents() { serviceEvents(curTick); } 355 356 // return true if no events are queued 357 bool empty() { return head == NULL; } 358 359 void dump(); 360 361 Tick nextEventTime() { return empty() ? curTick : head->when(); } 362 363 virtual void serialize(std::ostream &os); 364 virtual void unserialize(Checkpoint *cp, const std::string §ion); 365}; 366 367 368////////////////////// 369// 370// inline functions 371// 372// can't put these inside declaration due to circular dependence 373// between Event and EventQueue classes. 374// 375////////////////////// 376 377// schedule at specified time (place on event queue specified via 378// constructor) 379inline void 380Event::schedule(Tick t) 381{ 382 assert(!scheduled()); 383// if (t < curTick) 384// warn("t is less than curTick, ensure you don't want cycles"); 385 386 setFlags(Scheduled); 387#if TRACING_ON 388 when_scheduled = curTick; 389#endif 390 _when = t; 391 queue->schedule(this); 392} 393 394inline void 395Event::deschedule() 396{ 397 assert(scheduled()); 398 399 clearFlags(Squashed); 400 clearFlags(Scheduled); 401 queue->deschedule(this); 402} 403 404inline void 405Event::reschedule(Tick t) 406{ 407 assert(scheduled()); 408 clearFlags(Squashed); 409 410#if TRACING_ON 411 when_scheduled = curTick; 412#endif 413 _when = t; 414 queue->reschedule(this); 415} 416 417inline void 418EventQueue::schedule(Event *event) 419{ 420 insert(event); 421 if (DTRACE(Event)) 422 event->trace("scheduled"); 423} 424 425inline void 426EventQueue::deschedule(Event *event) 427{ 428 remove(event); 429 if (DTRACE(Event)) 430 event->trace("descheduled"); 431} 432 433inline void 434EventQueue::reschedule(Event *event) 435{ 436 remove(event); 437 insert(event); 438 if (DTRACE(Event)) 439 event->trace("rescheduled"); 440} 441 442 443 444#endif // __SIM_EVENTQ_HH__ 445