gem5  v22.1.0.0
simulate.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021 Arm Limited
3  * All rights reserved
4  *
5  * The license below extends only to copyright in the software and shall
6  * not be construed as granting a license to any other intellectual
7  * property including but not limited to intellectual property relating
8  * to a hardware implementation of the functionality of the software
9  * licensed hereunder. You may use the software subject to the license
10  * terms below provided that you ensure that this notice is replicated
11  * unmodified and in its entirety in all distributions of the software,
12  * modified or unmodified, in source code or in binary form.
13  *
14  * Copyright (c) 2006 The Regents of The University of Michigan
15  * Copyright (c) 2013 Advanced Micro Devices, Inc.
16  * Copyright (c) 2013 Mark D. Hill and David A. Wood
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions are
21  * met: redistributions of source code must retain the above copyright
22  * notice, this list of conditions and the following disclaimer;
23  * redistributions in binary form must reproduce the above copyright
24  * notice, this list of conditions and the following disclaimer in the
25  * documentation and/or other materials provided with the distribution;
26  * neither the name of the copyright holders nor the names of its
27  * contributors may be used to endorse or promote products derived from
28  * this software without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41  */
42 
43 #include "sim/simulate.hh"
44 
45 #include <atomic>
46 #include <mutex>
47 #include <thread>
48 
49 #include "base/logging.hh"
50 #include "base/pollevent.hh"
51 #include "base/types.hh"
52 #include "sim/async.hh"
53 #include "sim/eventq.hh"
54 #include "sim/sim_events.hh"
55 #include "sim/sim_exit.hh"
56 #include "sim/stat_control.hh"
57 
58 namespace gem5
59 {
60 
62 Event *doSimLoop(EventQueue *);
63 
65 
67 {
68  public:
69  SimulatorThreads() = delete;
72 
73  SimulatorThreads(uint32_t num_queues)
74  : terminate(false),
75  numQueues(num_queues),
76  barrier(num_queues)
77  {
78  threads.reserve(num_queues);
79  }
80 
82  {
83  // This should only happen after exit has been
84  // called. Subordinate event queues should normally (assuming
85  // exit is called from Python) be waiting on the barrier when
86  // this happens.
87  //
88  // N.B.: Not terminating here would make it impossible to
89  // safely destroy the barrier.
91  }
92 
94  {
95  assert(!terminate);
96 
97  // Start subordinate threads if needed.
98  if (threads.empty()) {
99  // the main thread (the one running Python) handles queue 0,
100  // so we only need to allocate new threads for queues 1..N-1.
101  // We'll call these the "subordinate" threads.
102  for (uint32_t i = 1; i < numQueues; i++) {
103  threads.emplace_back(
104  [this](EventQueue *eq) {
105  thread_main(eq);
106  }, mainEventQueue[i]);
107  }
108  }
109 
110  // This method is called from the main thread. All subordinate
111  // threads should be waiting on the barrier when the function
112  // is called. The arrival of the main thread here will satisfy
113  // the barrier and start another iteration in the thread loop.
114  barrier.wait();
115  }
116 
117  void
119  {
120  assert(!terminate);
121  if (threads.empty())
122  return;
123 
124  /* This function should only be called when the simulator is
125  * handling a global exit event (typically from Python). This
126  * means that the helper threads will be waiting on the
127  * barrier. Tell the helper threads to exit and release them from
128  * their barrier. */
129  terminate = true;
130  barrier.wait();
131 
132  /* Wait for all of the threads to terminate */
133  for (auto &t : threads) {
134  t.join();
135  }
136 
137  terminate = false;
138  threads.clear();
139  }
140 
141  protected:
150  void
152  {
153  /* Wait for all initialisation to complete */
154  barrier.wait();
155 
156  while (!terminate) {
157  doSimLoop(queue);
158  barrier.wait();
159  }
160  }
161 
162  std::atomic<bool> terminate;
163  uint32_t numQueues;
166 };
167 
168 static std::unique_ptr<SimulatorThreads> simulatorThreads;
169 
171 {
173  {
174  if (!event)
175  return;
176 
177  event->deschedule();
178  delete event;
179  }
180 };
181 
187 GlobalSimLoopExitEvent *
188 simulate(Tick num_cycles)
189 {
190  std::unique_ptr<GlobalSyncEvent, DescheduleDeleter> quantum_event;
191 
192  inform("Entering event queue @ %d. Starting simulation...\n", curTick());
193 
194  if (!simulatorThreads)
196 
197  if (!simulate_limit_event) {
198  // If the simulate_limit_event is not set, we set it to MaxTick.
200  }
201 
202  if (num_cycles != -1) {
203  // If the user has specified an exit event after X cycles, do so here.
204  // Note: This will override any prior set max_tick behaviour (such as
205  // that above when it is set to MAxTick).
206  const Tick max_tick = num_cycles < MaxTick - curTick() ?
207  curTick() + num_cycles : MaxTick;
208 
209  // This is kept to `set_max_tick` instead of `schedule_tick_exit` to
210  // preserve backwards functionality. It may be better to deprecate this
211  // behaviour at some point in favor of `schedule_tick_exit`.
212  set_max_tick(max_tick);
213  }
214 
215  if (numMainEventQueues > 1) {
216  fatal_if(simQuantum == 0,
217  "Quantum for multi-eventq simulation not specified");
218 
219  quantum_event.reset(
222 
223  inParallelMode = true;
224  }
225 
226  simulatorThreads->runUntilLocalExit();
227  Event *local_event = doSimLoop(mainEventQueue[0]);
228  assert(local_event);
229 
230  inParallelMode = false;
231 
232  // locate the global exit event and return it to Python
233  BaseGlobalEvent *global_event = local_event->globalEvent();
234  assert(global_event);
235 
236  GlobalSimLoopExitEvent *global_exit_event =
237  dynamic_cast<GlobalSimLoopExitEvent *>(global_event);
238  assert(global_exit_event);
239 
240  return global_exit_event;
241 }
242 
243 void set_max_tick(Tick tick)
244 {
245  if (!simulate_limit_event) {
247  mainEventQueue[0]->getCurTick(),
248  "simulate() limit reached", 0);
249  }
251 }
252 
253 
255 {
256  if (!simulate_limit_event) {
257  /* If the GlobalSimLoopExitEvent has not been setup, the maximum tick
258  * is `MaxTick` as declared in "src/base/types.hh".
259  */
260  return MaxTick;
261  }
262 
263  return simulate_limit_event->when();
264 }
265 
266 void
268 {
269  simulatorThreads->terminateThreads();
270 }
271 
272 
278 static bool
280 {
281  static std::mutex mutex;
282 
283  bool was_set = false;
284  mutex.lock();
285 
286  if (async_event) {
287  was_set = true;
288  async_event = false;
289  }
290 
291  mutex.unlock();
292  return was_set;
293 }
294 
300 Event *
302 {
303  // set the per thread current eventq pointer
304  curEventQueue(eventq);
305  eventq->handleAsyncInsertions();
306 
307  while (1) {
308  // there should always be at least one event (the SimLoopExitEvent
309  // we just scheduled) in the queue
310  assert(!eventq->empty());
311  assert(curTick() <= eventq->nextTick() &&
312  "event scheduled in the past");
313 
315  // Take the event queue lock in case any of the service
316  // routines want to schedule new events.
317  std::lock_guard<EventQueue> lock(*eventq);
320  async_statdump = false;
321  async_statreset = false;
322  }
323 
324  if (async_io) {
325  async_io = false;
326  pollQueue.service();
327  }
328 
329  if (async_exit) {
330  async_exit = false;
331  exitSimLoop("user interrupt received");
332  }
333 
334  if (async_exception) {
335  async_exception = false;
336  return NULL;
337  }
338  }
339 
340  Event *exit_event = eventq->serviceOne();
341  if (exit_event != NULL) {
342  return exit_event;
343  }
344  }
345 
346  // not reached... only exit is return on SimLoopExitEvent
347 }
348 
349 } // namespace gem5
This file defines flags used to handle asynchronous simulator events.
Defines global host-dependent types: Counter, Tick, and (indirectly) {int,uint}{8,...
bool wait()
Definition: barrier.hh:66
Common base class for GlobalEvent and GlobalSyncEvent.
Definition: global_event.hh:64
void reschedule(Tick when)
Queue of events sorted in time order.
Definition: eventq.hh:623
Event * serviceOne()
Definition: eventq.cc:198
Tick nextTick() const
Definition: eventq.hh:843
void handleAsyncInsertions()
Function for moving events from the async_queue to the main queue.
Definition: eventq.cc:432
virtual BaseGlobalEvent * globalEvent()
If this is part of a GlobalEvent, return the pointer to the Global Event.
Definition: eventq.hh:520
A special global event that synchronizes all threads and forces them to process asynchronously enqueu...
SimulatorThreads(uint32_t num_queues)
Definition: simulate.cc:73
std::vector< std::thread > threads
Definition: simulate.cc:164
void thread_main(EventQueue *queue)
The main function for all subordinate threads (i.e., all threads other than the main thread).
Definition: simulate.cc:151
std::atomic< bool > terminate
Definition: simulate.cc:162
SimulatorThreads(const SimulatorThreads &)=delete
SimulatorThreads & operator=(SimulatorThreads &)=delete
static const Priority Progress_Event_Pri
Progress events come at the end.
Definition: eventq.hh:226
bool empty() const
Returns true if no events are queued.
Definition: eventq.hh:898
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:226
PollQueue pollQueue
Definition: pollevent.cc:55
#define inform(...)
Definition: logging.hh:247
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 10, 5 > event
Bitfield< 29 > eq
Definition: misc.hh:58
Bitfield< 51 > t
Definition: pagetable.hh:56
Bitfield< 5 > lock
Definition: types.hh:82
void schedStatEvent(bool dump, bool reset, Tick when, Tick repeat)
Schedule statistics dumping.
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Tick simQuantum
Simulation Quantum for multiple eventq simulation.
Definition: eventq.cc:48
void set_max_tick(Tick tick)
Set the maximum tick.
Definition: simulate.cc:243
static bool testAndClearAsyncEvent()
Test and clear the global async_event flag, such that each time the flag is cleared,...
Definition: simulate.cc:279
volatile bool async_event
Some asynchronous event has happened.
Definition: async.cc:32
volatile bool async_statdump
Async request to dump stats.
Definition: async.cc:33
GlobalSimLoopExitEvent * simulate_limit_event
Definition: simulate.cc:64
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
static std::unique_ptr< SimulatorThreads > simulatorThreads
Definition: simulate.cc:168
Tick get_max_tick()
Get the maximum simulation tick.
Definition: simulate.cc:254
uint64_t Tick
Tick count type.
Definition: types.hh:58
void exitSimLoop(const std::string &message, int exit_code, Tick when, Tick repeat, bool serialize)
Schedule an event to exit the simulation loop (returning to Python) at the end of the current cycle (...
Definition: sim_events.cc:88
EventQueue * curEventQueue()
Definition: eventq.hh:88
const Tick MaxTick
Definition: types.hh:60
uint32_t numMainEventQueues
Current number of allocated main event queues.
Definition: eventq.cc:56
void terminateEventQueueThreads()
Terminate helper threads when running in parallel mode.
Definition: simulate.cc:267
GlobalSimLoopExitEvent * simulate(Tick num_cycles)
Simulate for num_cycles additional cycles.
Definition: simulate.cc:188
volatile bool async_io
Async I/O request (SIGIO).
Definition: async.cc:36
volatile bool async_exit
Async request to exit simulator.
Definition: async.cc:35
volatile bool async_statreset
Async request to reset stats.
Definition: async.cc:34
bool inParallelMode
Current mode of execution: parallel / serial.
Definition: eventq.cc:59
Event * doSimLoop(EventQueue *)
forward declaration
Definition: simulate.cc:301
volatile bool async_exception
Python exception.
Definition: async.cc:37
std::vector< EventQueue * > mainEventQueue
Array for main event queues.
Definition: eventq.cc:57
void operator()(BaseGlobalEvent *event)
Definition: simulate.cc:172

Generated on Wed Dec 21 2022 10:22:40 for gem5 by doxygen 1.9.1