global_event.hh revision 10153
1/* 2 * Copyright (c) 2011-2013 Advanced Micro Devices, Inc. 3 * Copyright (c) 2013 Mark D. Hill and David A. Wood 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer; 10 * redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution; 13 * neither the name of the copyright holders nor the names of its 14 * contributors may be used to endorse or promote products derived from 15 * this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * Authors: Steve Reinhardt 30 */ 31 32#ifndef __SIM_GLOBAL_EVENT_HH__ 33#define __SIM_GLOBAL_EVENT_HH__ 34 35#include <mutex> 36#include <vector> 37 38#include "base/barrier.hh" 39#include "sim/eventq_impl.hh" 40 41/** 42 * @file sim/global_event.hh 43 * Global events and related declarations. 44 * 45 * A global event is an event that occurs across all threads, i.e., 46 * globally. It consists of a set of "local" (regular) Events, one 47 * per thread/event queue, a barrier object, and common state. The 48 * local events are scheduled for the same tick. The local event 49 * process() method enters the barrier to wait for other threads; once 50 * all threads reach that tick (and enter the associated barrier), the 51 * global event is triggered and its associated activity is performed. 52 * 53 * There are two basic global event patterns, GlobalEvent and 54 * GlobalSyncEvent. GlobalEvent is the base class for typical global 55 * events, while GlobalSyncEvent is optimized for global 56 * synchronization operations. 57 */ 58 59/** 60 * Common base class for GlobalEvent and GlobalSyncEvent. 61 */ 62class BaseGlobalEvent : public EventBase 63{ 64 private: 65 //! Mutex variable for providing exculsive right to schedule global 66 //! events. This is necessary so that a total order can be maintained 67 //! amongst the global events. Without ensuring the total order, it is 68 //! possible that threads execute global events in different orders, 69 //! which can result in a deadlock. 70 static std::mutex globalQMutex; 71 72 protected: 73 74 /// The base class for the local events that will synchronize 75 /// threads to perform the global event. This class is abstract, 76 /// since it derives from the abstract Event class but still does 77 /// not define the required process() method. 78 class BarrierEvent : public Event 79 { 80 protected: 81 BaseGlobalEvent *_globalEvent; 82 83 BarrierEvent(BaseGlobalEvent *global_event, Priority p, Flags f) 84 : Event(p, f), _globalEvent(global_event) 85 { 86 } 87 88 ~BarrierEvent(); 89 90 friend class BaseGlobalEvent; 91 92 bool globalBarrier() 93 { 94 // This method will be called from the process() method in 95 // the local barrier events 96 // (GlobalSyncEvent::BarrierEvent). The local event 97 // queues are always locked when servicing events (calling 98 // the process() method), which means that it will be 99 // locked when entering this method. We need to unlock it 100 // while waiting on the barrier to prevent deadlocks if 101 // another thread wants to lock the event queue. 102 EventQueue::ScopedRelease release(curEventQueue()); 103 return _globalEvent->barrier->wait(); 104 } 105 106 public: 107 virtual BaseGlobalEvent *globalEvent() { return _globalEvent; } 108 }; 109 110 //! The barrier that all threads wait on before performing the 111 //! global event. 112 Barrier *barrier; 113 114 //! The individual local event instances (one per thread/event queue). 115 std::vector<BarrierEvent *> barrierEvent; 116 117 public: 118 BaseGlobalEvent(Priority p, Flags f); 119 120 virtual ~BaseGlobalEvent(); 121 122 virtual void process() = 0; 123 124 virtual const char *description() const = 0; 125 126 void schedule(Tick when); 127 128 bool scheduled() const 129 { 130 bool sched = false; 131 for (uint32_t i = 0; i < numMainEventQueues; ++i) { 132 sched = sched || barrierEvent[i]->scheduled(); 133 } 134 135 return sched; 136 } 137 138 Tick when() const 139 { 140 assert(numMainEventQueues > 0); 141 return barrierEvent[0]->when(); 142 } 143 144 void deschedule(); 145 void reschedule(Tick when); 146}; 147 148 149/** 150 * Funky intermediate class to support CRTP so that we can have a 151 * common constructor to create the local events, even though the 152 * types of the local events are defined in the derived classes. 153 */ 154template <class Derived> 155class BaseGlobalEventTemplate : public BaseGlobalEvent 156{ 157 protected: 158 BaseGlobalEventTemplate(Priority p, Flags f) 159 : BaseGlobalEvent(p, f) 160 { 161 for (int i = 0; i < numMainEventQueues; ++i) 162 barrierEvent[i] = new typename Derived::BarrierEvent(this, p, f); 163 } 164}; 165 166 167/** 168 * The main global event class. Ordinary global events should derive 169 * from this class, and define process() to specify the action to be 170 * taken when the event is reached. All threads will synchronize at a 171 * barrier, exactly one of the threads will execute the process() 172 * method, then the threads will synchronize again so that none of 173 * them continue until process() is complete. 174 */ 175class GlobalEvent : public BaseGlobalEventTemplate<GlobalEvent> 176{ 177 public: 178 typedef BaseGlobalEventTemplate<GlobalEvent> Base; 179 180 class BarrierEvent : public Base::BarrierEvent 181 { 182 public: 183 void process(); 184 BarrierEvent(Base *global_event, Priority p, Flags f) 185 : Base::BarrierEvent(global_event, p, f) 186 { } 187 }; 188 189 GlobalEvent(Priority p, Flags f) 190 : Base(p, f) 191 { } 192 193 GlobalEvent(Tick when, Priority p, Flags f) 194 : Base(p, f) 195 { 196 schedule(when); 197 } 198 199 virtual void process() = 0; 200}; 201 202/** 203 * A special global event that synchronizes all threads and forces 204 * them to process asynchronously enqueued events. Useful for 205 * separating quanta in a quantum-based parallel simulation. 206 */ 207class GlobalSyncEvent : public BaseGlobalEventTemplate<GlobalSyncEvent> 208{ 209 public: 210 typedef BaseGlobalEventTemplate<GlobalSyncEvent> Base; 211 212 class BarrierEvent : public Base::BarrierEvent 213 { 214 public: 215 void process(); 216 BarrierEvent(Base *global_event, Priority p, Flags f) 217 : Base::BarrierEvent(global_event, p, f) 218 { } 219 }; 220 221 GlobalSyncEvent(Priority p, Flags f) 222 : Base(p, f) 223 { } 224 225 GlobalSyncEvent(Tick when, Tick _repeat, Priority p, Flags f) 226 : Base(p, f), repeat(_repeat) 227 { 228 schedule(when); 229 } 230 231 void process(); 232 233 const char *description() const; 234 235 Tick repeat; 236}; 237 238 239#endif // __SIM_GLOBAL_EVENT_HH__ 240