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