simulate.cc revision 10153
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 744123Sbinkertn@umich.edu/** Simulate for num_cycles additional cycles. If num_cycles is -1 754123Sbinkertn@umich.edu * (the default), do not limit simulation; some other event must 764123Sbinkertn@umich.edu * terminate the loop. Exported to Python via SWIG. 774123Sbinkertn@umich.edu * @return The SimLoopExitEvent that caused the loop to exit. 784123Sbinkertn@umich.edu */ 799983Sstever@gmail.comGlobalSimLoopExitEvent * 804123Sbinkertn@umich.edusimulate(Tick num_cycles) 814123Sbinkertn@umich.edu{ 829983Sstever@gmail.com // The first time simulate() is called from the Python code, we need to 839983Sstever@gmail.com // create a thread for each of event queues referenced by the 849983Sstever@gmail.com // instantiated sim objects. 859983Sstever@gmail.com static bool threads_initialized = false; 869983Sstever@gmail.com static std::vector<std::thread *> threads; 879983Sstever@gmail.com 889983Sstever@gmail.com if (!threads_initialized) { 899983Sstever@gmail.com threadBarrier = new Barrier(numMainEventQueues); 909983Sstever@gmail.com 919983Sstever@gmail.com // the main thread (the one we're currently running on) 929983Sstever@gmail.com // handles queue 0, so we only need to allocate new threads 939983Sstever@gmail.com // for queues 1..N-1. We'll call these the "subordinate" threads. 949983Sstever@gmail.com for (uint32_t i = 1; i < numMainEventQueues; i++) { 959983Sstever@gmail.com threads.push_back(new std::thread(thread_loop, mainEventQueue[i])); 969983Sstever@gmail.com } 979983Sstever@gmail.com 989983Sstever@gmail.com threads_initialized = true; 999983Sstever@gmail.com } 1009983Sstever@gmail.com 1017823Ssteve.reinhardt@amd.com inform("Entering event queue @ %d. Starting simulation...\n", curTick()); 1024123Sbinkertn@umich.edu 1039174Satgutier@umich.edu if (num_cycles < MaxTick - curTick()) 1049174Satgutier@umich.edu num_cycles = curTick() + num_cycles; 1059174Satgutier@umich.edu else // counter would roll over or be set to MaxTick anyhow 1064123Sbinkertn@umich.edu num_cycles = MaxTick; 1074123Sbinkertn@umich.edu 1089983Sstever@gmail.com GlobalEvent *limit_event = new GlobalSimLoopExitEvent(num_cycles, 1099983Sstever@gmail.com "simulate() limit reached", 0, 0); 1109983Sstever@gmail.com 1119983Sstever@gmail.com GlobalSyncEvent *quantum_event = NULL; 1129983Sstever@gmail.com if (numMainEventQueues > 1) { 1139983Sstever@gmail.com if (simQuantum == 0) { 1149983Sstever@gmail.com fatal("Quantum for multi-eventq simulation not specified"); 1159983Sstever@gmail.com } 1169983Sstever@gmail.com 11710101Sandreas@sandberg.pp.se quantum_event = new GlobalSyncEvent(curTick() + simQuantum, simQuantum, 1189983Sstever@gmail.com EventBase::Progress_Event_Pri, 0); 1199983Sstever@gmail.com 1209983Sstever@gmail.com inParallelMode = true; 1219983Sstever@gmail.com } 1229983Sstever@gmail.com 1239983Sstever@gmail.com // all subordinate (created) threads should be waiting on the 1249983Sstever@gmail.com // barrier; the arrival of the main thread here will satisfy the 1259983Sstever@gmail.com // barrier, and all threads will enter doSimLoop in parallel 1269983Sstever@gmail.com threadBarrier->wait(); 1279983Sstever@gmail.com Event *local_event = doSimLoop(mainEventQueue[0]); 1289983Sstever@gmail.com assert(local_event != NULL); 1299983Sstever@gmail.com 1309983Sstever@gmail.com inParallelMode = false; 1319983Sstever@gmail.com 1329983Sstever@gmail.com // locate the global exit event and return it to Python 1339983Sstever@gmail.com BaseGlobalEvent *global_event = local_event->globalEvent(); 1349983Sstever@gmail.com assert(global_event != NULL); 1359983Sstever@gmail.com 1369983Sstever@gmail.com GlobalSimLoopExitEvent *global_exit_event = 1379983Sstever@gmail.com dynamic_cast<GlobalSimLoopExitEvent *>(global_event); 1389983Sstever@gmail.com assert(global_exit_event != NULL); 1399983Sstever@gmail.com 1409983Sstever@gmail.com // if we didn't hit limit_event, delete it. 1419983Sstever@gmail.com if (global_exit_event != limit_event) { 1429983Sstever@gmail.com assert(limit_event->scheduled()); 1439983Sstever@gmail.com limit_event->deschedule(); 1449983Sstever@gmail.com delete limit_event; 1459983Sstever@gmail.com } 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 Event *exit_event = eventq->serviceOne(); 1964123Sbinkertn@umich.edu if (exit_event != NULL) { 1979983Sstever@gmail.com return exit_event; 1984123Sbinkertn@umich.edu } 1994123Sbinkertn@umich.edu 2009983Sstever@gmail.com if (async_event && testAndClearAsyncEvent()) { 20110153Sandreas@sandberg.pp.se // Take the event queue lock in case any of the service 20210153Sandreas@sandberg.pp.se // routines want to schedule new events. 20310153Sandreas@sandberg.pp.se std::lock_guard<EventQueue> lock(*eventq); 2044123Sbinkertn@umich.edu async_event = false; 2054123Sbinkertn@umich.edu if (async_statdump || async_statreset) { 2067822Ssteve.reinhardt@amd.com Stats::schedStatEvent(async_statdump, async_statreset); 2074123Sbinkertn@umich.edu async_statdump = false; 2084123Sbinkertn@umich.edu async_statreset = false; 2094123Sbinkertn@umich.edu } 2104123Sbinkertn@umich.edu 2114123Sbinkertn@umich.edu if (async_exit) { 2124123Sbinkertn@umich.edu async_exit = false; 2134123Sbinkertn@umich.edu exitSimLoop("user interrupt received"); 2144123Sbinkertn@umich.edu } 2154123Sbinkertn@umich.edu 2169990Sandreas@sandberg.pp.se if (async_io) { 2174123Sbinkertn@umich.edu async_io = false; 2184123Sbinkertn@umich.edu pollQueue.service(); 2194123Sbinkertn@umich.edu } 2204123Sbinkertn@umich.edu 2214123Sbinkertn@umich.edu if (async_exception) { 2224123Sbinkertn@umich.edu async_exception = false; 2234123Sbinkertn@umich.edu return NULL; 2244123Sbinkertn@umich.edu } 2254123Sbinkertn@umich.edu } 2264123Sbinkertn@umich.edu } 2274123Sbinkertn@umich.edu 2284123Sbinkertn@umich.edu // not reached... only exit is return on SimLoopExitEvent 2294123Sbinkertn@umich.edu} 230