19983Sstever@gmail.com/*
29983Sstever@gmail.com * Copyright (c) 2011-2013 Advanced Micro Devices, Inc.
39983Sstever@gmail.com * Copyright (c) 2013 Mark D. Hill and David A. Wood
49983Sstever@gmail.com * All rights reserved.
59983Sstever@gmail.com *
69983Sstever@gmail.com * Redistribution and use in source and binary forms, with or without
79983Sstever@gmail.com * modification, are permitted provided that the following conditions are
89983Sstever@gmail.com * met: redistributions of source code must retain the above copyright
99983Sstever@gmail.com * notice, this list of conditions and the following disclaimer;
109983Sstever@gmail.com * redistributions in binary form must reproduce the above copyright
119983Sstever@gmail.com * notice, this list of conditions and the following disclaimer in the
129983Sstever@gmail.com * documentation and/or other materials provided with the distribution;
139983Sstever@gmail.com * neither the name of the copyright holders nor the names of its
149983Sstever@gmail.com * contributors may be used to endorse or promote products derived from
159983Sstever@gmail.com * this software without specific prior written permission.
169983Sstever@gmail.com *
179983Sstever@gmail.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
189983Sstever@gmail.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
199983Sstever@gmail.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
209983Sstever@gmail.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
219983Sstever@gmail.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
229983Sstever@gmail.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
239983Sstever@gmail.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
249983Sstever@gmail.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
259983Sstever@gmail.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
269983Sstever@gmail.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
279983Sstever@gmail.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
289983Sstever@gmail.com *
299983Sstever@gmail.com * Authors: Steve Reinhardt
309983Sstever@gmail.com */
319983Sstever@gmail.com
329983Sstever@gmail.com#ifndef __SIM_GLOBAL_EVENT_HH__
339983Sstever@gmail.com#define __SIM_GLOBAL_EVENT_HH__
349983Sstever@gmail.com
359983Sstever@gmail.com#include <mutex>
369983Sstever@gmail.com#include <vector>
379983Sstever@gmail.com
389983Sstever@gmail.com#include "base/barrier.hh"
399983Sstever@gmail.com#include "sim/eventq_impl.hh"
409983Sstever@gmail.com
419983Sstever@gmail.com/**
429983Sstever@gmail.com * @file sim/global_event.hh
439983Sstever@gmail.com * Global events and related declarations.
449983Sstever@gmail.com *
459983Sstever@gmail.com * A global event is an event that occurs across all threads, i.e.,
469983Sstever@gmail.com * globally.  It consists of a set of "local" (regular) Events, one
479983Sstever@gmail.com * per thread/event queue, a barrier object, and common state.  The
489983Sstever@gmail.com * local events are scheduled for the same tick.  The local event
499983Sstever@gmail.com * process() method enters the barrier to wait for other threads; once
509983Sstever@gmail.com * all threads reach that tick (and enter the associated barrier), the
519983Sstever@gmail.com * global event is triggered and its associated activity is performed.
529983Sstever@gmail.com *
539983Sstever@gmail.com * There are two basic global event patterns, GlobalEvent and
549983Sstever@gmail.com * GlobalSyncEvent.  GlobalEvent is the base class for typical global
559983Sstever@gmail.com * events, while GlobalSyncEvent is optimized for global
569983Sstever@gmail.com * synchronization operations.
579983Sstever@gmail.com */
589983Sstever@gmail.com
599983Sstever@gmail.com/**
609983Sstever@gmail.com * Common base class for GlobalEvent and GlobalSyncEvent.
619983Sstever@gmail.com */
629983Sstever@gmail.comclass BaseGlobalEvent : public EventBase
639983Sstever@gmail.com{
649983Sstever@gmail.com  private:
659983Sstever@gmail.com      //! Mutex variable for providing exculsive right to schedule global
669983Sstever@gmail.com      //! events. This is necessary so that a total order can be maintained
679983Sstever@gmail.com      //! amongst the global events. Without ensuring the total order, it is
689983Sstever@gmail.com      //! possible that threads execute global events in different orders,
699983Sstever@gmail.com      //! which can result in a deadlock.
709983Sstever@gmail.com      static std::mutex globalQMutex;
719983Sstever@gmail.com
729983Sstever@gmail.com  protected:
739983Sstever@gmail.com
749983Sstever@gmail.com    /// The base class for the local events that will synchronize
759983Sstever@gmail.com    /// threads to perform the global event.  This class is abstract,
769983Sstever@gmail.com    /// since it derives from the abstract Event class but still does
779983Sstever@gmail.com    /// not define the required process() method.
789983Sstever@gmail.com    class BarrierEvent : public Event
799983Sstever@gmail.com    {
809983Sstever@gmail.com      protected:
819983Sstever@gmail.com        BaseGlobalEvent *_globalEvent;
829983Sstever@gmail.com
839983Sstever@gmail.com        BarrierEvent(BaseGlobalEvent *global_event, Priority p, Flags f)
849983Sstever@gmail.com            : Event(p, f), _globalEvent(global_event)
859983Sstever@gmail.com        {
869983Sstever@gmail.com        }
879983Sstever@gmail.com
889983Sstever@gmail.com        ~BarrierEvent();
899983Sstever@gmail.com
909983Sstever@gmail.com        friend class BaseGlobalEvent;
919983Sstever@gmail.com
929983Sstever@gmail.com        bool globalBarrier()
939983Sstever@gmail.com        {
9410153Sandreas@sandberg.pp.se            // This method will be called from the process() method in
9510153Sandreas@sandberg.pp.se            // the local barrier events
9610153Sandreas@sandberg.pp.se            // (GlobalSyncEvent::BarrierEvent).  The local event
9710153Sandreas@sandberg.pp.se            // queues are always locked when servicing events (calling
9810153Sandreas@sandberg.pp.se            // the process() method), which means that it will be
9910153Sandreas@sandberg.pp.se            // locked when entering this method. We need to unlock it
10010153Sandreas@sandberg.pp.se            // while waiting on the barrier to prevent deadlocks if
10110153Sandreas@sandberg.pp.se            // another thread wants to lock the event queue.
10210153Sandreas@sandberg.pp.se            EventQueue::ScopedRelease release(curEventQueue());
10310361SAndreas.Sandberg@ARM.com            return _globalEvent->barrier.wait();
1049983Sstever@gmail.com        }
1059983Sstever@gmail.com
1069983Sstever@gmail.com      public:
1079983Sstever@gmail.com        virtual BaseGlobalEvent *globalEvent() { return _globalEvent; }
1089983Sstever@gmail.com    };
1099983Sstever@gmail.com
1109983Sstever@gmail.com    //! The barrier that all threads wait on before performing the
1119983Sstever@gmail.com    //! global event.
11210361SAndreas.Sandberg@ARM.com    Barrier barrier;
1139983Sstever@gmail.com
1149983Sstever@gmail.com    //! The individual local event instances (one per thread/event queue).
1159983Sstever@gmail.com    std::vector<BarrierEvent *> barrierEvent;
1169983Sstever@gmail.com
1179983Sstever@gmail.com  public:
1189983Sstever@gmail.com    BaseGlobalEvent(Priority p, Flags f);
1199983Sstever@gmail.com
1209983Sstever@gmail.com    virtual ~BaseGlobalEvent();
1219983Sstever@gmail.com
1229983Sstever@gmail.com    virtual void process() = 0;
1239983Sstever@gmail.com
1249983Sstever@gmail.com    virtual const char *description() const = 0;
1259983Sstever@gmail.com
1269983Sstever@gmail.com    void schedule(Tick when);
1279983Sstever@gmail.com
1289983Sstever@gmail.com    bool scheduled() const
1299983Sstever@gmail.com    {
1309983Sstever@gmail.com        bool sched = false;
1319983Sstever@gmail.com        for (uint32_t i = 0; i < numMainEventQueues; ++i) {
1329983Sstever@gmail.com            sched = sched || barrierEvent[i]->scheduled();
1339983Sstever@gmail.com        }
1349983Sstever@gmail.com
1359983Sstever@gmail.com        return sched;
1369983Sstever@gmail.com    }
1379983Sstever@gmail.com
1389983Sstever@gmail.com    Tick when() const
1399983Sstever@gmail.com    {
1409983Sstever@gmail.com        assert(numMainEventQueues > 0);
1419983Sstever@gmail.com        return barrierEvent[0]->when();
1429983Sstever@gmail.com    }
1439983Sstever@gmail.com
1449983Sstever@gmail.com    void deschedule();
1459983Sstever@gmail.com    void reschedule(Tick when);
1469983Sstever@gmail.com};
1479983Sstever@gmail.com
1489983Sstever@gmail.com
1499983Sstever@gmail.com/**
1509983Sstever@gmail.com * Funky intermediate class to support CRTP so that we can have a
1519983Sstever@gmail.com * common constructor to create the local events, even though the
1529983Sstever@gmail.com * types of the local events are defined in the derived classes.
1539983Sstever@gmail.com */
1549983Sstever@gmail.comtemplate <class Derived>
1559983Sstever@gmail.comclass BaseGlobalEventTemplate : public BaseGlobalEvent
1569983Sstever@gmail.com{
1579983Sstever@gmail.com  protected:
1589983Sstever@gmail.com    BaseGlobalEventTemplate(Priority p, Flags f)
1599983Sstever@gmail.com        : BaseGlobalEvent(p, f)
1609983Sstever@gmail.com    {
1619983Sstever@gmail.com        for (int i = 0; i < numMainEventQueues; ++i)
1629983Sstever@gmail.com            barrierEvent[i] = new typename Derived::BarrierEvent(this, p, f);
1639983Sstever@gmail.com    }
1649983Sstever@gmail.com};
1659983Sstever@gmail.com
1669983Sstever@gmail.com
1679983Sstever@gmail.com/**
1689983Sstever@gmail.com * The main global event class.  Ordinary global events should derive
1699983Sstever@gmail.com * from this class, and define process() to specify the action to be
1709983Sstever@gmail.com * taken when the event is reached.  All threads will synchronize at a
1719983Sstever@gmail.com * barrier, exactly one of the threads will execute the process()
1729983Sstever@gmail.com * method, then the threads will synchronize again so that none of
1739983Sstever@gmail.com * them continue until process() is complete.
1749983Sstever@gmail.com */
1759983Sstever@gmail.comclass GlobalEvent : public BaseGlobalEventTemplate<GlobalEvent>
1769983Sstever@gmail.com{
1779983Sstever@gmail.com  public:
1789983Sstever@gmail.com    typedef BaseGlobalEventTemplate<GlobalEvent> Base;
1799983Sstever@gmail.com
1809983Sstever@gmail.com    class BarrierEvent : public Base::BarrierEvent
1819983Sstever@gmail.com    {
1829983Sstever@gmail.com      public:
1839983Sstever@gmail.com        void process();
1849983Sstever@gmail.com        BarrierEvent(Base *global_event, Priority p, Flags f)
1859983Sstever@gmail.com            : Base::BarrierEvent(global_event, p, f)
1869983Sstever@gmail.com        { }
1879983Sstever@gmail.com    };
1889983Sstever@gmail.com
1899983Sstever@gmail.com    GlobalEvent(Priority p, Flags f)
1909983Sstever@gmail.com        : Base(p, f)
1919983Sstever@gmail.com    { }
1929983Sstever@gmail.com
1939983Sstever@gmail.com    GlobalEvent(Tick when, Priority p, Flags f)
1949983Sstever@gmail.com        : Base(p, f)
1959983Sstever@gmail.com    {
1969983Sstever@gmail.com        schedule(when);
1979983Sstever@gmail.com    }
1989983Sstever@gmail.com
1999983Sstever@gmail.com    virtual void process() = 0;
2009983Sstever@gmail.com};
2019983Sstever@gmail.com
2029983Sstever@gmail.com/**
2039983Sstever@gmail.com * A special global event that synchronizes all threads and forces
2049983Sstever@gmail.com * them to process asynchronously enqueued events.  Useful for
2059983Sstever@gmail.com * separating quanta in a quantum-based parallel simulation.
2069983Sstever@gmail.com */
2079983Sstever@gmail.comclass GlobalSyncEvent : public BaseGlobalEventTemplate<GlobalSyncEvent>
2089983Sstever@gmail.com{
2099983Sstever@gmail.com  public:
2109983Sstever@gmail.com    typedef BaseGlobalEventTemplate<GlobalSyncEvent> Base;
2119983Sstever@gmail.com
2129983Sstever@gmail.com    class BarrierEvent : public Base::BarrierEvent
2139983Sstever@gmail.com    {
2149983Sstever@gmail.com      public:
2159983Sstever@gmail.com        void process();
2169983Sstever@gmail.com        BarrierEvent(Base *global_event, Priority p, Flags f)
2179983Sstever@gmail.com            : Base::BarrierEvent(global_event, p, f)
2189983Sstever@gmail.com        { }
2199983Sstever@gmail.com    };
2209983Sstever@gmail.com
2219983Sstever@gmail.com    GlobalSyncEvent(Priority p, Flags f)
22211290Sgabor.dozsa@arm.com        : Base(p, f), repeat(0)
2239983Sstever@gmail.com    { }
2249983Sstever@gmail.com
2259983Sstever@gmail.com    GlobalSyncEvent(Tick when, Tick _repeat, Priority p, Flags f)
2269983Sstever@gmail.com        : Base(p, f), repeat(_repeat)
2279983Sstever@gmail.com    {
2289983Sstever@gmail.com        schedule(when);
2299983Sstever@gmail.com    }
2309983Sstever@gmail.com
2319983Sstever@gmail.com    void process();
2329983Sstever@gmail.com
2339983Sstever@gmail.com    const char *description() const;
2349983Sstever@gmail.com
2359983Sstever@gmail.com    Tick repeat;
2369983Sstever@gmail.com};
2379983Sstever@gmail.com
2389983Sstever@gmail.com
2399983Sstever@gmail.com#endif // __SIM_GLOBAL_EVENT_HH__
240