global_event.hh revision 11290:1640dd68b0a4
16691Stjones1@inf.ed.ac.uk/* 26691Stjones1@inf.ed.ac.uk * Copyright (c) 2011-2013 Advanced Micro Devices, Inc. 36691Stjones1@inf.ed.ac.uk * Copyright (c) 2013 Mark D. Hill and David A. Wood 46691Stjones1@inf.ed.ac.uk * All rights reserved. 56691Stjones1@inf.ed.ac.uk * 66691Stjones1@inf.ed.ac.uk * Redistribution and use in source and binary forms, with or without 76691Stjones1@inf.ed.ac.uk * modification, are permitted provided that the following conditions are 86691Stjones1@inf.ed.ac.uk * met: redistributions of source code must retain the above copyright 96691Stjones1@inf.ed.ac.uk * notice, this list of conditions and the following disclaimer; 106691Stjones1@inf.ed.ac.uk * redistributions in binary form must reproduce the above copyright 116691Stjones1@inf.ed.ac.uk * notice, this list of conditions and the following disclaimer in the 126691Stjones1@inf.ed.ac.uk * documentation and/or other materials provided with the distribution; 136691Stjones1@inf.ed.ac.uk * neither the name of the copyright holders nor the names of its 146691Stjones1@inf.ed.ac.uk * contributors may be used to endorse or promote products derived from 156691Stjones1@inf.ed.ac.uk * this software without specific prior written permission. 166691Stjones1@inf.ed.ac.uk * 176691Stjones1@inf.ed.ac.uk * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 186691Stjones1@inf.ed.ac.uk * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 196691Stjones1@inf.ed.ac.uk * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 206691Stjones1@inf.ed.ac.uk * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 216691Stjones1@inf.ed.ac.uk * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 226691Stjones1@inf.ed.ac.uk * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 236691Stjones1@inf.ed.ac.uk * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 246691Stjones1@inf.ed.ac.uk * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 256691Stjones1@inf.ed.ac.uk * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 266691Stjones1@inf.ed.ac.uk * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 276691Stjones1@inf.ed.ac.uk * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 286691Stjones1@inf.ed.ac.uk * 296691Stjones1@inf.ed.ac.uk * Authors: Steve Reinhardt 306691Stjones1@inf.ed.ac.uk */ 316691Stjones1@inf.ed.ac.uk 326691Stjones1@inf.ed.ac.uk#ifndef __SIM_GLOBAL_EVENT_HH__ 336691Stjones1@inf.ed.ac.uk#define __SIM_GLOBAL_EVENT_HH__ 346691Stjones1@inf.ed.ac.uk 356691Stjones1@inf.ed.ac.uk#include <mutex> 366691Stjones1@inf.ed.ac.uk#include <vector> 376691Stjones1@inf.ed.ac.uk 386691Stjones1@inf.ed.ac.uk#include "base/barrier.hh" 396691Stjones1@inf.ed.ac.uk#include "sim/eventq_impl.hh" 406691Stjones1@inf.ed.ac.uk 416691Stjones1@inf.ed.ac.uk/** 426691Stjones1@inf.ed.ac.uk * @file sim/global_event.hh 436691Stjones1@inf.ed.ac.uk * Global events and related declarations. 446691Stjones1@inf.ed.ac.uk * 456691Stjones1@inf.ed.ac.uk * A global event is an event that occurs across all threads, i.e., 466691Stjones1@inf.ed.ac.uk * globally. It consists of a set of "local" (regular) Events, one 476691Stjones1@inf.ed.ac.uk * per thread/event queue, a barrier object, and common state. The 486691Stjones1@inf.ed.ac.uk * local events are scheduled for the same tick. The local event 496691Stjones1@inf.ed.ac.uk * process() method enters the barrier to wait for other threads; once 506691Stjones1@inf.ed.ac.uk * all threads reach that tick (and enter the associated barrier), the 516691Stjones1@inf.ed.ac.uk * global event is triggered and its associated activity is performed. 526691Stjones1@inf.ed.ac.uk * 536691Stjones1@inf.ed.ac.uk * There are two basic global event patterns, GlobalEvent and 546691Stjones1@inf.ed.ac.uk * GlobalSyncEvent. GlobalEvent is the base class for typical global 556691Stjones1@inf.ed.ac.uk * events, while GlobalSyncEvent is optimized for global 566691Stjones1@inf.ed.ac.uk * synchronization operations. 576691Stjones1@inf.ed.ac.uk */ 586691Stjones1@inf.ed.ac.uk 596691Stjones1@inf.ed.ac.uk/** 606691Stjones1@inf.ed.ac.uk * Common base class for GlobalEvent and GlobalSyncEvent. 616691Stjones1@inf.ed.ac.uk */ 626691Stjones1@inf.ed.ac.ukclass BaseGlobalEvent : public EventBase 636691Stjones1@inf.ed.ac.uk{ 646691Stjones1@inf.ed.ac.uk private: 656691Stjones1@inf.ed.ac.uk //! Mutex variable for providing exculsive right to schedule global 666691Stjones1@inf.ed.ac.uk //! events. This is necessary so that a total order can be maintained 676691Stjones1@inf.ed.ac.uk //! amongst the global events. Without ensuring the total order, it is 686691Stjones1@inf.ed.ac.uk //! possible that threads execute global events in different orders, 696691Stjones1@inf.ed.ac.uk //! which can result in a deadlock. 706691Stjones1@inf.ed.ac.uk static std::mutex globalQMutex; 716691Stjones1@inf.ed.ac.uk 726691Stjones1@inf.ed.ac.uk protected: 736691Stjones1@inf.ed.ac.uk 746691Stjones1@inf.ed.ac.uk /// The base class for the local events that will synchronize 756691Stjones1@inf.ed.ac.uk /// threads to perform the global event. This class is abstract, 766691Stjones1@inf.ed.ac.uk /// since it derives from the abstract Event class but still does 776691Stjones1@inf.ed.ac.uk /// not define the required process() method. 786691Stjones1@inf.ed.ac.uk class BarrierEvent : public Event 796691Stjones1@inf.ed.ac.uk { 806691Stjones1@inf.ed.ac.uk protected: 816691Stjones1@inf.ed.ac.uk BaseGlobalEvent *_globalEvent; 826691Stjones1@inf.ed.ac.uk 836691Stjones1@inf.ed.ac.uk BarrierEvent(BaseGlobalEvent *global_event, Priority p, Flags f) 846691Stjones1@inf.ed.ac.uk : 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), repeat(0) 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