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:
| 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:
|
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.") 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)) 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") 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)") 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) 268 if not isinstance(new_cpu, objects.BaseCPU): 269 raise TypeError("%s is not of type BaseCPU" % new_cpu) 270 if new_cpu in old_cpu_set: 271 raise RuntimeError( 272 "New CPU (%s) is in the list of old CPUs." % (old_cpu,)) 273 if not new_cpu.switchedOut(): 274 raise RuntimeError("New CPU (%s) is already active." % (new_cpu,)) 275 if not new_cpu.support_take_over(): 276 raise RuntimeError( 277 "New CPU (%s) does not support CPU handover." % (old_cpu,)) 278 if new_cpu.memory_mode() != memory_mode_name: 279 raise RuntimeError( 280 "%s and %s require different memory modes." % (new_cpu, 281 new_cpus[0])) 282 if old_cpu.switchedOut(): 283 raise RuntimeError("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 343 if not _m5.core.listenersDisabled(): 344 raise RuntimeError("Can not fork a simulator with listeners enabled") 345 346 drain() 347 348 try: 349 pid = os.fork() 350 except OSError as 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 } 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
| 106 d = root.get_config_as_dict() 107 json.dump(d, json_file, indent=4) 108 json_file.close() 109 except ImportError: 110 pass 111 112 do_dot(root, options.outdir, options.dot_config) 113 114 # Initialize the global statistics 115 stats.initSimStats() 116 117 # Create the C++ sim objects and connect ports 118 for obj in root.descendants(): obj.createCCObject() 119 for obj in root.descendants(): obj.connectPorts() 120 121 # Do a second pass to finish initializing the sim objects 122 for obj in root.descendants(): obj.init() 123 124 # Do a third pass to initialize statistics 125 for obj in root.descendants(): obj.regStats() 126 127 # Do a fourth pass to initialize probe points 128 for obj in root.descendants(): obj.regProbePoints() 129 130 # Do a fifth pass to connect probe listeners 131 for obj in root.descendants(): obj.regProbeListeners() 132 133 # We want to generate the DVFS diagram for the system. This can only be 134 # done once all of the CPP objects have been created and initialised so 135 # that we are able to figure out which object belongs to which domain. 136 if options.dot_dvfs_config: 137 do_dvfs_dot(root, options.outdir, options.dot_dvfs_config) 138 139 # We're done registering statistics. Enable the stats package now. 140 stats.enable() 141 142 # Restore checkpoint (if any) 143 if ckpt_dir: 144 _drain_manager.preCheckpointRestore() 145 ckpt = _m5.core.getCheckpoint(ckpt_dir) 146 _m5.core.unserializeGlobals(ckpt); 147 for obj in root.descendants(): obj.loadState(ckpt) 148 else: 149 for obj in root.descendants(): obj.initState() 150 151 # Check to see if any of the stat events are in the past after resuming from 152 # a checkpoint, If so, this call will shift them to be at a valid time. 153 updateStatEvents() 154 155need_startup = True 156def simulate(*args, **kwargs): 157 global need_startup 158 159 if need_startup: 160 root = objects.Root.getInstance() 161 for obj in root.descendants(): obj.startup() 162 need_startup = False 163 164 # Python exit handlers happen in reverse order. 165 # We want to dump stats last. 166 atexit.register(stats.dump) 167 168 # register our C++ exit callback function with Python 169 atexit.register(_m5.core.doExitCleanup) 170 171 # Reset to put the stats in a consistent state. 172 stats.reset() 173 174 if _drain_manager.isDrained(): 175 _drain_manager.resume() 176 177 return _m5.event.simulate(*args, **kwargs) 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 201 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") 230 _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("New CPU (%s) is already active." % (new_cpu,)) 276 if not new_cpu.support_take_over(): 277 raise RuntimeError( 278 "New CPU (%s) does not support CPU handover." % (old_cpu,)) 279 if new_cpu.memory_mode() != memory_mode_name: 280 raise RuntimeError( 281 "%s and %s require different memory modes." % (new_cpu, 282 new_cpus[0])) 283 if old_cpu.switchedOut(): 284 raise RuntimeError("Old CPU (%s) is inactive." % (new_cpu,)) 285 if not old_cpu.support_take_over(): 286 raise RuntimeError( 287 "Old CPU (%s) does not support CPU handover." % (old_cpu,)) 288 289 try: 290 memory_mode = _memory_modes[memory_mode_name] 291 except KeyError: 292 raise RuntimeError("Invalid memory mode (%s)" % memory_mode_name) 293 294 drain() 295 296 # Now all of the CPUs are ready to be switched out 297 for old_cpu, new_cpu in cpuList: 298 old_cpu.switchOut() 299 300 # Change the memory mode if required. We check if this is needed 301 # to avoid printing a warning if no switch was performed. 302 if system.getMemoryMode() != memory_mode: 303 # Flush the memory system if we are switching to a memory mode 304 # that disables caches. This typically happens when switching to a 305 # hardware virtualized CPU. 306 if memory_mode == objects.params.atomic_noncaching: 307 memWriteback(system) 308 memInvalidate(system) 309 310 _changeMemoryMode(system, memory_mode) 311 312 for old_cpu, new_cpu in cpuList: 313 new_cpu.takeOverFrom(old_cpu) 314 315def notifyFork(root): 316 for obj in root.descendants(): 317 obj.notifyFork() 318 319fork_count = 0 320def fork(simout="%(parent)s.f%(fork_seq)i"): 321 """Fork the simulator. 322 323 This function forks the simulator. After forking the simulator, 324 the child process gets its output files redirected to a new output 325 directory. The default name of the output directory is the same as 326 the parent with the suffix ".fN" added where N is the fork 327 sequence number. The name of the output directory can be 328 overridden using the simout keyword argument. 329 330 Output file formatting dictionary: 331 parent -- Path to the parent process's output directory. 332 fork_seq -- Fork sequence number. 333 pid -- PID of the child process. 334 335 Keyword Arguments: 336 simout -- New simulation output directory. 337 338 Return Value: 339 pid of the child process or 0 if running in the child. 340 """ 341 from m5 import options 342 global fork_count 343 344 if not _m5.core.listenersDisabled(): 345 raise RuntimeError("Can not fork a simulator with listeners enabled") 346 347 drain() 348 349 try: 350 pid = os.fork() 351 except OSError as e: 352 raise e 353 354 if pid == 0: 355 # In child, notify objects of the fork 356 root = objects.Root.getInstance() 357 notifyFork(root) 358 # Setup a new output directory 359 parent = options.outdir 360 options.outdir = simout % { 361 "parent" : parent, 362 "fork_seq" : fork_count, 363 "pid" : os.getpid(), 364 } 365 _m5.core.setOutputDir(options.outdir) 366 else: 367 fork_count += 1 368 369 return pid 370 371from _m5.core import disableAllListeners, listenersDisabled 372from _m5.core import listenersLoopbackOnly 373from _m5.core import curTick
|