simulate.cc revision 12334:e0ab29a34764
110259SAndrew.Bardsley@arm.com/*
210259SAndrew.Bardsley@arm.com * Copyright (c) 2006 The Regents of The University of Michigan
310259SAndrew.Bardsley@arm.com * Copyright (c) 2013 Advanced Micro Devices, Inc.
410259SAndrew.Bardsley@arm.com * Copyright (c) 2013 Mark D. Hill and David A. Wood
510259SAndrew.Bardsley@arm.com * All rights reserved.
610259SAndrew.Bardsley@arm.com *
710259SAndrew.Bardsley@arm.com * Redistribution and use in source and binary forms, with or without
810259SAndrew.Bardsley@arm.com * modification, are permitted provided that the following conditions are
910259SAndrew.Bardsley@arm.com * met: redistributions of source code must retain the above copyright
1010259SAndrew.Bardsley@arm.com * notice, this list of conditions and the following disclaimer;
1110259SAndrew.Bardsley@arm.com * redistributions in binary form must reproduce the above copyright
1210259SAndrew.Bardsley@arm.com * notice, this list of conditions and the following disclaimer in the
1310259SAndrew.Bardsley@arm.com * documentation and/or other materials provided with the distribution;
1410259SAndrew.Bardsley@arm.com * neither the name of the copyright holders nor the names of its
1510259SAndrew.Bardsley@arm.com * contributors may be used to endorse or promote products derived from
1610259SAndrew.Bardsley@arm.com * this software without specific prior written permission.
1710259SAndrew.Bardsley@arm.com *
1810259SAndrew.Bardsley@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1910259SAndrew.Bardsley@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2010259SAndrew.Bardsley@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2110259SAndrew.Bardsley@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2210259SAndrew.Bardsley@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2310259SAndrew.Bardsley@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2410259SAndrew.Bardsley@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2510259SAndrew.Bardsley@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2610259SAndrew.Bardsley@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2710259SAndrew.Bardsley@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2810259SAndrew.Bardsley@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2910259SAndrew.Bardsley@arm.com *
3010259SAndrew.Bardsley@arm.com * Authors: Nathan Binkert
3110259SAndrew.Bardsley@arm.com *          Steve Reinhardt
3210259SAndrew.Bardsley@arm.com */
3310259SAndrew.Bardsley@arm.com
3410259SAndrew.Bardsley@arm.com#include "sim/simulate.hh"
3510259SAndrew.Bardsley@arm.com
3610259SAndrew.Bardsley@arm.com#include <mutex>
3710259SAndrew.Bardsley@arm.com#include <thread>
3810259SAndrew.Bardsley@arm.com
3910259SAndrew.Bardsley@arm.com#include "base/logging.hh"
4010259SAndrew.Bardsley@arm.com#include "base/pollevent.hh"
4110259SAndrew.Bardsley@arm.com#include "base/types.hh"
4210259SAndrew.Bardsley@arm.com#include "sim/async.hh"
4310259SAndrew.Bardsley@arm.com#include "sim/eventq_impl.hh"
4410259SAndrew.Bardsley@arm.com#include "sim/sim_events.hh"
4510259SAndrew.Bardsley@arm.com#include "sim/sim_exit.hh"
4610259SAndrew.Bardsley@arm.com#include "sim/stat_control.hh"
4710259SAndrew.Bardsley@arm.com
4810259SAndrew.Bardsley@arm.com//! Mutex for handling async events.
4910259SAndrew.Bardsley@arm.comstd::mutex asyncEventMutex;
5010259SAndrew.Bardsley@arm.com
5110259SAndrew.Bardsley@arm.com//! Global barrier for synchronizing threads entering/exiting the
5210259SAndrew.Bardsley@arm.com//! simulation loop.
5310259SAndrew.Bardsley@arm.comBarrier *threadBarrier;
5410259SAndrew.Bardsley@arm.com
5510259SAndrew.Bardsley@arm.com//! forward declaration
5610259SAndrew.Bardsley@arm.comEvent *doSimLoop(EventQueue *);
5710259SAndrew.Bardsley@arm.com
5810259SAndrew.Bardsley@arm.com/**
5910259SAndrew.Bardsley@arm.com * The main function for all subordinate threads (i.e., all threads
6010259SAndrew.Bardsley@arm.com * other than the main thread).  These threads start by waiting on
6110259SAndrew.Bardsley@arm.com * threadBarrier.  Once all threads have arrived at threadBarrier,
6210259SAndrew.Bardsley@arm.com * they enter the simulation loop concurrently.  When they exit the
6310259SAndrew.Bardsley@arm.com * loop, they return to waiting on threadBarrier.  This process is
6410259SAndrew.Bardsley@arm.com * repeated until the simulation terminates.
6510259SAndrew.Bardsley@arm.com */
6610259SAndrew.Bardsley@arm.comstatic void
6710259SAndrew.Bardsley@arm.comthread_loop(EventQueue *queue)
6810259SAndrew.Bardsley@arm.com{
6910259SAndrew.Bardsley@arm.com    while (true) {
7010259SAndrew.Bardsley@arm.com        threadBarrier->wait();
7110259SAndrew.Bardsley@arm.com        doSimLoop(queue);
7210259SAndrew.Bardsley@arm.com    }
7310259SAndrew.Bardsley@arm.com}
7410259SAndrew.Bardsley@arm.com
7510259SAndrew.Bardsley@arm.comGlobalSimLoopExitEvent *simulate_limit_event = nullptr;
7610259SAndrew.Bardsley@arm.com
7710259SAndrew.Bardsley@arm.com/** Simulate for num_cycles additional cycles.  If num_cycles is -1
7810259SAndrew.Bardsley@arm.com * (the default), do not limit simulation; some other event must
7910259SAndrew.Bardsley@arm.com * terminate the loop.  Exported to Python.
8010259SAndrew.Bardsley@arm.com * @return The SimLoopExitEvent that caused the loop to exit.
8110259SAndrew.Bardsley@arm.com */
8210259SAndrew.Bardsley@arm.comGlobalSimLoopExitEvent *
8310259SAndrew.Bardsley@arm.comsimulate(Tick num_cycles)
8410259SAndrew.Bardsley@arm.com{
8510259SAndrew.Bardsley@arm.com    // The first time simulate() is called from the Python code, we need to
8610259SAndrew.Bardsley@arm.com    // create a thread for each of event queues referenced by the
8710259SAndrew.Bardsley@arm.com    // instantiated sim objects.
8810259SAndrew.Bardsley@arm.com    static bool threads_initialized = false;
8910259SAndrew.Bardsley@arm.com    static std::vector<std::thread *> threads;
9010259SAndrew.Bardsley@arm.com
9110259SAndrew.Bardsley@arm.com    if (!threads_initialized) {
9210259SAndrew.Bardsley@arm.com        threadBarrier = new Barrier(numMainEventQueues);
9310259SAndrew.Bardsley@arm.com
9410259SAndrew.Bardsley@arm.com        // the main thread (the one we're currently running on)
9510259SAndrew.Bardsley@arm.com        // handles queue 0, so we only need to allocate new threads
9610259SAndrew.Bardsley@arm.com        // for queues 1..N-1.  We'll call these the "subordinate" threads.
9710259SAndrew.Bardsley@arm.com        for (uint32_t i = 1; i < numMainEventQueues; i++) {
9810259SAndrew.Bardsley@arm.com            threads.push_back(new std::thread(thread_loop, mainEventQueue[i]));
9910259SAndrew.Bardsley@arm.com        }
10010259SAndrew.Bardsley@arm.com
10110259SAndrew.Bardsley@arm.com        threads_initialized = true;
10210259SAndrew.Bardsley@arm.com        simulate_limit_event =
10310259SAndrew.Bardsley@arm.com            new GlobalSimLoopExitEvent(mainEventQueue[0]->getCurTick(),
10410259SAndrew.Bardsley@arm.com                                       "simulate() limit reached", 0);
10510259SAndrew.Bardsley@arm.com    }
10610259SAndrew.Bardsley@arm.com
10710259SAndrew.Bardsley@arm.com    inform("Entering event queue @ %d.  Starting simulation...\n", curTick());
10810259SAndrew.Bardsley@arm.com
10910259SAndrew.Bardsley@arm.com    if (num_cycles < MaxTick - curTick())
11010259SAndrew.Bardsley@arm.com        num_cycles = curTick() + num_cycles;
11110259SAndrew.Bardsley@arm.com    else // counter would roll over or be set to MaxTick anyhow
11210259SAndrew.Bardsley@arm.com        num_cycles = MaxTick;
11310259SAndrew.Bardsley@arm.com
11410259SAndrew.Bardsley@arm.com    simulate_limit_event->reschedule(num_cycles);
11510259SAndrew.Bardsley@arm.com
11610259SAndrew.Bardsley@arm.com    GlobalSyncEvent *quantum_event = NULL;
11710259SAndrew.Bardsley@arm.com    if (numMainEventQueues > 1) {
11810259SAndrew.Bardsley@arm.com        if (simQuantum == 0) {
11910259SAndrew.Bardsley@arm.com            fatal("Quantum for multi-eventq simulation not specified");
12010259SAndrew.Bardsley@arm.com        }
12110259SAndrew.Bardsley@arm.com
12210259SAndrew.Bardsley@arm.com        quantum_event = new GlobalSyncEvent(curTick() + simQuantum, simQuantum,
12310259SAndrew.Bardsley@arm.com                            EventBase::Progress_Event_Pri, 0);
12410259SAndrew.Bardsley@arm.com
12510259SAndrew.Bardsley@arm.com        inParallelMode = true;
12610259SAndrew.Bardsley@arm.com    }
12710259SAndrew.Bardsley@arm.com
12810259SAndrew.Bardsley@arm.com    // all subordinate (created) threads should be waiting on the
12910259SAndrew.Bardsley@arm.com    // barrier; the arrival of the main thread here will satisfy the
13010259SAndrew.Bardsley@arm.com    // barrier, and all threads will enter doSimLoop in parallel
13110259SAndrew.Bardsley@arm.com    threadBarrier->wait();
13210259SAndrew.Bardsley@arm.com    Event *local_event = doSimLoop(mainEventQueue[0]);
13310259SAndrew.Bardsley@arm.com    assert(local_event != NULL);
13410259SAndrew.Bardsley@arm.com
13510259SAndrew.Bardsley@arm.com    inParallelMode = false;
13610259SAndrew.Bardsley@arm.com
13710259SAndrew.Bardsley@arm.com    // locate the global exit event and return it to Python
13810259SAndrew.Bardsley@arm.com    BaseGlobalEvent *global_event = local_event->globalEvent();
13910259SAndrew.Bardsley@arm.com    assert(global_event != NULL);
14010259SAndrew.Bardsley@arm.com
14110259SAndrew.Bardsley@arm.com    GlobalSimLoopExitEvent *global_exit_event =
14210259SAndrew.Bardsley@arm.com        dynamic_cast<GlobalSimLoopExitEvent *>(global_event);
14310259SAndrew.Bardsley@arm.com    assert(global_exit_event != NULL);
14410259SAndrew.Bardsley@arm.com
14510259SAndrew.Bardsley@arm.com    //! Delete the simulation quantum event.
14610259SAndrew.Bardsley@arm.com    if (quantum_event != NULL) {
14710259SAndrew.Bardsley@arm.com        quantum_event->deschedule();
14810259SAndrew.Bardsley@arm.com        delete quantum_event;
14910259SAndrew.Bardsley@arm.com    }
15010259SAndrew.Bardsley@arm.com
15110259SAndrew.Bardsley@arm.com    return global_exit_event;
15210259SAndrew.Bardsley@arm.com}
15310259SAndrew.Bardsley@arm.com
15410259SAndrew.Bardsley@arm.com/**
15510259SAndrew.Bardsley@arm.com * Test and clear the global async_event flag, such that each time the
15610259SAndrew.Bardsley@arm.com * flag is cleared, only one thread returns true (and thus is assigned
15710259SAndrew.Bardsley@arm.com * to handle the corresponding async event(s)).
15810259SAndrew.Bardsley@arm.com */
15910259SAndrew.Bardsley@arm.comstatic bool
16010259SAndrew.Bardsley@arm.comtestAndClearAsyncEvent()
16110259SAndrew.Bardsley@arm.com{
16210259SAndrew.Bardsley@arm.com    bool was_set = false;
16310259SAndrew.Bardsley@arm.com    asyncEventMutex.lock();
16410259SAndrew.Bardsley@arm.com
16510259SAndrew.Bardsley@arm.com    if (async_event) {
16610259SAndrew.Bardsley@arm.com        was_set = true;
16710259SAndrew.Bardsley@arm.com        async_event = false;
16810259SAndrew.Bardsley@arm.com    }
16910259SAndrew.Bardsley@arm.com
17010259SAndrew.Bardsley@arm.com    asyncEventMutex.unlock();
17110259SAndrew.Bardsley@arm.com    return was_set;
17210259SAndrew.Bardsley@arm.com}
17310259SAndrew.Bardsley@arm.com
17410259SAndrew.Bardsley@arm.com/**
17510259SAndrew.Bardsley@arm.com * The main per-thread simulation loop. This loop is executed by all
17610259SAndrew.Bardsley@arm.com * simulation threads (the main thread and the subordinate threads) in
17710259SAndrew.Bardsley@arm.com * parallel.
17810259SAndrew.Bardsley@arm.com */
17910259SAndrew.Bardsley@arm.comEvent *
18010259SAndrew.Bardsley@arm.comdoSimLoop(EventQueue *eventq)
18110259SAndrew.Bardsley@arm.com{
18210259SAndrew.Bardsley@arm.com    // set the per thread current eventq pointer
18310259SAndrew.Bardsley@arm.com    curEventQueue(eventq);
18410259SAndrew.Bardsley@arm.com    eventq->handleAsyncInsertions();
18510259SAndrew.Bardsley@arm.com
18610259SAndrew.Bardsley@arm.com    while (1) {
18710259SAndrew.Bardsley@arm.com        // there should always be at least one event (the SimLoopExitEvent
18810259SAndrew.Bardsley@arm.com        // we just scheduled) in the queue
18910259SAndrew.Bardsley@arm.com        assert(!eventq->empty());
19010259SAndrew.Bardsley@arm.com        assert(curTick() <= eventq->nextTick() &&
19110259SAndrew.Bardsley@arm.com               "event scheduled in the past");
19210259SAndrew.Bardsley@arm.com
19310259SAndrew.Bardsley@arm.com        if (async_event && testAndClearAsyncEvent()) {
19410259SAndrew.Bardsley@arm.com            // Take the event queue lock in case any of the service
19510259SAndrew.Bardsley@arm.com            // routines want to schedule new events.
19610259SAndrew.Bardsley@arm.com            std::lock_guard<EventQueue> lock(*eventq);
19710259SAndrew.Bardsley@arm.com            if (async_statdump || async_statreset) {
19810259SAndrew.Bardsley@arm.com                Stats::schedStatEvent(async_statdump, async_statreset);
19910259SAndrew.Bardsley@arm.com                async_statdump = false;
20010259SAndrew.Bardsley@arm.com                async_statreset = false;
20110259SAndrew.Bardsley@arm.com            }
20210259SAndrew.Bardsley@arm.com
20310259SAndrew.Bardsley@arm.com            if (async_io) {
20410259SAndrew.Bardsley@arm.com                async_io = false;
20510259SAndrew.Bardsley@arm.com                pollQueue.service();
20610259SAndrew.Bardsley@arm.com            }
20710259SAndrew.Bardsley@arm.com
20810259SAndrew.Bardsley@arm.com            if (async_exit) {
20910259SAndrew.Bardsley@arm.com                async_exit = false;
21010259SAndrew.Bardsley@arm.com                exitSimLoop("user interrupt received");
21110259SAndrew.Bardsley@arm.com            }
21210259SAndrew.Bardsley@arm.com
21310259SAndrew.Bardsley@arm.com            if (async_exception) {
21410259SAndrew.Bardsley@arm.com                async_exception = false;
21510259SAndrew.Bardsley@arm.com                return NULL;
21610259SAndrew.Bardsley@arm.com            }
21710259SAndrew.Bardsley@arm.com        }
21810259SAndrew.Bardsley@arm.com
21910259SAndrew.Bardsley@arm.com        Event *exit_event = eventq->serviceOne();
22010259SAndrew.Bardsley@arm.com        if (exit_event != NULL) {
22110259SAndrew.Bardsley@arm.com            return exit_event;
22210259SAndrew.Bardsley@arm.com        }
22310259SAndrew.Bardsley@arm.com    }
22410259SAndrew.Bardsley@arm.com
22510259SAndrew.Bardsley@arm.com    // not reached... only exit is return on SimLoopExitEvent
22610259SAndrew.Bardsley@arm.com}
22710259SAndrew.Bardsley@arm.com