simulate.cc revision 10756
14123Sbinkertn@umich.edu/*
24123Sbinkertn@umich.edu * Copyright (c) 2006 The Regents of The University of Michigan
39983Sstever@gmail.com * Copyright (c) 2013 Advanced Micro Devices, Inc.
49983Sstever@gmail.com * Copyright (c) 2013 Mark D. Hill and David A. Wood
54123Sbinkertn@umich.edu * All rights reserved.
64123Sbinkertn@umich.edu *
74123Sbinkertn@umich.edu * Redistribution and use in source and binary forms, with or without
84123Sbinkertn@umich.edu * modification, are permitted provided that the following conditions are
94123Sbinkertn@umich.edu * met: redistributions of source code must retain the above copyright
104123Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer;
114123Sbinkertn@umich.edu * redistributions in binary form must reproduce the above copyright
124123Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer in the
134123Sbinkertn@umich.edu * documentation and/or other materials provided with the distribution;
144123Sbinkertn@umich.edu * neither the name of the copyright holders nor the names of its
154123Sbinkertn@umich.edu * contributors may be used to endorse or promote products derived from
164123Sbinkertn@umich.edu * this software without specific prior written permission.
174123Sbinkertn@umich.edu *
184123Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
194123Sbinkertn@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
204123Sbinkertn@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
214123Sbinkertn@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
224123Sbinkertn@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
234123Sbinkertn@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
244123Sbinkertn@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
254123Sbinkertn@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
264123Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
274123Sbinkertn@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
284123Sbinkertn@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
294123Sbinkertn@umich.edu *
304123Sbinkertn@umich.edu * Authors: Nathan Binkert
314123Sbinkertn@umich.edu *          Steve Reinhardt
324123Sbinkertn@umich.edu */
334123Sbinkertn@umich.edu
349983Sstever@gmail.com#include <mutex>
359983Sstever@gmail.com#include <thread>
369983Sstever@gmail.com
374123Sbinkertn@umich.edu#include "base/misc.hh"
384123Sbinkertn@umich.edu#include "base/pollevent.hh"
396216Snate@binkert.org#include "base/types.hh"
404123Sbinkertn@umich.edu#include "sim/async.hh"
419356Snilay@cs.wisc.edu#include "sim/eventq_impl.hh"
424123Sbinkertn@umich.edu#include "sim/sim_events.hh"
434123Sbinkertn@umich.edu#include "sim/sim_exit.hh"
444123Sbinkertn@umich.edu#include "sim/simulate.hh"
456216Snate@binkert.org#include "sim/stat_control.hh"
464123Sbinkertn@umich.edu
479983Sstever@gmail.com//! Mutex for handling async events.
489983Sstever@gmail.comstd::mutex asyncEventMutex;
499983Sstever@gmail.com
509983Sstever@gmail.com//! Global barrier for synchronizing threads entering/exiting the
519983Sstever@gmail.com//! simulation loop.
529983Sstever@gmail.comBarrier *threadBarrier;
539983Sstever@gmail.com
549983Sstever@gmail.com//! forward declaration
559983Sstever@gmail.comEvent *doSimLoop(EventQueue *);
569983Sstever@gmail.com
579983Sstever@gmail.com/**
589983Sstever@gmail.com * The main function for all subordinate threads (i.e., all threads
599983Sstever@gmail.com * other than the main thread).  These threads start by waiting on
609983Sstever@gmail.com * threadBarrier.  Once all threads have arrived at threadBarrier,
619983Sstever@gmail.com * they enter the simulation loop concurrently.  When they exit the
629983Sstever@gmail.com * loop, they return to waiting on threadBarrier.  This process is
639983Sstever@gmail.com * repeated until the simulation terminates.
649983Sstever@gmail.com */
659983Sstever@gmail.comstatic void
669983Sstever@gmail.comthread_loop(EventQueue *queue)
679983Sstever@gmail.com{
689983Sstever@gmail.com    while (true) {
699983Sstever@gmail.com        threadBarrier->wait();
709983Sstever@gmail.com        doSimLoop(queue);
719983Sstever@gmail.com    }
729983Sstever@gmail.com}
739983Sstever@gmail.com
7410756SCurtis.Dunham@arm.comGlobalEvent*
7510756SCurtis.Dunham@arm.comgetLimitEvent(void) {
7610756SCurtis.Dunham@arm.com    static GlobalSimLoopExitEvent
7710756SCurtis.Dunham@arm.com           simulate_limit_event(mainEventQueue[0]->getCurTick(),
7810756SCurtis.Dunham@arm.com                                "simulate() limit reached", 0);
7910756SCurtis.Dunham@arm.com    return &simulate_limit_event;
8010756SCurtis.Dunham@arm.com}
8110756SCurtis.Dunham@arm.com
824123Sbinkertn@umich.edu/** Simulate for num_cycles additional cycles.  If num_cycles is -1
834123Sbinkertn@umich.edu * (the default), do not limit simulation; some other event must
844123Sbinkertn@umich.edu * terminate the loop.  Exported to Python via SWIG.
854123Sbinkertn@umich.edu * @return The SimLoopExitEvent that caused the loop to exit.
864123Sbinkertn@umich.edu */
879983Sstever@gmail.comGlobalSimLoopExitEvent *
884123Sbinkertn@umich.edusimulate(Tick num_cycles)
894123Sbinkertn@umich.edu{
909983Sstever@gmail.com    // The first time simulate() is called from the Python code, we need to
919983Sstever@gmail.com    // create a thread for each of event queues referenced by the
929983Sstever@gmail.com    // instantiated sim objects.
939983Sstever@gmail.com    static bool threads_initialized = false;
949983Sstever@gmail.com    static std::vector<std::thread *> threads;
959983Sstever@gmail.com
969983Sstever@gmail.com    if (!threads_initialized) {
979983Sstever@gmail.com        threadBarrier = new Barrier(numMainEventQueues);
989983Sstever@gmail.com
999983Sstever@gmail.com        // the main thread (the one we're currently running on)
1009983Sstever@gmail.com        // handles queue 0, so we only need to allocate new threads
1019983Sstever@gmail.com        // for queues 1..N-1.  We'll call these the "subordinate" threads.
1029983Sstever@gmail.com        for (uint32_t i = 1; i < numMainEventQueues; i++) {
1039983Sstever@gmail.com            threads.push_back(new std::thread(thread_loop, mainEventQueue[i]));
1049983Sstever@gmail.com        }
1059983Sstever@gmail.com
1069983Sstever@gmail.com        threads_initialized = true;
1079983Sstever@gmail.com    }
1089983Sstever@gmail.com
1097823Ssteve.reinhardt@amd.com    inform("Entering event queue @ %d.  Starting simulation...\n", curTick());
1104123Sbinkertn@umich.edu
1119174Satgutier@umich.edu    if (num_cycles < MaxTick - curTick())
1129174Satgutier@umich.edu        num_cycles = curTick() + num_cycles;
1139174Satgutier@umich.edu    else // counter would roll over or be set to MaxTick anyhow
1144123Sbinkertn@umich.edu        num_cycles = MaxTick;
1154123Sbinkertn@umich.edu
11610756SCurtis.Dunham@arm.com    getLimitEvent()->reschedule(num_cycles);
1179983Sstever@gmail.com
1189983Sstever@gmail.com    GlobalSyncEvent *quantum_event = NULL;
1199983Sstever@gmail.com    if (numMainEventQueues > 1) {
1209983Sstever@gmail.com        if (simQuantum == 0) {
1219983Sstever@gmail.com            fatal("Quantum for multi-eventq simulation not specified");
1229983Sstever@gmail.com        }
1239983Sstever@gmail.com
12410101Sandreas@sandberg.pp.se        quantum_event = new GlobalSyncEvent(curTick() + simQuantum, simQuantum,
1259983Sstever@gmail.com                            EventBase::Progress_Event_Pri, 0);
1269983Sstever@gmail.com
1279983Sstever@gmail.com        inParallelMode = true;
1289983Sstever@gmail.com    }
1299983Sstever@gmail.com
1309983Sstever@gmail.com    // all subordinate (created) threads should be waiting on the
1319983Sstever@gmail.com    // barrier; the arrival of the main thread here will satisfy the
1329983Sstever@gmail.com    // barrier, and all threads will enter doSimLoop in parallel
1339983Sstever@gmail.com    threadBarrier->wait();
1349983Sstever@gmail.com    Event *local_event = doSimLoop(mainEventQueue[0]);
1359983Sstever@gmail.com    assert(local_event != NULL);
1369983Sstever@gmail.com
1379983Sstever@gmail.com    inParallelMode = false;
1389983Sstever@gmail.com
1399983Sstever@gmail.com    // locate the global exit event and return it to Python
1409983Sstever@gmail.com    BaseGlobalEvent *global_event = local_event->globalEvent();
1419983Sstever@gmail.com    assert(global_event != NULL);
1429983Sstever@gmail.com
1439983Sstever@gmail.com    GlobalSimLoopExitEvent *global_exit_event =
1449983Sstever@gmail.com        dynamic_cast<GlobalSimLoopExitEvent *>(global_event);
1459983Sstever@gmail.com    assert(global_exit_event != NULL);
1469983Sstever@gmail.com
1479983Sstever@gmail.com    //! Delete the simulation quantum event.
1489983Sstever@gmail.com    if (quantum_event != NULL) {
1499983Sstever@gmail.com        quantum_event->deschedule();
1509983Sstever@gmail.com        delete quantum_event;
1519983Sstever@gmail.com    }
1529983Sstever@gmail.com
1539983Sstever@gmail.com    return global_exit_event;
1549983Sstever@gmail.com}
1559983Sstever@gmail.com
1569983Sstever@gmail.com/**
1579983Sstever@gmail.com * Test and clear the global async_event flag, such that each time the
1589983Sstever@gmail.com * flag is cleared, only one thread returns true (and thus is assigned
1599983Sstever@gmail.com * to handle the corresponding async event(s)).
1609983Sstever@gmail.com */
1619983Sstever@gmail.comstatic bool
1629983Sstever@gmail.comtestAndClearAsyncEvent()
1639983Sstever@gmail.com{
1649983Sstever@gmail.com    bool was_set = false;
1659983Sstever@gmail.com    asyncEventMutex.lock();
1669983Sstever@gmail.com
1679983Sstever@gmail.com    if (async_event) {
1689983Sstever@gmail.com        was_set = true;
1699983Sstever@gmail.com        async_event = false;
1709983Sstever@gmail.com    }
1719983Sstever@gmail.com
1729983Sstever@gmail.com    asyncEventMutex.unlock();
1739983Sstever@gmail.com    return was_set;
1749983Sstever@gmail.com}
1759983Sstever@gmail.com
1769983Sstever@gmail.com/**
1779983Sstever@gmail.com * The main per-thread simulation loop. This loop is executed by all
1789983Sstever@gmail.com * simulation threads (the main thread and the subordinate threads) in
1799983Sstever@gmail.com * parallel.
1809983Sstever@gmail.com */
1819983Sstever@gmail.comEvent *
1829983Sstever@gmail.comdoSimLoop(EventQueue *eventq)
1839983Sstever@gmail.com{
1849983Sstever@gmail.com    // set the per thread current eventq pointer
1859983Sstever@gmail.com    curEventQueue(eventq);
1869983Sstever@gmail.com    eventq->handleAsyncInsertions();
1874123Sbinkertn@umich.edu
1884123Sbinkertn@umich.edu    while (1) {
1894123Sbinkertn@umich.edu        // there should always be at least one event (the SimLoopExitEvent
1904123Sbinkertn@umich.edu        // we just scheduled) in the queue
1919983Sstever@gmail.com        assert(!eventq->empty());
1929983Sstever@gmail.com        assert(curTick() <= eventq->nextTick() &&
1934123Sbinkertn@umich.edu               "event scheduled in the past");
1944123Sbinkertn@umich.edu
1959983Sstever@gmail.com        if (async_event && testAndClearAsyncEvent()) {
19610153Sandreas@sandberg.pp.se            // Take the event queue lock in case any of the service
19710153Sandreas@sandberg.pp.se            // routines want to schedule new events.
19810153Sandreas@sandberg.pp.se            std::lock_guard<EventQueue> lock(*eventq);
1994123Sbinkertn@umich.edu            if (async_statdump || async_statreset) {
2007822Ssteve.reinhardt@amd.com                Stats::schedStatEvent(async_statdump, async_statreset);
2014123Sbinkertn@umich.edu                async_statdump = false;
2024123Sbinkertn@umich.edu                async_statreset = false;
2034123Sbinkertn@umich.edu            }
2044123Sbinkertn@umich.edu
20510670SCurtis.Dunham@arm.com            if (async_io) {
20610670SCurtis.Dunham@arm.com                async_io = false;
20710670SCurtis.Dunham@arm.com                pollQueue.service();
20810670SCurtis.Dunham@arm.com            }
20910670SCurtis.Dunham@arm.com
2104123Sbinkertn@umich.edu            if (async_exit) {
2114123Sbinkertn@umich.edu                async_exit = false;
2124123Sbinkertn@umich.edu                exitSimLoop("user interrupt received");
2134123Sbinkertn@umich.edu            }
2144123Sbinkertn@umich.edu
2154123Sbinkertn@umich.edu            if (async_exception) {
2164123Sbinkertn@umich.edu                async_exception = false;
2174123Sbinkertn@umich.edu                return NULL;
2184123Sbinkertn@umich.edu            }
2194123Sbinkertn@umich.edu        }
22010670SCurtis.Dunham@arm.com
22110670SCurtis.Dunham@arm.com        Event *exit_event = eventq->serviceOne();
22210670SCurtis.Dunham@arm.com        if (exit_event != NULL) {
22310670SCurtis.Dunham@arm.com            return exit_event;
22410670SCurtis.Dunham@arm.com        }
2254123Sbinkertn@umich.edu    }
2264123Sbinkertn@umich.edu
2274123Sbinkertn@umich.edu    // not reached... only exit is return on SimLoopExitEvent
2284123Sbinkertn@umich.edu}
229