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 50import stats 51import SimObject 52import ticks 53import objects 54from 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 69_drain_manager = internal.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.
| 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 50import stats 51import SimObject 52import ticks 53import objects 54from 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 69_drain_manager = internal.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.
|
133 134 # We're done registering statistics. Enable the stats package now. 135 stats.enable() 136 137 # Restore checkpoint (if any) 138 if ckpt_dir: 139 _drain_manager.preCheckpointRestore() 140 ckpt = internal.core.getCheckpoint(ckpt_dir) 141 internal.core.unserializeGlobals(ckpt); 142 for obj in root.descendants(): obj.loadState(ckpt) 143 else: 144 for obj in root.descendants(): obj.initState() 145 146 # Check to see if any of the stat events are in the past after resuming from 147 # a checkpoint, If so, this call will shift them to be at a valid time. 148 updateStatEvents() 149 150need_startup = True 151def simulate(*args, **kwargs): 152 global need_startup 153 154 if need_startup: 155 root = objects.Root.getInstance() 156 for obj in root.descendants(): obj.startup() 157 need_startup = False 158 159 # Python exit handlers happen in reverse order. 160 # We want to dump stats last. 161 atexit.register(stats.dump) 162 163 # register our C++ exit callback function with Python 164 atexit.register(internal.core.doExitCleanup) 165 166 # Reset to put the stats in a consistent state. 167 stats.reset() 168 169 if _drain_manager.isDrained(): 170 _drain_manager.resume() 171 172 return internal.event.simulate(*args, **kwargs) 173 174# Export curTick to user script. 175def curTick(): 176 return internal.core.curTick() 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 = internal.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 internal.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, \ 275 "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, \ 285 "Old CPU (%s) is inactive." % (new_cpu,) 286 if not old_cpu.support_take_over(): 287 raise RuntimeError, \ 288 "Old CPU (%s) does not support CPU handover." % (old_cpu,) 289 290 try: 291 memory_mode = _memory_modes[memory_mode_name] 292 except KeyError: 293 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 internal.core.listenersDisabled(): 346 raise RuntimeError, "Can not fork a simulator with listeners enabled" 347 348 drain() 349 350 try: 351 pid = os.fork() 352 except OSError, 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 core.setOutputDir(options.outdir) 367 else: 368 fork_count += 1 369 370 return pid 371 372from internal.core import disableAllListeners 373from internal.core import listenersDisabled
| 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() 141 ckpt = internal.core.getCheckpoint(ckpt_dir) 142 internal.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 165 atexit.register(internal.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 173 return internal.event.simulate(*args, **kwargs) 174 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 201 exit_event = internal.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 internal.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 346 if not internal.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 } 367 core.setOutputDir(options.outdir) 368 else: 369 fork_count += 1 370 371 return pid 372 373from internal.core import disableAllListeners 374from internal.core import listenersDisabled
|