simulate.py (12563:8d59ed22ae79) simulate.py (13663:9b64aeabf9a5)
1# Copyright (c) 2012 ARM Limited
2# All rights reserved.
3#
4# The license below extends only to copyright in the software and shall
5# not be construed as granting a license to any other intellectual
6# property including but not limited to intellectual property relating
7# to a hardware implementation of the functionality of the software
8# licensed hereunder. You may use the software subject to the license
9# terms below provided that you ensure that this notice is replicated
10# unmodified and in its entirety in all distributions of the software,
11# modified or unmodified, in source code or in binary form.
12#
13# Copyright (c) 2005 The Regents of The University of Michigan
14# Copyright (c) 2010 Advanced Micro Devices, Inc.
15# All rights reserved.
16#
17# Redistribution and use in source and binary forms, with or without
18# modification, are permitted provided that the following conditions are
19# met: redistributions of source code must retain the above copyright
20# notice, this list of conditions and the following disclaimer;
21# redistributions in binary form must reproduce the above copyright
22# notice, this list of conditions and the following disclaimer in the
23# documentation and/or other materials provided with the distribution;
24# neither the name of the copyright holders nor the names of its
25# contributors may be used to endorse or promote products derived from
26# this software without specific prior written permission.
27#
28# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39#
40# Authors: Nathan Binkert
41# Steve Reinhardt
42
43from __future__ import print_function
44
45import atexit
46import os
47import sys
48
49# import the wrapped C++ functions
50import _m5.drain
51import _m5.core
52from _m5.stats import updateEvents as updateStatEvents
53
54import stats
55import SimObject
56import ticks
57import objects
58from m5.util.dot_writer import do_dot, do_dvfs_dot
59
60from util import fatal
61from util import attrdict
62
63# define a MaxTick parameter, unsigned 64 bit
64MaxTick = 2**64 - 1
65
66_memory_modes = {
67 "atomic" : objects.params.atomic,
68 "timing" : objects.params.timing,
69 "atomic_noncaching" : objects.params.atomic_noncaching,
70 }
71
72_drain_manager = _m5.drain.DrainManager.instance()
73
74# The final hook to generate .ini files. Called from the user script
75# once the config is built.
76def instantiate(ckpt_dir=None):
77 from m5 import options
78
79 root = objects.Root.getInstance()
80
81 if not root:
82 fatal("Need to instantiate Root() before calling instantiate()")
83
84 # we need to fix the global frequency
85 ticks.fixGlobalFrequency()
86
87 # Make sure SimObject-valued params are in the configuration
88 # hierarchy so we catch them with future descendants() walks
89 for obj in root.descendants(): obj.adoptOrphanParams()
90
91 # Unproxy in sorted order for determinism
92 for obj in root.descendants(): obj.unproxyParams()
93
94 if options.dump_config:
95 ini_file = file(os.path.join(options.outdir, options.dump_config), 'w')
96 # Print ini sections in sorted order for easier diffing
97 for obj in sorted(root.descendants(), key=lambda o: o.path()):
98 obj.print_ini(ini_file)
99 ini_file.close()
100
101 if options.json_config:
102 try:
103 import json
104 json_file = file(os.path.join(options.outdir, options.json_config), 'w')
105 d = root.get_config_as_dict()
106 json.dump(d, json_file, indent=4)
107 json_file.close()
108 except ImportError:
109 pass
110
111 do_dot(root, options.outdir, options.dot_config)
112
113 # Initialize the global statistics
114 stats.initSimStats()
115
116 # Create the C++ sim objects and connect ports
117 for obj in root.descendants(): obj.createCCObject()
118 for obj in root.descendants(): obj.connectPorts()
119
120 # Do a second pass to finish initializing the sim objects
121 for obj in root.descendants(): obj.init()
122
123 # Do a third pass to initialize statistics
124 for obj in root.descendants(): obj.regStats()
125
126 # Do a fourth pass to initialize probe points
127 for obj in root.descendants(): obj.regProbePoints()
128
129 # Do a fifth pass to connect probe listeners
130 for obj in root.descendants(): obj.regProbeListeners()
131
132 # We want to generate the DVFS diagram for the system. This can only be
133 # done once all of the CPP objects have been created and initialised so
134 # that we are able to figure out which object belongs to which domain.
135 if options.dot_dvfs_config:
136 do_dvfs_dot(root, options.outdir, options.dot_dvfs_config)
137
138 # We're done registering statistics. Enable the stats package now.
139 stats.enable()
140
141 # Restore checkpoint (if any)
142 if ckpt_dir:
143 _drain_manager.preCheckpointRestore()
144 ckpt = _m5.core.getCheckpoint(ckpt_dir)
145 _m5.core.unserializeGlobals(ckpt);
146 for obj in root.descendants(): obj.loadState(ckpt)
147 else:
148 for obj in root.descendants(): obj.initState()
149
150 # Check to see if any of the stat events are in the past after resuming from
151 # a checkpoint, If so, this call will shift them to be at a valid time.
152 updateStatEvents()
153
154need_startup = True
155def simulate(*args, **kwargs):
156 global need_startup
157
158 if need_startup:
159 root = objects.Root.getInstance()
160 for obj in root.descendants(): obj.startup()
161 need_startup = False
162
163 # Python exit handlers happen in reverse order.
164 # We want to dump stats last.
165 atexit.register(stats.dump)
166
167 # register our C++ exit callback function with Python
168 atexit.register(_m5.core.doExitCleanup)
169
170 # Reset to put the stats in a consistent state.
171 stats.reset()
172
173 if _drain_manager.isDrained():
174 _drain_manager.resume()
175
176 return _m5.event.simulate(*args, **kwargs)
177
178def drain():
179 """Drain the simulator in preparation of a checkpoint or memory mode
180 switch.
181
182 This operation is a no-op if the simulator is already in the
183 Drained state.
184
185 """
186
187 # Try to drain all objects. Draining might not be completed unless
188 # all objects return that they are drained on the first call. This
189 # is because as objects drain they may cause other objects to no
190 # longer be drained.
191 def _drain():
192 # Try to drain the system. The drain is successful if all
193 # objects are done without simulation. We need to simulate
194 # more if not.
195 if _drain_manager.tryDrain():
196 return True
197
198 # WARNING: if a valid exit event occurs while draining, it
199 # will not get returned to the user script
200 exit_event = _m5.event.simulate()
201 while exit_event.getCause() != 'Finished drain':
202 exit_event = simulate()
203
204 return False
205
206 # Don't try to drain a system that is already drained
207 is_drained = _drain_manager.isDrained()
208 while not is_drained:
209 is_drained = _drain()
210
211 assert _drain_manager.isDrained(), "Drain state inconsistent"
212
213def memWriteback(root):
214 for obj in root.descendants():
215 obj.memWriteback()
216
217def memInvalidate(root):
218 for obj in root.descendants():
219 obj.memInvalidate()
220
221def checkpoint(dir):
222 root = objects.Root.getInstance()
223 if not isinstance(root, objects.Root):
1# Copyright (c) 2012 ARM Limited
2# All rights reserved.
3#
4# The license below extends only to copyright in the software and shall
5# not be construed as granting a license to any other intellectual
6# property including but not limited to intellectual property relating
7# to a hardware implementation of the functionality of the software
8# licensed hereunder. You may use the software subject to the license
9# terms below provided that you ensure that this notice is replicated
10# unmodified and in its entirety in all distributions of the software,
11# modified or unmodified, in source code or in binary form.
12#
13# Copyright (c) 2005 The Regents of The University of Michigan
14# Copyright (c) 2010 Advanced Micro Devices, Inc.
15# All rights reserved.
16#
17# Redistribution and use in source and binary forms, with or without
18# modification, are permitted provided that the following conditions are
19# met: redistributions of source code must retain the above copyright
20# notice, this list of conditions and the following disclaimer;
21# redistributions in binary form must reproduce the above copyright
22# notice, this list of conditions and the following disclaimer in the
23# documentation and/or other materials provided with the distribution;
24# neither the name of the copyright holders nor the names of its
25# contributors may be used to endorse or promote products derived from
26# this software without specific prior written permission.
27#
28# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39#
40# Authors: Nathan Binkert
41# Steve Reinhardt
42
43from __future__ import print_function
44
45import atexit
46import os
47import sys
48
49# import the wrapped C++ functions
50import _m5.drain
51import _m5.core
52from _m5.stats import updateEvents as updateStatEvents
53
54import stats
55import SimObject
56import ticks
57import objects
58from m5.util.dot_writer import do_dot, do_dvfs_dot
59
60from util import fatal
61from util import attrdict
62
63# define a MaxTick parameter, unsigned 64 bit
64MaxTick = 2**64 - 1
65
66_memory_modes = {
67 "atomic" : objects.params.atomic,
68 "timing" : objects.params.timing,
69 "atomic_noncaching" : objects.params.atomic_noncaching,
70 }
71
72_drain_manager = _m5.drain.DrainManager.instance()
73
74# The final hook to generate .ini files. Called from the user script
75# once the config is built.
76def instantiate(ckpt_dir=None):
77 from m5 import options
78
79 root = objects.Root.getInstance()
80
81 if not root:
82 fatal("Need to instantiate Root() before calling instantiate()")
83
84 # we need to fix the global frequency
85 ticks.fixGlobalFrequency()
86
87 # Make sure SimObject-valued params are in the configuration
88 # hierarchy so we catch them with future descendants() walks
89 for obj in root.descendants(): obj.adoptOrphanParams()
90
91 # Unproxy in sorted order for determinism
92 for obj in root.descendants(): obj.unproxyParams()
93
94 if options.dump_config:
95 ini_file = file(os.path.join(options.outdir, options.dump_config), 'w')
96 # Print ini sections in sorted order for easier diffing
97 for obj in sorted(root.descendants(), key=lambda o: o.path()):
98 obj.print_ini(ini_file)
99 ini_file.close()
100
101 if options.json_config:
102 try:
103 import json
104 json_file = file(os.path.join(options.outdir, options.json_config), 'w')
105 d = root.get_config_as_dict()
106 json.dump(d, json_file, indent=4)
107 json_file.close()
108 except ImportError:
109 pass
110
111 do_dot(root, options.outdir, options.dot_config)
112
113 # Initialize the global statistics
114 stats.initSimStats()
115
116 # Create the C++ sim objects and connect ports
117 for obj in root.descendants(): obj.createCCObject()
118 for obj in root.descendants(): obj.connectPorts()
119
120 # Do a second pass to finish initializing the sim objects
121 for obj in root.descendants(): obj.init()
122
123 # Do a third pass to initialize statistics
124 for obj in root.descendants(): obj.regStats()
125
126 # Do a fourth pass to initialize probe points
127 for obj in root.descendants(): obj.regProbePoints()
128
129 # Do a fifth pass to connect probe listeners
130 for obj in root.descendants(): obj.regProbeListeners()
131
132 # We want to generate the DVFS diagram for the system. This can only be
133 # done once all of the CPP objects have been created and initialised so
134 # that we are able to figure out which object belongs to which domain.
135 if options.dot_dvfs_config:
136 do_dvfs_dot(root, options.outdir, options.dot_dvfs_config)
137
138 # We're done registering statistics. Enable the stats package now.
139 stats.enable()
140
141 # Restore checkpoint (if any)
142 if ckpt_dir:
143 _drain_manager.preCheckpointRestore()
144 ckpt = _m5.core.getCheckpoint(ckpt_dir)
145 _m5.core.unserializeGlobals(ckpt);
146 for obj in root.descendants(): obj.loadState(ckpt)
147 else:
148 for obj in root.descendants(): obj.initState()
149
150 # Check to see if any of the stat events are in the past after resuming from
151 # a checkpoint, If so, this call will shift them to be at a valid time.
152 updateStatEvents()
153
154need_startup = True
155def simulate(*args, **kwargs):
156 global need_startup
157
158 if need_startup:
159 root = objects.Root.getInstance()
160 for obj in root.descendants(): obj.startup()
161 need_startup = False
162
163 # Python exit handlers happen in reverse order.
164 # We want to dump stats last.
165 atexit.register(stats.dump)
166
167 # register our C++ exit callback function with Python
168 atexit.register(_m5.core.doExitCleanup)
169
170 # Reset to put the stats in a consistent state.
171 stats.reset()
172
173 if _drain_manager.isDrained():
174 _drain_manager.resume()
175
176 return _m5.event.simulate(*args, **kwargs)
177
178def drain():
179 """Drain the simulator in preparation of a checkpoint or memory mode
180 switch.
181
182 This operation is a no-op if the simulator is already in the
183 Drained state.
184
185 """
186
187 # Try to drain all objects. Draining might not be completed unless
188 # all objects return that they are drained on the first call. This
189 # is because as objects drain they may cause other objects to no
190 # longer be drained.
191 def _drain():
192 # Try to drain the system. The drain is successful if all
193 # objects are done without simulation. We need to simulate
194 # more if not.
195 if _drain_manager.tryDrain():
196 return True
197
198 # WARNING: if a valid exit event occurs while draining, it
199 # will not get returned to the user script
200 exit_event = _m5.event.simulate()
201 while exit_event.getCause() != 'Finished drain':
202 exit_event = simulate()
203
204 return False
205
206 # Don't try to drain a system that is already drained
207 is_drained = _drain_manager.isDrained()
208 while not is_drained:
209 is_drained = _drain()
210
211 assert _drain_manager.isDrained(), "Drain state inconsistent"
212
213def memWriteback(root):
214 for obj in root.descendants():
215 obj.memWriteback()
216
217def memInvalidate(root):
218 for obj in root.descendants():
219 obj.memInvalidate()
220
221def checkpoint(dir):
222 root = objects.Root.getInstance()
223 if not isinstance(root, objects.Root):
224 raise TypeError, "Checkpoint must be called on a root object."
224 raise TypeError("Checkpoint must be called on a root object.")
225
226 drain()
227 memWriteback(root)
228 print("Writing checkpoint")
229 _m5.core.serializeAll(dir)
230
231def _changeMemoryMode(system, mode):
232 if not isinstance(system, (objects.Root, objects.System)):
225
226 drain()
227 memWriteback(root)
228 print("Writing checkpoint")
229 _m5.core.serializeAll(dir)
230
231def _changeMemoryMode(system, mode):
232 if not isinstance(system, (objects.Root, objects.System)):
233 raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
234 (type(system), objects.Root, objects.System)
233 raise TypeError("Parameter of type '%s'. Must be type %s or %s." % \
234 (type(system), objects.Root, objects.System))
235 if system.getMemoryMode() != mode:
236 system.setMemoryMode(mode)
237 else:
238 print("System already in target mode. Memory mode unchanged.")
239
240def switchCpus(system, cpuList, verbose=True):
241 """Switch CPUs in a system.
242
243 Note: This method may switch the memory mode of the system if that
244 is required by the CPUs. It may also flush all caches in the
245 system.
246
247 Arguments:
248 system -- Simulated system.
249 cpuList -- (old_cpu, new_cpu) tuples
250 """
251
252 if verbose:
253 print("switching cpus")
254
255 if not isinstance(cpuList, list):
235 if system.getMemoryMode() != mode:
236 system.setMemoryMode(mode)
237 else:
238 print("System already in target mode. Memory mode unchanged.")
239
240def switchCpus(system, cpuList, verbose=True):
241 """Switch CPUs in a system.
242
243 Note: This method may switch the memory mode of the system if that
244 is required by the CPUs. It may also flush all caches in the
245 system.
246
247 Arguments:
248 system -- Simulated system.
249 cpuList -- (old_cpu, new_cpu) tuples
250 """
251
252 if verbose:
253 print("switching cpus")
254
255 if not isinstance(cpuList, list):
256 raise RuntimeError, "Must pass a list to this function"
256 raise RuntimeError("Must pass a list to this function")
257 for item in cpuList:
258 if not isinstance(item, tuple) or len(item) != 2:
257 for item in cpuList:
258 if not isinstance(item, tuple) or len(item) != 2:
259 raise RuntimeError, "List must have tuples of (oldCPU,newCPU)"
259 raise RuntimeError("List must have tuples of (oldCPU,newCPU)")
260
261 old_cpus = [old_cpu for old_cpu, new_cpu in cpuList]
262 new_cpus = [new_cpu for old_cpu, new_cpu in cpuList]
263 old_cpu_set = set(old_cpus)
264 memory_mode_name = new_cpus[0].memory_mode()
265 for old_cpu, new_cpu in cpuList:
266 if not isinstance(old_cpu, objects.BaseCPU):
260
261 old_cpus = [old_cpu for old_cpu, new_cpu in cpuList]
262 new_cpus = [new_cpu for old_cpu, new_cpu in cpuList]
263 old_cpu_set = set(old_cpus)
264 memory_mode_name = new_cpus[0].memory_mode()
265 for old_cpu, new_cpu in cpuList:
266 if not isinstance(old_cpu, objects.BaseCPU):
267 raise TypeError, "%s is not of type BaseCPU" % old_cpu
267 raise TypeError("%s is not of type BaseCPU" % old_cpu)
268 if not isinstance(new_cpu, objects.BaseCPU):
268 if not isinstance(new_cpu, objects.BaseCPU):
269 raise TypeError, "%s is not of type BaseCPU" % new_cpu
269 raise TypeError("%s is not of type BaseCPU" % new_cpu)
270 if new_cpu in old_cpu_set:
270 if new_cpu in old_cpu_set:
271 raise RuntimeError, \
272 "New CPU (%s) is in the list of old CPUs." % (old_cpu,)
271 raise RuntimeError(
272 "New CPU (%s) is in the list of old CPUs." % (old_cpu,))
273 if not new_cpu.switchedOut():
273 if not new_cpu.switchedOut():
274 raise RuntimeError, \
275 "New CPU (%s) is already active." % (new_cpu,)
274 raise RuntimeError("New CPU (%s) is already active." % (new_cpu,))
276 if not new_cpu.support_take_over():
275 if not new_cpu.support_take_over():
277 raise RuntimeError, \
278 "New CPU (%s) does not support CPU handover." % (old_cpu,)
276 raise RuntimeError(
277 "New CPU (%s) does not support CPU handover." % (old_cpu,))
279 if new_cpu.memory_mode() != memory_mode_name:
278 if new_cpu.memory_mode() != memory_mode_name:
280 raise RuntimeError, \
279 raise RuntimeError(
281 "%s and %s require different memory modes." % (new_cpu,
280 "%s and %s require different memory modes." % (new_cpu,
282 new_cpus[0])
281 new_cpus[0]))
283 if old_cpu.switchedOut():
282 if old_cpu.switchedOut():
284 raise RuntimeError, \
285 "Old CPU (%s) is inactive." % (new_cpu,)
283 raise RuntimeError("Old CPU (%s) is inactive." % (new_cpu,))
286 if not old_cpu.support_take_over():
284 if not old_cpu.support_take_over():
287 raise RuntimeError, \
288 "Old CPU (%s) does not support CPU handover." % (old_cpu,)
285 raise RuntimeError(
286 "Old CPU (%s) does not support CPU handover." % (old_cpu,))
289
290 try:
291 memory_mode = _memory_modes[memory_mode_name]
292 except KeyError:
287
288 try:
289 memory_mode = _memory_modes[memory_mode_name]
290 except KeyError:
293 raise RuntimeError, "Invalid memory mode (%s)" % memory_mode_name
291 raise RuntimeError("Invalid memory mode (%s)" % memory_mode_name)
294
295 drain()
296
297 # Now all of the CPUs are ready to be switched out
298 for old_cpu, new_cpu in cpuList:
299 old_cpu.switchOut()
300
301 # Change the memory mode if required. We check if this is needed
302 # to avoid printing a warning if no switch was performed.
303 if system.getMemoryMode() != memory_mode:
304 # Flush the memory system if we are switching to a memory mode
305 # that disables caches. This typically happens when switching to a
306 # hardware virtualized CPU.
307 if memory_mode == objects.params.atomic_noncaching:
308 memWriteback(system)
309 memInvalidate(system)
310
311 _changeMemoryMode(system, memory_mode)
312
313 for old_cpu, new_cpu in cpuList:
314 new_cpu.takeOverFrom(old_cpu)
315
316def notifyFork(root):
317 for obj in root.descendants():
318 obj.notifyFork()
319
320fork_count = 0
321def fork(simout="%(parent)s.f%(fork_seq)i"):
322 """Fork the simulator.
323
324 This function forks the simulator. After forking the simulator,
325 the child process gets its output files redirected to a new output
326 directory. The default name of the output directory is the same as
327 the parent with the suffix ".fN" added where N is the fork
328 sequence number. The name of the output directory can be
329 overridden using the simout keyword argument.
330
331 Output file formatting dictionary:
332 parent -- Path to the parent process's output directory.
333 fork_seq -- Fork sequence number.
334 pid -- PID of the child process.
335
336 Keyword Arguments:
337 simout -- New simulation output directory.
338
339 Return Value:
340 pid of the child process or 0 if running in the child.
341 """
342 from m5 import options
343 global fork_count
344
345 if not _m5.core.listenersDisabled():
292
293 drain()
294
295 # Now all of the CPUs are ready to be switched out
296 for old_cpu, new_cpu in cpuList:
297 old_cpu.switchOut()
298
299 # Change the memory mode if required. We check if this is needed
300 # to avoid printing a warning if no switch was performed.
301 if system.getMemoryMode() != memory_mode:
302 # Flush the memory system if we are switching to a memory mode
303 # that disables caches. This typically happens when switching to a
304 # hardware virtualized CPU.
305 if memory_mode == objects.params.atomic_noncaching:
306 memWriteback(system)
307 memInvalidate(system)
308
309 _changeMemoryMode(system, memory_mode)
310
311 for old_cpu, new_cpu in cpuList:
312 new_cpu.takeOverFrom(old_cpu)
313
314def notifyFork(root):
315 for obj in root.descendants():
316 obj.notifyFork()
317
318fork_count = 0
319def fork(simout="%(parent)s.f%(fork_seq)i"):
320 """Fork the simulator.
321
322 This function forks the simulator. After forking the simulator,
323 the child process gets its output files redirected to a new output
324 directory. The default name of the output directory is the same as
325 the parent with the suffix ".fN" added where N is the fork
326 sequence number. The name of the output directory can be
327 overridden using the simout keyword argument.
328
329 Output file formatting dictionary:
330 parent -- Path to the parent process's output directory.
331 fork_seq -- Fork sequence number.
332 pid -- PID of the child process.
333
334 Keyword Arguments:
335 simout -- New simulation output directory.
336
337 Return Value:
338 pid of the child process or 0 if running in the child.
339 """
340 from m5 import options
341 global fork_count
342
343 if not _m5.core.listenersDisabled():
346 raise RuntimeError, "Can not fork a simulator with listeners enabled"
344 raise RuntimeError("Can not fork a simulator with listeners enabled")
347
348 drain()
349
350 try:
351 pid = os.fork()
345
346 drain()
347
348 try:
349 pid = os.fork()
352 except OSError, e:
350 except OSError as e:
353 raise e
354
355 if pid == 0:
356 # In child, notify objects of the fork
357 root = objects.Root.getInstance()
358 notifyFork(root)
359 # Setup a new output directory
360 parent = options.outdir
361 options.outdir = simout % {
362 "parent" : parent,
363 "fork_seq" : fork_count,
364 "pid" : os.getpid(),
365 }
366 _m5.core.setOutputDir(options.outdir)
367 else:
368 fork_count += 1
369
370 return pid
371
372from _m5.core import disableAllListeners, listenersDisabled
373from _m5.core import listenersLoopbackOnly
374from _m5.core import curTick
351 raise e
352
353 if pid == 0:
354 # In child, notify objects of the fork
355 root = objects.Root.getInstance()
356 notifyFork(root)
357 # Setup a new output directory
358 parent = options.outdir
359 options.outdir = simout % {
360 "parent" : parent,
361 "fork_seq" : fork_count,
362 "pid" : os.getpid(),
363 }
364 _m5.core.setOutputDir(options.outdir)
365 else:
366 fork_count += 1
367
368 return pid
369
370from _m5.core import disableAllListeners, listenersDisabled
371from _m5.core import listenersLoopbackOnly
372from _m5.core import curTick