simulate.cc revision 10762
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 7410762SCurtis.Dunham@arm.comGlobalSimLoopExitEvent *simulate_limit_event = nullptr; 7510756SCurtis.Dunham@arm.com 764123Sbinkertn@umich.edu/** Simulate for num_cycles additional cycles. If num_cycles is -1 774123Sbinkertn@umich.edu * (the default), do not limit simulation; some other event must 784123Sbinkertn@umich.edu * terminate the loop. Exported to Python via SWIG. 794123Sbinkertn@umich.edu * @return The SimLoopExitEvent that caused the loop to exit. 804123Sbinkertn@umich.edu */ 819983Sstever@gmail.comGlobalSimLoopExitEvent * 824123Sbinkertn@umich.edusimulate(Tick num_cycles) 834123Sbinkertn@umich.edu{ 849983Sstever@gmail.com // The first time simulate() is called from the Python code, we need to 859983Sstever@gmail.com // create a thread for each of event queues referenced by the 869983Sstever@gmail.com // instantiated sim objects. 879983Sstever@gmail.com static bool threads_initialized = false; 889983Sstever@gmail.com static std::vector<std::thread *> threads; 899983Sstever@gmail.com 909983Sstever@gmail.com if (!threads_initialized) { 919983Sstever@gmail.com threadBarrier = new Barrier(numMainEventQueues); 929983Sstever@gmail.com 939983Sstever@gmail.com // the main thread (the one we're currently running on) 949983Sstever@gmail.com // handles queue 0, so we only need to allocate new threads 959983Sstever@gmail.com // for queues 1..N-1. We'll call these the "subordinate" threads. 969983Sstever@gmail.com for (uint32_t i = 1; i < numMainEventQueues; i++) { 979983Sstever@gmail.com threads.push_back(new std::thread(thread_loop, mainEventQueue[i])); 989983Sstever@gmail.com } 999983Sstever@gmail.com 1009983Sstever@gmail.com threads_initialized = true; 10110762SCurtis.Dunham@arm.com simulate_limit_event = 10210762SCurtis.Dunham@arm.com new GlobalSimLoopExitEvent(mainEventQueue[0]->getCurTick(), 10310762SCurtis.Dunham@arm.com "simulate() limit reached", 0); 1049983Sstever@gmail.com } 1059983Sstever@gmail.com 1067823Ssteve.reinhardt@amd.com inform("Entering event queue @ %d. Starting simulation...\n", curTick()); 1074123Sbinkertn@umich.edu 1089174Satgutier@umich.edu if (num_cycles < MaxTick - curTick()) 1099174Satgutier@umich.edu num_cycles = curTick() + num_cycles; 1109174Satgutier@umich.edu else // counter would roll over or be set to MaxTick anyhow 1114123Sbinkertn@umich.edu num_cycles = MaxTick; 1124123Sbinkertn@umich.edu 11310762SCurtis.Dunham@arm.com simulate_limit_event->reschedule(num_cycles); 1149983Sstever@gmail.com 1159983Sstever@gmail.com GlobalSyncEvent *quantum_event = NULL; 1169983Sstever@gmail.com if (numMainEventQueues > 1) { 1179983Sstever@gmail.com if (simQuantum == 0) { 1189983Sstever@gmail.com fatal("Quantum for multi-eventq simulation not specified"); 1199983Sstever@gmail.com } 1209983Sstever@gmail.com 12110101Sandreas@sandberg.pp.se quantum_event = new GlobalSyncEvent(curTick() + simQuantum, simQuantum, 1229983Sstever@gmail.com EventBase::Progress_Event_Pri, 0); 1239983Sstever@gmail.com 1249983Sstever@gmail.com inParallelMode = true; 1259983Sstever@gmail.com } 1269983Sstever@gmail.com 1279983Sstever@gmail.com // all subordinate (created) threads should be waiting on the 1289983Sstever@gmail.com // barrier; the arrival of the main thread here will satisfy the 1299983Sstever@gmail.com // barrier, and all threads will enter doSimLoop in parallel 1309983Sstever@gmail.com threadBarrier->wait(); 1319983Sstever@gmail.com Event *local_event = doSimLoop(mainEventQueue[0]); 1329983Sstever@gmail.com assert(local_event != NULL); 1339983Sstever@gmail.com 1349983Sstever@gmail.com inParallelMode = false; 1359983Sstever@gmail.com 1369983Sstever@gmail.com // locate the global exit event and return it to Python 1379983Sstever@gmail.com BaseGlobalEvent *global_event = local_event->globalEvent(); 1389983Sstever@gmail.com assert(global_event != NULL); 1399983Sstever@gmail.com 1409983Sstever@gmail.com GlobalSimLoopExitEvent *global_exit_event = 1419983Sstever@gmail.com dynamic_cast<GlobalSimLoopExitEvent *>(global_event); 1429983Sstever@gmail.com assert(global_exit_event != NULL); 1439983Sstever@gmail.com 1449983Sstever@gmail.com //! Delete the simulation quantum event. 1459983Sstever@gmail.com if (quantum_event != NULL) { 1469983Sstever@gmail.com quantum_event->deschedule(); 1479983Sstever@gmail.com delete quantum_event; 1489983Sstever@gmail.com } 1499983Sstever@gmail.com 1509983Sstever@gmail.com return global_exit_event; 1519983Sstever@gmail.com} 1529983Sstever@gmail.com 1539983Sstever@gmail.com/** 1549983Sstever@gmail.com * Test and clear the global async_event flag, such that each time the 1559983Sstever@gmail.com * flag is cleared, only one thread returns true (and thus is assigned 1569983Sstever@gmail.com * to handle the corresponding async event(s)). 1579983Sstever@gmail.com */ 1589983Sstever@gmail.comstatic bool 1599983Sstever@gmail.comtestAndClearAsyncEvent() 1609983Sstever@gmail.com{ 1619983Sstever@gmail.com bool was_set = false; 1629983Sstever@gmail.com asyncEventMutex.lock(); 1639983Sstever@gmail.com 1649983Sstever@gmail.com if (async_event) { 1659983Sstever@gmail.com was_set = true; 1669983Sstever@gmail.com async_event = false; 1679983Sstever@gmail.com } 1689983Sstever@gmail.com 1699983Sstever@gmail.com asyncEventMutex.unlock(); 1709983Sstever@gmail.com return was_set; 1719983Sstever@gmail.com} 1729983Sstever@gmail.com 1739983Sstever@gmail.com/** 1749983Sstever@gmail.com * The main per-thread simulation loop. This loop is executed by all 1759983Sstever@gmail.com * simulation threads (the main thread and the subordinate threads) in 1769983Sstever@gmail.com * parallel. 1779983Sstever@gmail.com */ 1789983Sstever@gmail.comEvent * 1799983Sstever@gmail.comdoSimLoop(EventQueue *eventq) 1809983Sstever@gmail.com{ 1819983Sstever@gmail.com // set the per thread current eventq pointer 1829983Sstever@gmail.com curEventQueue(eventq); 1839983Sstever@gmail.com eventq->handleAsyncInsertions(); 1844123Sbinkertn@umich.edu 1854123Sbinkertn@umich.edu while (1) { 1864123Sbinkertn@umich.edu // there should always be at least one event (the SimLoopExitEvent 1874123Sbinkertn@umich.edu // we just scheduled) in the queue 1889983Sstever@gmail.com assert(!eventq->empty()); 1899983Sstever@gmail.com assert(curTick() <= eventq->nextTick() && 1904123Sbinkertn@umich.edu "event scheduled in the past"); 1914123Sbinkertn@umich.edu 1929983Sstever@gmail.com if (async_event && testAndClearAsyncEvent()) { 19310153Sandreas@sandberg.pp.se // Take the event queue lock in case any of the service 19410153Sandreas@sandberg.pp.se // routines want to schedule new events. 19510153Sandreas@sandberg.pp.se std::lock_guard<EventQueue> lock(*eventq); 1964123Sbinkertn@umich.edu if (async_statdump || async_statreset) { 1977822Ssteve.reinhardt@amd.com Stats::schedStatEvent(async_statdump, async_statreset); 1984123Sbinkertn@umich.edu async_statdump = false; 1994123Sbinkertn@umich.edu async_statreset = false; 2004123Sbinkertn@umich.edu } 2014123Sbinkertn@umich.edu 20210670SCurtis.Dunham@arm.com if (async_io) { 20310670SCurtis.Dunham@arm.com async_io = false; 20410670SCurtis.Dunham@arm.com pollQueue.service(); 20510670SCurtis.Dunham@arm.com } 20610670SCurtis.Dunham@arm.com 2074123Sbinkertn@umich.edu if (async_exit) { 2084123Sbinkertn@umich.edu async_exit = false; 2094123Sbinkertn@umich.edu exitSimLoop("user interrupt received"); 2104123Sbinkertn@umich.edu } 2114123Sbinkertn@umich.edu 2124123Sbinkertn@umich.edu if (async_exception) { 2134123Sbinkertn@umich.edu async_exception = false; 2144123Sbinkertn@umich.edu return NULL; 2154123Sbinkertn@umich.edu } 2164123Sbinkertn@umich.edu } 21710670SCurtis.Dunham@arm.com 21810670SCurtis.Dunham@arm.com Event *exit_event = eventq->serviceOne(); 21910670SCurtis.Dunham@arm.com if (exit_event != NULL) { 22010670SCurtis.Dunham@arm.com return exit_event; 22110670SCurtis.Dunham@arm.com } 2224123Sbinkertn@umich.edu } 2234123Sbinkertn@umich.edu 2244123Sbinkertn@umich.edu // not reached... only exit is return on SimLoopExitEvent 2254123Sbinkertn@umich.edu} 226