simulate.cc revision 11990
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 3411793Sbrandon.potter@amd.com#include "sim/simulate.hh" 3511793Sbrandon.potter@amd.com 369983Sstever@gmail.com#include <mutex> 379983Sstever@gmail.com#include <thread> 389983Sstever@gmail.com 394123Sbinkertn@umich.edu#include "base/misc.hh" 404123Sbinkertn@umich.edu#include "base/pollevent.hh" 416216Snate@binkert.org#include "base/types.hh" 424123Sbinkertn@umich.edu#include "sim/async.hh" 439356Snilay@cs.wisc.edu#include "sim/eventq_impl.hh" 444123Sbinkertn@umich.edu#include "sim/sim_events.hh" 454123Sbinkertn@umich.edu#include "sim/sim_exit.hh" 466216Snate@binkert.org#include "sim/stat_control.hh" 474123Sbinkertn@umich.edu 489983Sstever@gmail.com//! Mutex for handling async events. 499983Sstever@gmail.comstd::mutex asyncEventMutex; 509983Sstever@gmail.com 519983Sstever@gmail.com//! Global barrier for synchronizing threads entering/exiting the 529983Sstever@gmail.com//! simulation loop. 539983Sstever@gmail.comBarrier *threadBarrier; 549983Sstever@gmail.com 559983Sstever@gmail.com//! forward declaration 569983Sstever@gmail.comEvent *doSimLoop(EventQueue *); 579983Sstever@gmail.com 589983Sstever@gmail.com/** 599983Sstever@gmail.com * The main function for all subordinate threads (i.e., all threads 609983Sstever@gmail.com * other than the main thread). These threads start by waiting on 619983Sstever@gmail.com * threadBarrier. Once all threads have arrived at threadBarrier, 629983Sstever@gmail.com * they enter the simulation loop concurrently. When they exit the 639983Sstever@gmail.com * loop, they return to waiting on threadBarrier. This process is 649983Sstever@gmail.com * repeated until the simulation terminates. 659983Sstever@gmail.com */ 669983Sstever@gmail.comstatic void 679983Sstever@gmail.comthread_loop(EventQueue *queue) 689983Sstever@gmail.com{ 699983Sstever@gmail.com while (true) { 709983Sstever@gmail.com threadBarrier->wait(); 719983Sstever@gmail.com doSimLoop(queue); 729983Sstever@gmail.com } 739983Sstever@gmail.com} 749983Sstever@gmail.com 7510762SCurtis.Dunham@arm.comGlobalSimLoopExitEvent *simulate_limit_event = nullptr; 7610756SCurtis.Dunham@arm.com 774123Sbinkertn@umich.edu/** Simulate for num_cycles additional cycles. If num_cycles is -1 784123Sbinkertn@umich.edu * (the default), do not limit simulation; some other event must 7911990Sandreas.sandberg@arm.com * terminate the loop. Exported to Python. 804123Sbinkertn@umich.edu * @return The SimLoopExitEvent that caused the loop to exit. 814123Sbinkertn@umich.edu */ 829983Sstever@gmail.comGlobalSimLoopExitEvent * 834123Sbinkertn@umich.edusimulate(Tick num_cycles) 844123Sbinkertn@umich.edu{ 859983Sstever@gmail.com // The first time simulate() is called from the Python code, we need to 869983Sstever@gmail.com // create a thread for each of event queues referenced by the 879983Sstever@gmail.com // instantiated sim objects. 889983Sstever@gmail.com static bool threads_initialized = false; 899983Sstever@gmail.com static std::vector<std::thread *> threads; 909983Sstever@gmail.com 919983Sstever@gmail.com if (!threads_initialized) { 929983Sstever@gmail.com threadBarrier = new Barrier(numMainEventQueues); 939983Sstever@gmail.com 949983Sstever@gmail.com // the main thread (the one we're currently running on) 959983Sstever@gmail.com // handles queue 0, so we only need to allocate new threads 969983Sstever@gmail.com // for queues 1..N-1. We'll call these the "subordinate" threads. 979983Sstever@gmail.com for (uint32_t i = 1; i < numMainEventQueues; i++) { 989983Sstever@gmail.com threads.push_back(new std::thread(thread_loop, mainEventQueue[i])); 999983Sstever@gmail.com } 1009983Sstever@gmail.com 1019983Sstever@gmail.com threads_initialized = true; 10210762SCurtis.Dunham@arm.com simulate_limit_event = 10310762SCurtis.Dunham@arm.com new GlobalSimLoopExitEvent(mainEventQueue[0]->getCurTick(), 10410762SCurtis.Dunham@arm.com "simulate() limit reached", 0); 1059983Sstever@gmail.com } 1069983Sstever@gmail.com 1077823Ssteve.reinhardt@amd.com inform("Entering event queue @ %d. Starting simulation...\n", curTick()); 1084123Sbinkertn@umich.edu 1099174Satgutier@umich.edu if (num_cycles < MaxTick - curTick()) 1109174Satgutier@umich.edu num_cycles = curTick() + num_cycles; 1119174Satgutier@umich.edu else // counter would roll over or be set to MaxTick anyhow 1124123Sbinkertn@umich.edu num_cycles = MaxTick; 1134123Sbinkertn@umich.edu 11410762SCurtis.Dunham@arm.com simulate_limit_event->reschedule(num_cycles); 1159983Sstever@gmail.com 1169983Sstever@gmail.com GlobalSyncEvent *quantum_event = NULL; 1179983Sstever@gmail.com if (numMainEventQueues > 1) { 1189983Sstever@gmail.com if (simQuantum == 0) { 1199983Sstever@gmail.com fatal("Quantum for multi-eventq simulation not specified"); 1209983Sstever@gmail.com } 1219983Sstever@gmail.com 12210101Sandreas@sandberg.pp.se quantum_event = new GlobalSyncEvent(curTick() + simQuantum, simQuantum, 1239983Sstever@gmail.com EventBase::Progress_Event_Pri, 0); 1249983Sstever@gmail.com 1259983Sstever@gmail.com inParallelMode = true; 1269983Sstever@gmail.com } 1279983Sstever@gmail.com 1289983Sstever@gmail.com // all subordinate (created) threads should be waiting on the 1299983Sstever@gmail.com // barrier; the arrival of the main thread here will satisfy the 1309983Sstever@gmail.com // barrier, and all threads will enter doSimLoop in parallel 1319983Sstever@gmail.com threadBarrier->wait(); 1329983Sstever@gmail.com Event *local_event = doSimLoop(mainEventQueue[0]); 1339983Sstever@gmail.com assert(local_event != NULL); 1349983Sstever@gmail.com 1359983Sstever@gmail.com inParallelMode = false; 1369983Sstever@gmail.com 1379983Sstever@gmail.com // locate the global exit event and return it to Python 1389983Sstever@gmail.com BaseGlobalEvent *global_event = local_event->globalEvent(); 1399983Sstever@gmail.com assert(global_event != NULL); 1409983Sstever@gmail.com 1419983Sstever@gmail.com GlobalSimLoopExitEvent *global_exit_event = 1429983Sstever@gmail.com dynamic_cast<GlobalSimLoopExitEvent *>(global_event); 1439983Sstever@gmail.com assert(global_exit_event != NULL); 1449983Sstever@gmail.com 1459983Sstever@gmail.com //! Delete the simulation quantum event. 1469983Sstever@gmail.com if (quantum_event != NULL) { 1479983Sstever@gmail.com quantum_event->deschedule(); 1489983Sstever@gmail.com delete quantum_event; 1499983Sstever@gmail.com } 1509983Sstever@gmail.com 1519983Sstever@gmail.com return global_exit_event; 1529983Sstever@gmail.com} 1539983Sstever@gmail.com 1549983Sstever@gmail.com/** 1559983Sstever@gmail.com * Test and clear the global async_event flag, such that each time the 1569983Sstever@gmail.com * flag is cleared, only one thread returns true (and thus is assigned 1579983Sstever@gmail.com * to handle the corresponding async event(s)). 1589983Sstever@gmail.com */ 1599983Sstever@gmail.comstatic bool 1609983Sstever@gmail.comtestAndClearAsyncEvent() 1619983Sstever@gmail.com{ 1629983Sstever@gmail.com bool was_set = false; 1639983Sstever@gmail.com asyncEventMutex.lock(); 1649983Sstever@gmail.com 1659983Sstever@gmail.com if (async_event) { 1669983Sstever@gmail.com was_set = true; 1679983Sstever@gmail.com async_event = false; 1689983Sstever@gmail.com } 1699983Sstever@gmail.com 1709983Sstever@gmail.com asyncEventMutex.unlock(); 1719983Sstever@gmail.com return was_set; 1729983Sstever@gmail.com} 1739983Sstever@gmail.com 1749983Sstever@gmail.com/** 1759983Sstever@gmail.com * The main per-thread simulation loop. This loop is executed by all 1769983Sstever@gmail.com * simulation threads (the main thread and the subordinate threads) in 1779983Sstever@gmail.com * parallel. 1789983Sstever@gmail.com */ 1799983Sstever@gmail.comEvent * 1809983Sstever@gmail.comdoSimLoop(EventQueue *eventq) 1819983Sstever@gmail.com{ 1829983Sstever@gmail.com // set the per thread current eventq pointer 1839983Sstever@gmail.com curEventQueue(eventq); 1849983Sstever@gmail.com eventq->handleAsyncInsertions(); 1854123Sbinkertn@umich.edu 1864123Sbinkertn@umich.edu while (1) { 1874123Sbinkertn@umich.edu // there should always be at least one event (the SimLoopExitEvent 1884123Sbinkertn@umich.edu // we just scheduled) in the queue 1899983Sstever@gmail.com assert(!eventq->empty()); 1909983Sstever@gmail.com assert(curTick() <= eventq->nextTick() && 1914123Sbinkertn@umich.edu "event scheduled in the past"); 1924123Sbinkertn@umich.edu 1939983Sstever@gmail.com if (async_event && testAndClearAsyncEvent()) { 19410153Sandreas@sandberg.pp.se // Take the event queue lock in case any of the service 19510153Sandreas@sandberg.pp.se // routines want to schedule new events. 19610153Sandreas@sandberg.pp.se std::lock_guard<EventQueue> lock(*eventq); 1974123Sbinkertn@umich.edu if (async_statdump || async_statreset) { 1987822Ssteve.reinhardt@amd.com Stats::schedStatEvent(async_statdump, async_statreset); 1994123Sbinkertn@umich.edu async_statdump = false; 2004123Sbinkertn@umich.edu async_statreset = false; 2014123Sbinkertn@umich.edu } 2024123Sbinkertn@umich.edu 20310670SCurtis.Dunham@arm.com if (async_io) { 20410670SCurtis.Dunham@arm.com async_io = false; 20510670SCurtis.Dunham@arm.com pollQueue.service(); 20610670SCurtis.Dunham@arm.com } 20710670SCurtis.Dunham@arm.com 2084123Sbinkertn@umich.edu if (async_exit) { 2094123Sbinkertn@umich.edu async_exit = false; 2104123Sbinkertn@umich.edu exitSimLoop("user interrupt received"); 2114123Sbinkertn@umich.edu } 2124123Sbinkertn@umich.edu 2134123Sbinkertn@umich.edu if (async_exception) { 2144123Sbinkertn@umich.edu async_exception = false; 2154123Sbinkertn@umich.edu return NULL; 2164123Sbinkertn@umich.edu } 2174123Sbinkertn@umich.edu } 21810670SCurtis.Dunham@arm.com 21910670SCurtis.Dunham@arm.com Event *exit_event = eventq->serviceOne(); 22010670SCurtis.Dunham@arm.com if (exit_event != NULL) { 22110670SCurtis.Dunham@arm.com return exit_event; 22210670SCurtis.Dunham@arm.com } 2234123Sbinkertn@umich.edu } 2244123Sbinkertn@umich.edu 2254123Sbinkertn@umich.edu // not reached... only exit is return on SimLoopExitEvent 2264123Sbinkertn@umich.edu} 227