simulate.cc revision 9983
12207SN/A/*
22207SN/A * Copyright (c) 2006 The Regents of The University of Michigan
32207SN/A * Copyright (c) 2013 Advanced Micro Devices, Inc.
42207SN/A * Copyright (c) 2013 Mark D. Hill and David A. Wood
52207SN/A * All rights reserved.
62207SN/A *
72207SN/A * Redistribution and use in source and binary forms, with or without
82207SN/A * modification, are permitted provided that the following conditions are
92207SN/A * met: redistributions of source code must retain the above copyright
102207SN/A * notice, this list of conditions and the following disclaimer;
112207SN/A * redistributions in binary form must reproduce the above copyright
122207SN/A * notice, this list of conditions and the following disclaimer in the
132207SN/A * documentation and/or other materials provided with the distribution;
142207SN/A * neither the name of the copyright holders nor the names of its
152207SN/A * contributors may be used to endorse or promote products derived from
162207SN/A * this software without specific prior written permission.
172207SN/A *
182207SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
192207SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
202207SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
212207SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
222207SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
232207SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
242207SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
252207SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
262207SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
272665Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
282665Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
292665Ssaidi@eecs.umich.edu *
302207SN/A * Authors: Nathan Binkert
312207SN/A *          Steve Reinhardt
3211793Sbrandon.potter@amd.com */
3311793Sbrandon.potter@amd.com
342972Sgblack@eecs.umich.edu#include <mutex>
358229Snate@binkert.org#include <thread>
362454SN/A
3712334Sgabeblack@google.com#include "base/misc.hh"
382680Sktlim@umich.edu#include "base/pollevent.hh"
398232Snate@binkert.org#include "base/types.hh"
405759Shsul@eecs.umich.edu#include "sim/async.hh"
4112431Sgabeblack@google.com#include "sim/eventq_impl.hh"
4211854Sbrandon.potter@amd.com#include "sim/sim_events.hh"
437678Sgblack@eecs.umich.edu#include "sim/sim_exit.hh"
445759Shsul@eecs.umich.edu#include "sim/simulate.hh"
4511800Sbrandon.potter@amd.com#include "sim/stat_control.hh"
462474SN/A
472207SN/A//! Mutex for handling async events.
482474SN/Astd::mutex asyncEventMutex;
492474SN/A
502474SN/A//! Global barrier for synchronizing threads entering/exiting the
5111851Sbrandon.potter@amd.com//! simulation loop.
5212432Sgabeblack@google.comBarrier *threadBarrier;
5312432Sgabeblack@google.com
542474SN/A//! forward declaration
5512441Sgabeblack@google.comEvent *doSimLoop(EventQueue *);
5611905SBrandon.Potter@amd.com
5711905SBrandon.Potter@amd.com/**
5811905SBrandon.Potter@amd.com * The main function for all subordinate threads (i.e., all threads
592474SN/A * other than the main thread).  These threads start by waiting on
602474SN/A * threadBarrier.  Once all threads have arrived at threadBarrier,
612474SN/A * they enter the simulation loop concurrently.  When they exit the
6211905SBrandon.Potter@amd.com * loop, they return to waiting on threadBarrier.  This process is
632474SN/A * repeated until the simulation terminates.
6411905SBrandon.Potter@amd.com */
6511905SBrandon.Potter@amd.comstatic void
6611905SBrandon.Potter@amd.comthread_loop(EventQueue *queue)
6711905SBrandon.Potter@amd.com{
682474SN/A    while (true) {
692474SN/A        threadBarrier->wait();
7011905SBrandon.Potter@amd.com        doSimLoop(queue);
712474SN/A    }
7211905SBrandon.Potter@amd.com}
7311905SBrandon.Potter@amd.com
742474SN/A/** Simulate for num_cycles additional cycles.  If num_cycles is -1
752474SN/A * (the default), do not limit simulation; some other event must
762474SN/A * terminate the loop.  Exported to Python via SWIG.
7711851Sbrandon.potter@amd.com * @return The SimLoopExitEvent that caused the loop to exit.
785759Shsul@eecs.umich.edu */
7911389Sbrandon.potter@amd.comGlobalSimLoopExitEvent *
8011389Sbrandon.potter@amd.comsimulate(Tick num_cycles)
8111389Sbrandon.potter@amd.com{
825759Shsul@eecs.umich.edu    // The first time simulate() is called from the Python code, we need to
835759Shsul@eecs.umich.edu    // create a thread for each of event queues referenced by the
845771Shsul@eecs.umich.edu    // instantiated sim objects.
855759Shsul@eecs.umich.edu    static bool threads_initialized = false;
865759Shsul@eecs.umich.edu    static std::vector<std::thread *> threads;
875759Shsul@eecs.umich.edu
8811321Ssteve.reinhardt@amd.com    if (!threads_initialized) {
895759Shsul@eecs.umich.edu        threadBarrier = new Barrier(numMainEventQueues);
9011320Ssteve.reinhardt@amd.com
915759Shsul@eecs.umich.edu        // the main thread (the one we're currently running on)
925759Shsul@eecs.umich.edu        // handles queue 0, so we only need to allocate new threads
935759Shsul@eecs.umich.edu        // for queues 1..N-1.  We'll call these the "subordinate" threads.
945759Shsul@eecs.umich.edu        for (uint32_t i = 1; i < numMainEventQueues; i++) {
955759Shsul@eecs.umich.edu            threads.push_back(new std::thread(thread_loop, mainEventQueue[i]));
965759Shsul@eecs.umich.edu        }
975759Shsul@eecs.umich.edu
9810318Sandreas.hansson@arm.com        threads_initialized = true;
995759Shsul@eecs.umich.edu    }
1005759Shsul@eecs.umich.edu
1015759Shsul@eecs.umich.edu    inform("Entering event queue @ %d.  Starting simulation...\n", curTick());
1025759Shsul@eecs.umich.edu
10311389Sbrandon.potter@amd.com    if (num_cycles < MaxTick - curTick())
10411389Sbrandon.potter@amd.com        num_cycles = curTick() + num_cycles;
10511389Sbrandon.potter@amd.com    else // counter would roll over or be set to MaxTick anyhow
10611389Sbrandon.potter@amd.com        num_cycles = MaxTick;
1075759Shsul@eecs.umich.edu
1085759Shsul@eecs.umich.edu    GlobalEvent *limit_event = new GlobalSimLoopExitEvent(num_cycles,
1095759Shsul@eecs.umich.edu                                "simulate() limit reached", 0, 0);
1105759Shsul@eecs.umich.edu
1115759Shsul@eecs.umich.edu    GlobalSyncEvent *quantum_event = NULL;
1125759Shsul@eecs.umich.edu    if (numMainEventQueues > 1) {
1135759Shsul@eecs.umich.edu        if (simQuantum == 0) {
1145759Shsul@eecs.umich.edu            fatal("Quantum for multi-eventq simulation not specified");
1155759Shsul@eecs.umich.edu        }
1165759Shsul@eecs.umich.edu
1175759Shsul@eecs.umich.edu        quantum_event = new GlobalSyncEvent(simQuantum, simQuantum,
1185759Shsul@eecs.umich.edu                            EventBase::Progress_Event_Pri, 0);
1195759Shsul@eecs.umich.edu
1205759Shsul@eecs.umich.edu        inParallelMode = true;
1216227Snate@binkert.org    }
1225759Shsul@eecs.umich.edu
1235759Shsul@eecs.umich.edu    // all subordinate (created) threads should be waiting on the
1245759Shsul@eecs.umich.edu    // barrier; the arrival of the main thread here will satisfy the
1256227Snate@binkert.org    // barrier, and all threads will enter doSimLoop in parallel
1265759Shsul@eecs.umich.edu    threadBarrier->wait();
1275759Shsul@eecs.umich.edu    Event *local_event = doSimLoop(mainEventQueue[0]);
1285759Shsul@eecs.umich.edu    assert(local_event != NULL);
1295759Shsul@eecs.umich.edu
13011320Ssteve.reinhardt@amd.com    inParallelMode = false;
13111320Ssteve.reinhardt@amd.com
1325759Shsul@eecs.umich.edu    // locate the global exit event and return it to Python
13311320Ssteve.reinhardt@amd.com    BaseGlobalEvent *global_event = local_event->globalEvent();
1345759Shsul@eecs.umich.edu    assert(global_event != NULL);
1355759Shsul@eecs.umich.edu
1365759Shsul@eecs.umich.edu    GlobalSimLoopExitEvent *global_exit_event =
1375759Shsul@eecs.umich.edu        dynamic_cast<GlobalSimLoopExitEvent *>(global_event);
1385759Shsul@eecs.umich.edu    assert(global_exit_event != NULL);
1395759Shsul@eecs.umich.edu
14011905SBrandon.Potter@amd.com    // if we didn't hit limit_event, delete it.
1415759Shsul@eecs.umich.edu    if (global_exit_event != limit_event) {
14211905SBrandon.Potter@amd.com        assert(limit_event->scheduled());
14311905SBrandon.Potter@amd.com        limit_event->deschedule();
1445759Shsul@eecs.umich.edu        delete limit_event;
14511905SBrandon.Potter@amd.com    }
14611905SBrandon.Potter@amd.com
1475759Shsul@eecs.umich.edu    //! Delete the simulation quantum event.
1485759Shsul@eecs.umich.edu    if (quantum_event != NULL) {
14911905SBrandon.Potter@amd.com        quantum_event->deschedule();
1505759Shsul@eecs.umich.edu        delete quantum_event;
1515759Shsul@eecs.umich.edu    }
1525759Shsul@eecs.umich.edu
1535759Shsul@eecs.umich.edu    return global_exit_event;
1545759Shsul@eecs.umich.edu}
1555759Shsul@eecs.umich.edu
1565759Shsul@eecs.umich.edu/**
1575759Shsul@eecs.umich.edu * Test and clear the global async_event flag, such that each time the
1585759Shsul@eecs.umich.edu * flag is cleared, only one thread returns true (and thus is assigned
1595759Shsul@eecs.umich.edu * to handle the corresponding async event(s)).
1605759Shsul@eecs.umich.edu */
1615759Shsul@eecs.umich.edustatic bool
1625759Shsul@eecs.umich.edutestAndClearAsyncEvent()
1635759Shsul@eecs.umich.edu{
16411905SBrandon.Potter@amd.com    bool was_set = false;
1655759Shsul@eecs.umich.edu    asyncEventMutex.lock();
1665759Shsul@eecs.umich.edu
1675759Shsul@eecs.umich.edu    if (async_event) {
1685759Shsul@eecs.umich.edu        was_set = true;
1695759Shsul@eecs.umich.edu        async_event = false;
1706227Snate@binkert.org    }
1718852Sandreas.hansson@arm.com
1725759Shsul@eecs.umich.edu    asyncEventMutex.unlock();
1738852Sandreas.hansson@arm.com    return was_set;
1745759Shsul@eecs.umich.edu}
1755759Shsul@eecs.umich.edu
1765759Shsul@eecs.umich.edu/**
1775759Shsul@eecs.umich.edu * The main per-thread simulation loop. This loop is executed by all
1785759Shsul@eecs.umich.edu * simulation threads (the main thread and the subordinate threads) in
1795958Sgblack@eecs.umich.edu * parallel.
1805958Sgblack@eecs.umich.edu */
18111905SBrandon.Potter@amd.comEvent *
1825759Shsul@eecs.umich.edudoSimLoop(EventQueue *eventq)
18311389Sbrandon.potter@amd.com{
1845759Shsul@eecs.umich.edu    // set the per thread current eventq pointer
1855759Shsul@eecs.umich.edu    curEventQueue(eventq);
1865759Shsul@eecs.umich.edu    eventq->handleAsyncInsertions();
18711851Sbrandon.potter@amd.com
1882474SN/A    while (1) {
1896820SLisa.Hsu@amd.com        // there should always be at least one event (the SimLoopExitEvent
19011801Sbrandon.potter@amd.com        // we just scheduled) in the queue
1917532Ssteve.reinhardt@amd.com        assert(!eventq->empty());
1926820SLisa.Hsu@amd.com        assert(curTick() <= eventq->nextTick() &&
1935183Ssaidi@eecs.umich.edu               "event scheduled in the past");
1947532Ssteve.reinhardt@amd.com
19512186Sgabeblack@google.com        Event *exit_event = eventq->serviceOne();
1967532Ssteve.reinhardt@amd.com        if (exit_event != NULL) {
19712186Sgabeblack@google.com            return exit_event;
19811801Sbrandon.potter@amd.com        }
1997532Ssteve.reinhardt@amd.com
2007532Ssteve.reinhardt@amd.com        if (async_event && testAndClearAsyncEvent()) {
2017532Ssteve.reinhardt@amd.com            async_event = false;
2027532Ssteve.reinhardt@amd.com            if (async_statdump || async_statreset) {
2037532Ssteve.reinhardt@amd.com                Stats::schedStatEvent(async_statdump, async_statreset);
2047532Ssteve.reinhardt@amd.com                async_statdump = false;
20511851Sbrandon.potter@amd.com                async_statreset = false;
2067532Ssteve.reinhardt@amd.com            }
2077532Ssteve.reinhardt@amd.com
2087532Ssteve.reinhardt@amd.com            if (async_exit) {
2097532Ssteve.reinhardt@amd.com                async_exit = false;
2107532Ssteve.reinhardt@amd.com                exitSimLoop("user interrupt received");
21111851Sbrandon.potter@amd.com            }
2125759Shsul@eecs.umich.edu
21310318Sandreas.hansson@arm.com            if (async_io || async_alarm) {
2142474SN/A                async_io = false;
2157532Ssteve.reinhardt@amd.com                async_alarm = false;
2165713Shsul@eecs.umich.edu                pollQueue.service();
2175713Shsul@eecs.umich.edu            }
2187701Sgblack@eecs.umich.edu
2197701Sgblack@eecs.umich.edu            if (async_exception) {
2204997Sgblack@eecs.umich.edu                async_exception = false;
2215713Shsul@eecs.umich.edu                return NULL;
2222474SN/A            }
2232474SN/A        }
2245958Sgblack@eecs.umich.edu    }
22511851Sbrandon.potter@amd.com
2265958Sgblack@eecs.umich.edu    // not reached... only exit is return on SimLoopExitEvent
2275958Sgblack@eecs.umich.edu}
2286701Sgblack@eecs.umich.edu