simulate.py (11431:871eaaa0ab24) simulate.py (11802:be62996c95d1)
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
43import atexit
44import os
45import sys
46
47# import the SWIG-wrapped main C++ functions
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
43import atexit
44import os
45import sys
46
47# import the SWIG-wrapped main C++ functions
48import internal
49import core
48import _m5.drain
49import _m5.core
50from _m5.stats import updateEvents as updateStatEvents
51
50import stats
51import SimObject
52import ticks
53import objects
54from m5.util.dot_writer import do_dot, do_dvfs_dot
52import stats
53import SimObject
54import ticks
55import objects
56from m5.util.dot_writer import do_dot, do_dvfs_dot
55from m5.internal.stats import updateEvents as updateStatEvents
56
57from util import fatal
58from util import attrdict
59
60# define a MaxTick parameter, unsigned 64 bit
61MaxTick = 2**64 - 1
62
63_memory_modes = {
64 "atomic" : objects.params.atomic,
65 "timing" : objects.params.timing,
66 "atomic_noncaching" : objects.params.atomic_noncaching,
67 }
68
57
58from util import fatal
59from util import attrdict
60
61# define a MaxTick parameter, unsigned 64 bit
62MaxTick = 2**64 - 1
63
64_memory_modes = {
65 "atomic" : objects.params.atomic,
66 "timing" : objects.params.timing,
67 "atomic_noncaching" : objects.params.atomic_noncaching,
68 }
69
69_drain_manager = internal.drain.DrainManager.instance()
70_drain_manager = _m5.drain.DrainManager.instance()
70
71# The final hook to generate .ini files. Called from the user script
72# once the config is built.
73def instantiate(ckpt_dir=None):
74 from m5 import options
75
76 root = objects.Root.getInstance()
77
78 if not root:
79 fatal("Need to instantiate Root() before calling instantiate()")
80
81 # we need to fix the global frequency
82 ticks.fixGlobalFrequency()
83
84 # Make sure SimObject-valued params are in the configuration
85 # hierarchy so we catch them with future descendants() walks
86 for obj in root.descendants(): obj.adoptOrphanParams()
87
88 # Unproxy in sorted order for determinism
89 for obj in root.descendants(): obj.unproxyParams()
90
91 if options.dump_config:
92 ini_file = file(os.path.join(options.outdir, options.dump_config), 'w')
93 # Print ini sections in sorted order for easier diffing
94 for obj in sorted(root.descendants(), key=lambda o: o.path()):
95 obj.print_ini(ini_file)
96 ini_file.close()
97
98 if options.json_config:
99 try:
100 import json
101 json_file = file(os.path.join(options.outdir, options.json_config), 'w')
102 d = root.get_config_as_dict()
103 json.dump(d, json_file, indent=4)
104 json_file.close()
105 except ImportError:
106 pass
107
108 do_dot(root, options.outdir, options.dot_config)
109
110 # Initialize the global statistics
111 stats.initSimStats()
112
113 # Create the C++ sim objects and connect ports
114 for obj in root.descendants(): obj.createCCObject()
115 for obj in root.descendants(): obj.connectPorts()
116
117 # Do a second pass to finish initializing the sim objects
118 for obj in root.descendants(): obj.init()
119
120 # Do a third pass to initialize statistics
121 for obj in root.descendants(): obj.regStats()
122
123 # Do a fourth pass to initialize probe points
124 for obj in root.descendants(): obj.regProbePoints()
125
126 # Do a fifth pass to connect probe listeners
127 for obj in root.descendants(): obj.regProbeListeners()
128
129 # We want to generate the DVFS diagram for the system. This can only be
130 # done once all of the CPP objects have been created and initialised so
131 # that we are able to figure out which object belongs to which domain.
132 if options.dot_dvfs_config:
133 do_dvfs_dot(root, options.outdir, options.dot_dvfs_config)
134
135 # We're done registering statistics. Enable the stats package now.
136 stats.enable()
137
138 # Restore checkpoint (if any)
139 if ckpt_dir:
140 _drain_manager.preCheckpointRestore()
71
72# The final hook to generate .ini files. Called from the user script
73# once the config is built.
74def instantiate(ckpt_dir=None):
75 from m5 import options
76
77 root = objects.Root.getInstance()
78
79 if not root:
80 fatal("Need to instantiate Root() before calling instantiate()")
81
82 # we need to fix the global frequency
83 ticks.fixGlobalFrequency()
84
85 # Make sure SimObject-valued params are in the configuration
86 # hierarchy so we catch them with future descendants() walks
87 for obj in root.descendants(): obj.adoptOrphanParams()
88
89 # Unproxy in sorted order for determinism
90 for obj in root.descendants(): obj.unproxyParams()
91
92 if options.dump_config:
93 ini_file = file(os.path.join(options.outdir, options.dump_config), 'w')
94 # Print ini sections in sorted order for easier diffing
95 for obj in sorted(root.descendants(), key=lambda o: o.path()):
96 obj.print_ini(ini_file)
97 ini_file.close()
98
99 if options.json_config:
100 try:
101 import json
102 json_file = file(os.path.join(options.outdir, options.json_config), 'w')
103 d = root.get_config_as_dict()
104 json.dump(d, json_file, indent=4)
105 json_file.close()
106 except ImportError:
107 pass
108
109 do_dot(root, options.outdir, options.dot_config)
110
111 # Initialize the global statistics
112 stats.initSimStats()
113
114 # Create the C++ sim objects and connect ports
115 for obj in root.descendants(): obj.createCCObject()
116 for obj in root.descendants(): obj.connectPorts()
117
118 # Do a second pass to finish initializing the sim objects
119 for obj in root.descendants(): obj.init()
120
121 # Do a third pass to initialize statistics
122 for obj in root.descendants(): obj.regStats()
123
124 # Do a fourth pass to initialize probe points
125 for obj in root.descendants(): obj.regProbePoints()
126
127 # Do a fifth pass to connect probe listeners
128 for obj in root.descendants(): obj.regProbeListeners()
129
130 # We want to generate the DVFS diagram for the system. This can only be
131 # done once all of the CPP objects have been created and initialised so
132 # that we are able to figure out which object belongs to which domain.
133 if options.dot_dvfs_config:
134 do_dvfs_dot(root, options.outdir, options.dot_dvfs_config)
135
136 # We're done registering statistics. Enable the stats package now.
137 stats.enable()
138
139 # Restore checkpoint (if any)
140 if ckpt_dir:
141 _drain_manager.preCheckpointRestore()
141 ckpt = internal.core.getCheckpoint(ckpt_dir)
142 internal.core.unserializeGlobals(ckpt);
142 ckpt = _m5.core.getCheckpoint(ckpt_dir)
143 _m5.core.unserializeGlobals(ckpt);
143 for obj in root.descendants(): obj.loadState(ckpt)
144 else:
145 for obj in root.descendants(): obj.initState()
146
147 # Check to see if any of the stat events are in the past after resuming from
148 # a checkpoint, If so, this call will shift them to be at a valid time.
149 updateStatEvents()
150
151need_startup = True
152def simulate(*args, **kwargs):
153 global need_startup
154
155 if need_startup:
156 root = objects.Root.getInstance()
157 for obj in root.descendants(): obj.startup()
158 need_startup = False
159
160 # Python exit handlers happen in reverse order.
161 # We want to dump stats last.
162 atexit.register(stats.dump)
163
164 # register our C++ exit callback function with Python
144 for obj in root.descendants(): obj.loadState(ckpt)
145 else:
146 for obj in root.descendants(): obj.initState()
147
148 # Check to see if any of the stat events are in the past after resuming from
149 # a checkpoint, If so, this call will shift them to be at a valid time.
150 updateStatEvents()
151
152need_startup = True
153def simulate(*args, **kwargs):
154 global need_startup
155
156 if need_startup:
157 root = objects.Root.getInstance()
158 for obj in root.descendants(): obj.startup()
159 need_startup = False
160
161 # Python exit handlers happen in reverse order.
162 # We want to dump stats last.
163 atexit.register(stats.dump)
164
165 # register our C++ exit callback function with Python
165 atexit.register(internal.core.doExitCleanup)
166 atexit.register(_m5.core.doExitCleanup)
166
167 # Reset to put the stats in a consistent state.
168 stats.reset()
169
170 if _drain_manager.isDrained():
171 _drain_manager.resume()
172
167
168 # Reset to put the stats in a consistent state.
169 stats.reset()
170
171 if _drain_manager.isDrained():
172 _drain_manager.resume()
173
173 return internal.event.simulate(*args, **kwargs)
174 return _m5.event.simulate(*args, **kwargs)
174
175
175# Export curTick to user script.
176def curTick():
177 return internal.core.curTick()
178
179def drain():
180 """Drain the simulator in preparation of a checkpoint or memory mode
181 switch.
182
183 This operation is a no-op if the simulator is already in the
184 Drained state.
185
186 """
187
188 # Try to drain all objects. Draining might not be completed unless
189 # all objects return that they are drained on the first call. This
190 # is because as objects drain they may cause other objects to no
191 # longer be drained.
192 def _drain():
193 # Try to drain the system. The drain is successful if all
194 # objects are done without simulation. We need to simulate
195 # more if not.
196 if _drain_manager.tryDrain():
197 return True
198
199 # WARNING: if a valid exit event occurs while draining, it
200 # will not get returned to the user script
176def drain():
177 """Drain the simulator in preparation of a checkpoint or memory mode
178 switch.
179
180 This operation is a no-op if the simulator is already in the
181 Drained state.
182
183 """
184
185 # Try to drain all objects. Draining might not be completed unless
186 # all objects return that they are drained on the first call. This
187 # is because as objects drain they may cause other objects to no
188 # longer be drained.
189 def _drain():
190 # Try to drain the system. The drain is successful if all
191 # objects are done without simulation. We need to simulate
192 # more if not.
193 if _drain_manager.tryDrain():
194 return True
195
196 # WARNING: if a valid exit event occurs while draining, it
197 # will not get returned to the user script
201 exit_event = internal.event.simulate()
198 exit_event = _m5.event.simulate()
202 while exit_event.getCause() != 'Finished drain':
203 exit_event = simulate()
204
205 return False
206
207 # Don't try to drain a system that is already drained
208 is_drained = _drain_manager.isDrained()
209 while not is_drained:
210 is_drained = _drain()
211
212 assert _drain_manager.isDrained(), "Drain state inconsistent"
213
214def memWriteback(root):
215 for obj in root.descendants():
216 obj.memWriteback()
217
218def memInvalidate(root):
219 for obj in root.descendants():
220 obj.memInvalidate()
221
222def checkpoint(dir):
223 root = objects.Root.getInstance()
224 if not isinstance(root, objects.Root):
225 raise TypeError, "Checkpoint must be called on a root object."
226
227 drain()
228 memWriteback(root)
229 print "Writing checkpoint"
199 while exit_event.getCause() != 'Finished drain':
200 exit_event = simulate()
201
202 return False
203
204 # Don't try to drain a system that is already drained
205 is_drained = _drain_manager.isDrained()
206 while not is_drained:
207 is_drained = _drain()
208
209 assert _drain_manager.isDrained(), "Drain state inconsistent"
210
211def memWriteback(root):
212 for obj in root.descendants():
213 obj.memWriteback()
214
215def memInvalidate(root):
216 for obj in root.descendants():
217 obj.memInvalidate()
218
219def checkpoint(dir):
220 root = objects.Root.getInstance()
221 if not isinstance(root, objects.Root):
222 raise TypeError, "Checkpoint must be called on a root object."
223
224 drain()
225 memWriteback(root)
226 print "Writing checkpoint"
230 internal.core.serializeAll(dir)
227 _m5.core.serializeAll(dir)
231
232def _changeMemoryMode(system, mode):
233 if not isinstance(system, (objects.Root, objects.System)):
234 raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
235 (type(system), objects.Root, objects.System)
236 if system.getMemoryMode() != mode:
237 system.setMemoryMode(mode)
238 else:
239 print "System already in target mode. Memory mode unchanged."
240
241def switchCpus(system, cpuList, verbose=True):
242 """Switch CPUs in a system.
243
244 Note: This method may switch the memory mode of the system if that
245 is required by the CPUs. It may also flush all caches in the
246 system.
247
248 Arguments:
249 system -- Simulated system.
250 cpuList -- (old_cpu, new_cpu) tuples
251 """
252
253 if verbose:
254 print "switching cpus"
255
256 if not isinstance(cpuList, list):
257 raise RuntimeError, "Must pass a list to this function"
258 for item in cpuList:
259 if not isinstance(item, tuple) or len(item) != 2:
260 raise RuntimeError, "List must have tuples of (oldCPU,newCPU)"
261
262 old_cpus = [old_cpu for old_cpu, new_cpu in cpuList]
263 new_cpus = [new_cpu for old_cpu, new_cpu in cpuList]
264 old_cpu_set = set(old_cpus)
265 memory_mode_name = new_cpus[0].memory_mode()
266 for old_cpu, new_cpu in cpuList:
267 if not isinstance(old_cpu, objects.BaseCPU):
268 raise TypeError, "%s is not of type BaseCPU" % old_cpu
269 if not isinstance(new_cpu, objects.BaseCPU):
270 raise TypeError, "%s is not of type BaseCPU" % new_cpu
271 if new_cpu in old_cpu_set:
272 raise RuntimeError, \
273 "New CPU (%s) is in the list of old CPUs." % (old_cpu,)
274 if not new_cpu.switchedOut():
275 raise RuntimeError, \
276 "New CPU (%s) is already active." % (new_cpu,)
277 if not new_cpu.support_take_over():
278 raise RuntimeError, \
279 "New CPU (%s) does not support CPU handover." % (old_cpu,)
280 if new_cpu.memory_mode() != memory_mode_name:
281 raise RuntimeError, \
282 "%s and %s require different memory modes." % (new_cpu,
283 new_cpus[0])
284 if old_cpu.switchedOut():
285 raise RuntimeError, \
286 "Old CPU (%s) is inactive." % (new_cpu,)
287 if not old_cpu.support_take_over():
288 raise RuntimeError, \
289 "Old CPU (%s) does not support CPU handover." % (old_cpu,)
290
291 try:
292 memory_mode = _memory_modes[memory_mode_name]
293 except KeyError:
294 raise RuntimeError, "Invalid memory mode (%s)" % memory_mode_name
295
296 drain()
297
298 # Now all of the CPUs are ready to be switched out
299 for old_cpu, new_cpu in cpuList:
300 old_cpu.switchOut()
301
302 # Change the memory mode if required. We check if this is needed
303 # to avoid printing a warning if no switch was performed.
304 if system.getMemoryMode() != memory_mode:
305 # Flush the memory system if we are switching to a memory mode
306 # that disables caches. This typically happens when switching to a
307 # hardware virtualized CPU.
308 if memory_mode == objects.params.atomic_noncaching:
309 memWriteback(system)
310 memInvalidate(system)
311
312 _changeMemoryMode(system, memory_mode)
313
314 for old_cpu, new_cpu in cpuList:
315 new_cpu.takeOverFrom(old_cpu)
316
317def notifyFork(root):
318 for obj in root.descendants():
319 obj.notifyFork()
320
321fork_count = 0
322def fork(simout="%(parent)s.f%(fork_seq)i"):
323 """Fork the simulator.
324
325 This function forks the simulator. After forking the simulator,
326 the child process gets its output files redirected to a new output
327 directory. The default name of the output directory is the same as
328 the parent with the suffix ".fN" added where N is the fork
329 sequence number. The name of the output directory can be
330 overridden using the simout keyword argument.
331
332 Output file formatting dictionary:
333 parent -- Path to the parent process's output directory.
334 fork_seq -- Fork sequence number.
335 pid -- PID of the child process.
336
337 Keyword Arguments:
338 simout -- New simulation output directory.
339
340 Return Value:
341 pid of the child process or 0 if running in the child.
342 """
343 from m5 import options
344 global fork_count
345
228
229def _changeMemoryMode(system, mode):
230 if not isinstance(system, (objects.Root, objects.System)):
231 raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
232 (type(system), objects.Root, objects.System)
233 if system.getMemoryMode() != mode:
234 system.setMemoryMode(mode)
235 else:
236 print "System already in target mode. Memory mode unchanged."
237
238def switchCpus(system, cpuList, verbose=True):
239 """Switch CPUs in a system.
240
241 Note: This method may switch the memory mode of the system if that
242 is required by the CPUs. It may also flush all caches in the
243 system.
244
245 Arguments:
246 system -- Simulated system.
247 cpuList -- (old_cpu, new_cpu) tuples
248 """
249
250 if verbose:
251 print "switching cpus"
252
253 if not isinstance(cpuList, list):
254 raise RuntimeError, "Must pass a list to this function"
255 for item in cpuList:
256 if not isinstance(item, tuple) or len(item) != 2:
257 raise RuntimeError, "List must have tuples of (oldCPU,newCPU)"
258
259 old_cpus = [old_cpu for old_cpu, new_cpu in cpuList]
260 new_cpus = [new_cpu for old_cpu, new_cpu in cpuList]
261 old_cpu_set = set(old_cpus)
262 memory_mode_name = new_cpus[0].memory_mode()
263 for old_cpu, new_cpu in cpuList:
264 if not isinstance(old_cpu, objects.BaseCPU):
265 raise TypeError, "%s is not of type BaseCPU" % old_cpu
266 if not isinstance(new_cpu, objects.BaseCPU):
267 raise TypeError, "%s is not of type BaseCPU" % new_cpu
268 if new_cpu in old_cpu_set:
269 raise RuntimeError, \
270 "New CPU (%s) is in the list of old CPUs." % (old_cpu,)
271 if not new_cpu.switchedOut():
272 raise RuntimeError, \
273 "New CPU (%s) is already active." % (new_cpu,)
274 if not new_cpu.support_take_over():
275 raise RuntimeError, \
276 "New CPU (%s) does not support CPU handover." % (old_cpu,)
277 if new_cpu.memory_mode() != memory_mode_name:
278 raise RuntimeError, \
279 "%s and %s require different memory modes." % (new_cpu,
280 new_cpus[0])
281 if old_cpu.switchedOut():
282 raise RuntimeError, \
283 "Old CPU (%s) is inactive." % (new_cpu,)
284 if not old_cpu.support_take_over():
285 raise RuntimeError, \
286 "Old CPU (%s) does not support CPU handover." % (old_cpu,)
287
288 try:
289 memory_mode = _memory_modes[memory_mode_name]
290 except KeyError:
291 raise RuntimeError, "Invalid memory mode (%s)" % memory_mode_name
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
346 if not internal.core.listenersDisabled():
343 if not _m5.core.listenersDisabled():
347 raise RuntimeError, "Can not fork a simulator with listeners enabled"
348
349 drain()
350
351 try:
352 pid = os.fork()
353 except OSError, e:
354 raise e
355
356 if pid == 0:
357 # In child, notify objects of the fork
358 root = objects.Root.getInstance()
359 notifyFork(root)
360 # Setup a new output directory
361 parent = options.outdir
362 options.outdir = simout % {
363 "parent" : parent,
364 "fork_seq" : fork_count,
365 "pid" : os.getpid(),
366 }
344 raise RuntimeError, "Can not fork a simulator with listeners enabled"
345
346 drain()
347
348 try:
349 pid = os.fork()
350 except OSError, e:
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 }
367 core.setOutputDir(options.outdir)
364 _m5.core.setOutputDir(options.outdir)
368 else:
369 fork_count += 1
370
371 return pid
372
365 else:
366 fork_count += 1
367
368 return pid
369
373from internal.core import disableAllListeners
374from internal.core import listenersDisabled
370from _m5.core import disableAllListeners, listenersDisabled
371from _m5.core import curTick