d3c27fa08c5708eeafafd96d190a247176fbc432
2 * Copyright (c) 2006 The Regents of The University of Michigan
3 * Copyright (c) 2013 Advanced Micro Devices, Inc.
4 * Copyright (c) 2013 Mark D. Hill and David A. Wood
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met: redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer;
11 * redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution;
14 * neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * Authors: Nathan Binkert
34 #include "sim/simulate.hh"
39 #include "base/misc.hh"
40 #include "base/pollevent.hh"
41 #include "base/types.hh"
42 #include "sim/async.hh"
43 #include "sim/eventq_impl.hh"
44 #include "sim/sim_events.hh"
45 #include "sim/sim_exit.hh"
46 #include "sim/stat_control.hh"
48 //! Mutex for handling async events.
49 std::mutex asyncEventMutex
;
51 //! Global barrier for synchronizing threads entering/exiting the
53 Barrier
*threadBarrier
;
55 //! forward declaration
56 Event
*doSimLoop(EventQueue
*);
59 * The main function for all subordinate threads (i.e., all threads
60 * other than the main thread). These threads start by waiting on
61 * threadBarrier. Once all threads have arrived at threadBarrier,
62 * they enter the simulation loop concurrently. When they exit the
63 * loop, they return to waiting on threadBarrier. This process is
64 * repeated until the simulation terminates.
67 thread_loop(EventQueue
*queue
)
70 threadBarrier
->wait();
75 GlobalSimLoopExitEvent
*simulate_limit_event
= nullptr;
77 /** Simulate for num_cycles additional cycles. If num_cycles is -1
78 * (the default), do not limit simulation; some other event must
79 * terminate the loop. Exported to Python.
80 * @return The SimLoopExitEvent that caused the loop to exit.
82 GlobalSimLoopExitEvent
*
83 simulate(Tick num_cycles
)
85 // The first time simulate() is called from the Python code, we need to
86 // create a thread for each of event queues referenced by the
87 // instantiated sim objects.
88 static bool threads_initialized
= false;
89 static std::vector
<std::thread
*> threads
;
91 if (!threads_initialized
) {
92 threadBarrier
= new Barrier(numMainEventQueues
);
94 // the main thread (the one we're currently running on)
95 // handles queue 0, so we only need to allocate new threads
96 // for queues 1..N-1. We'll call these the "subordinate" threads.
97 for (uint32_t i
= 1; i
< numMainEventQueues
; i
++) {
98 threads
.push_back(new std::thread(thread_loop
, mainEventQueue
[i
]));
101 threads_initialized
= true;
102 simulate_limit_event
=
103 new GlobalSimLoopExitEvent(mainEventQueue
[0]->getCurTick(),
104 "simulate() limit reached", 0);
107 inform("Entering event queue @ %d. Starting simulation...\n", curTick());
109 if (num_cycles
< MaxTick
- curTick())
110 num_cycles
= curTick() + num_cycles
;
111 else // counter would roll over or be set to MaxTick anyhow
112 num_cycles
= MaxTick
;
114 simulate_limit_event
->reschedule(num_cycles
);
116 GlobalSyncEvent
*quantum_event
= NULL
;
117 if (numMainEventQueues
> 1) {
118 if (simQuantum
== 0) {
119 fatal("Quantum for multi-eventq simulation not specified");
122 quantum_event
= new GlobalSyncEvent(curTick() + simQuantum
, simQuantum
,
123 EventBase::Progress_Event_Pri
, 0);
125 inParallelMode
= true;
128 // all subordinate (created) threads should be waiting on the
129 // barrier; the arrival of the main thread here will satisfy the
130 // barrier, and all threads will enter doSimLoop in parallel
131 threadBarrier
->wait();
132 Event
*local_event
= doSimLoop(mainEventQueue
[0]);
133 assert(local_event
!= NULL
);
135 inParallelMode
= false;
137 // locate the global exit event and return it to Python
138 BaseGlobalEvent
*global_event
= local_event
->globalEvent();
139 assert(global_event
!= NULL
);
141 GlobalSimLoopExitEvent
*global_exit_event
=
142 dynamic_cast<GlobalSimLoopExitEvent
*>(global_event
);
143 assert(global_exit_event
!= NULL
);
145 //! Delete the simulation quantum event.
146 if (quantum_event
!= NULL
) {
147 quantum_event
->deschedule();
148 delete quantum_event
;
151 return global_exit_event
;
155 * Test and clear the global async_event flag, such that each time the
156 * flag is cleared, only one thread returns true (and thus is assigned
157 * to handle the corresponding async event(s)).
160 testAndClearAsyncEvent()
162 bool was_set
= false;
163 asyncEventMutex
.lock();
170 asyncEventMutex
.unlock();
175 * The main per-thread simulation loop. This loop is executed by all
176 * simulation threads (the main thread and the subordinate threads) in
180 doSimLoop(EventQueue
*eventq
)
182 // set the per thread current eventq pointer
183 curEventQueue(eventq
);
184 eventq
->handleAsyncInsertions();
187 // there should always be at least one event (the SimLoopExitEvent
188 // we just scheduled) in the queue
189 assert(!eventq
->empty());
190 assert(curTick() <= eventq
->nextTick() &&
191 "event scheduled in the past");
193 if (async_event
&& testAndClearAsyncEvent()) {
194 // Take the event queue lock in case any of the service
195 // routines want to schedule new events.
196 std::lock_guard
<EventQueue
> lock(*eventq
);
197 if (async_statdump
|| async_statreset
) {
198 Stats::schedStatEvent(async_statdump
, async_statreset
);
199 async_statdump
= false;
200 async_statreset
= false;
210 exitSimLoop("user interrupt received");
213 if (async_exception
) {
214 async_exception
= false;
219 Event
*exit_event
= eventq
->serviceOne();
220 if (exit_event
!= NULL
) {
225 // not reached... only exit is return on SimLoopExitEvent