simulate.py (10023:91faf6649de0) simulate.py (10436:bdb307e8be54)
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
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# The final hook to generate .ini files. Called from the user script
70# once the config is built.
71def instantiate(ckpt_dir=None):
72 from m5 import options
73
74 root = objects.Root.getInstance()
75
76 if not root:
77 fatal("Need to instantiate Root() before calling instantiate()")
78
79 # we need to fix the global frequency
80 ticks.fixGlobalFrequency()
81
82 # Make sure SimObject-valued params are in the configuration
83 # hierarchy so we catch them with future descendants() walks
84 for obj in root.descendants(): obj.adoptOrphanParams()
85
86 # Unproxy in sorted order for determinism
87 for obj in root.descendants(): obj.unproxyParams()
88
89 if options.dump_config:
90 ini_file = file(os.path.join(options.outdir, options.dump_config), 'w')
91 # Print ini sections in sorted order for easier diffing
92 for obj in sorted(root.descendants(), key=lambda o: o.path()):
93 obj.print_ini(ini_file)
94 ini_file.close()
95
96 if options.json_config:
97 try:
98 import json
99 json_file = file(os.path.join(options.outdir, options.json_config), 'w')
100 d = root.get_config_as_dict()
101 json.dump(d, json_file, indent=4)
102 json_file.close()
103 except ImportError:
104 pass
105
106 do_dot(root, options.outdir, options.dot_config)
107
108 # Initialize the global statistics
109 stats.initSimStats()
110
111 # Create the C++ sim objects and connect ports
112 for obj in root.descendants(): obj.createCCObject()
113 for obj in root.descendants(): obj.connectPorts()
114
115 # Do a second pass to finish initializing the sim objects
116 for obj in root.descendants(): obj.init()
117
118 # Do a third pass to initialize statistics
119 for obj in root.descendants(): obj.regStats()
120
121 # Do a fourth pass to initialize probe points
122 for obj in root.descendants(): obj.regProbePoints()
123
124 # Do a fifth pass to connect probe listeners
125 for obj in root.descendants(): obj.regProbeListeners()
126
127 # We're done registering statistics. Enable the stats package now.
128 stats.enable()
129
130 # Restore checkpoint (if any)
131 if ckpt_dir:
132 ckpt = internal.core.getCheckpoint(ckpt_dir)
133 internal.core.unserializeGlobals(ckpt);
134 for obj in root.descendants(): obj.loadState(ckpt)
135 need_resume.append(root)
136 else:
137 for obj in root.descendants(): obj.initState()
138
139 # Check to see if any of the stat events are in the past after resuming from
140 # a checkpoint, If so, this call will shift them to be at a valid time.
141 updateStatEvents()
142
143need_resume = []
144need_startup = True
145def simulate(*args, **kwargs):
146 global need_resume, need_startup
147
148 if need_startup:
149 root = objects.Root.getInstance()
150 for obj in root.descendants(): obj.startup()
151 need_startup = False
152
153 # Python exit handlers happen in reverse order.
154 # We want to dump stats last.
155 atexit.register(stats.dump)
156
157 # register our C++ exit callback function with Python
158 atexit.register(internal.core.doExitCleanup)
159
160 # Reset to put the stats in a consistent state.
161 stats.reset()
162
163 for root in need_resume:
164 resume(root)
165 need_resume = []
166
167 return internal.event.simulate(*args, **kwargs)
168
169# Export curTick to user script.
170def curTick():
171 return internal.core.curTick()
172
173# Drain the system in preparation of a checkpoint or memory mode
174# switch.
175def drain(root):
176 # Try to drain all objects. Draining might not be completed unless
177 # all objects return that they are drained on the first call. This
178 # is because as objects drain they may cause other objects to no
179 # longer be drained.
180 def _drain():
181 all_drained = False
182 dm = internal.drain.createDrainManager()
183 unready_objs = sum(obj.drain(dm) for obj in root.descendants())
184 # If we've got some objects that can't drain immediately, then simulate
185 if unready_objs > 0:
186 dm.setCount(unready_objs)
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
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# The final hook to generate .ini files. Called from the user script
70# once the config is built.
71def instantiate(ckpt_dir=None):
72 from m5 import options
73
74 root = objects.Root.getInstance()
75
76 if not root:
77 fatal("Need to instantiate Root() before calling instantiate()")
78
79 # we need to fix the global frequency
80 ticks.fixGlobalFrequency()
81
82 # Make sure SimObject-valued params are in the configuration
83 # hierarchy so we catch them with future descendants() walks
84 for obj in root.descendants(): obj.adoptOrphanParams()
85
86 # Unproxy in sorted order for determinism
87 for obj in root.descendants(): obj.unproxyParams()
88
89 if options.dump_config:
90 ini_file = file(os.path.join(options.outdir, options.dump_config), 'w')
91 # Print ini sections in sorted order for easier diffing
92 for obj in sorted(root.descendants(), key=lambda o: o.path()):
93 obj.print_ini(ini_file)
94 ini_file.close()
95
96 if options.json_config:
97 try:
98 import json
99 json_file = file(os.path.join(options.outdir, options.json_config), 'w')
100 d = root.get_config_as_dict()
101 json.dump(d, json_file, indent=4)
102 json_file.close()
103 except ImportError:
104 pass
105
106 do_dot(root, options.outdir, options.dot_config)
107
108 # Initialize the global statistics
109 stats.initSimStats()
110
111 # Create the C++ sim objects and connect ports
112 for obj in root.descendants(): obj.createCCObject()
113 for obj in root.descendants(): obj.connectPorts()
114
115 # Do a second pass to finish initializing the sim objects
116 for obj in root.descendants(): obj.init()
117
118 # Do a third pass to initialize statistics
119 for obj in root.descendants(): obj.regStats()
120
121 # Do a fourth pass to initialize probe points
122 for obj in root.descendants(): obj.regProbePoints()
123
124 # Do a fifth pass to connect probe listeners
125 for obj in root.descendants(): obj.regProbeListeners()
126
127 # We're done registering statistics. Enable the stats package now.
128 stats.enable()
129
130 # Restore checkpoint (if any)
131 if ckpt_dir:
132 ckpt = internal.core.getCheckpoint(ckpt_dir)
133 internal.core.unserializeGlobals(ckpt);
134 for obj in root.descendants(): obj.loadState(ckpt)
135 need_resume.append(root)
136 else:
137 for obj in root.descendants(): obj.initState()
138
139 # Check to see if any of the stat events are in the past after resuming from
140 # a checkpoint, If so, this call will shift them to be at a valid time.
141 updateStatEvents()
142
143need_resume = []
144need_startup = True
145def simulate(*args, **kwargs):
146 global need_resume, need_startup
147
148 if need_startup:
149 root = objects.Root.getInstance()
150 for obj in root.descendants(): obj.startup()
151 need_startup = False
152
153 # Python exit handlers happen in reverse order.
154 # We want to dump stats last.
155 atexit.register(stats.dump)
156
157 # register our C++ exit callback function with Python
158 atexit.register(internal.core.doExitCleanup)
159
160 # Reset to put the stats in a consistent state.
161 stats.reset()
162
163 for root in need_resume:
164 resume(root)
165 need_resume = []
166
167 return internal.event.simulate(*args, **kwargs)
168
169# Export curTick to user script.
170def curTick():
171 return internal.core.curTick()
172
173# Drain the system in preparation of a checkpoint or memory mode
174# switch.
175def drain(root):
176 # Try to drain all objects. Draining might not be completed unless
177 # all objects return that they are drained on the first call. This
178 # is because as objects drain they may cause other objects to no
179 # longer be drained.
180 def _drain():
181 all_drained = False
182 dm = internal.drain.createDrainManager()
183 unready_objs = sum(obj.drain(dm) for obj in root.descendants())
184 # If we've got some objects that can't drain immediately, then simulate
185 if unready_objs > 0:
186 dm.setCount(unready_objs)
187 simulate()
187 #WARNING: if a valid exit event occurs while draining, it will not
188 # get returned to the user script
189 exit_event = simulate()
190 while exit_event.getCause() != 'Finished drain':
191 exit_event = simulate()
188 else:
189 all_drained = True
190 internal.drain.cleanupDrainManager(dm)
191 return all_drained
192
193 all_drained = _drain()
194 while (not all_drained):
195 all_drained = _drain()
196
197def memWriteback(root):
198 for obj in root.descendants():
199 obj.memWriteback()
200
201def memInvalidate(root):
202 for obj in root.descendants():
203 obj.memInvalidate()
204
205def resume(root):
206 for obj in root.descendants(): obj.drainResume()
207
208def checkpoint(dir):
209 root = objects.Root.getInstance()
210 if not isinstance(root, objects.Root):
211 raise TypeError, "Checkpoint must be called on a root object."
212 drain(root)
213 memWriteback(root)
214 print "Writing checkpoint"
215 internal.core.serializeAll(dir)
216 resume(root)
217
218def _changeMemoryMode(system, mode):
219 if not isinstance(system, (objects.Root, objects.System)):
220 raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
221 (type(system), objects.Root, objects.System)
222 if system.getMemoryMode() != mode:
223 drain(system)
224 system.setMemoryMode(mode)
225 else:
226 print "System already in target mode. Memory mode unchanged."
227
228def switchCpus(system, cpuList, do_drain=True, verbose=True):
229 """Switch CPUs in a system.
230
231 By default, this method drains and resumes the system. This
232 behavior can be disabled by setting the keyword argument
233 'do_drain' to false, which might be desirable if multiple
234 operations requiring a drained system are going to be performed in
235 sequence.
236
237 Note: This method may switch the memory mode of the system if that
238 is required by the CPUs. It may also flush all caches in the
239 system.
240
241 Arguments:
242 system -- Simulated system.
243 cpuList -- (old_cpu, new_cpu) tuples
244
245 Keyword Arguments:
246 do_drain -- Perform a drain/resume of the system when switching.
247 """
248
249 if verbose:
250 print "switching cpus"
251
252 if not isinstance(cpuList, list):
253 raise RuntimeError, "Must pass a list to this function"
254 for item in cpuList:
255 if not isinstance(item, tuple) or len(item) != 2:
256 raise RuntimeError, "List must have tuples of (oldCPU,newCPU)"
257
258 old_cpus = [old_cpu for old_cpu, new_cpu in cpuList]
259 new_cpus = [new_cpu for old_cpu, new_cpu in cpuList]
260 old_cpu_set = set(old_cpus)
261 memory_mode_name = new_cpus[0].memory_mode()
262 for old_cpu, new_cpu in cpuList:
263 if not isinstance(old_cpu, objects.BaseCPU):
264 raise TypeError, "%s is not of type BaseCPU" % old_cpu
265 if not isinstance(new_cpu, objects.BaseCPU):
266 raise TypeError, "%s is not of type BaseCPU" % new_cpu
267 if new_cpu in old_cpu_set:
268 raise RuntimeError, \
269 "New CPU (%s) is in the list of old CPUs." % (old_cpu,)
270 if not new_cpu.switchedOut():
271 raise RuntimeError, \
272 "New CPU (%s) is already active." % (new_cpu,)
273 if not new_cpu.support_take_over():
274 raise RuntimeError, \
275 "New CPU (%s) does not support CPU handover." % (old_cpu,)
276 if new_cpu.memory_mode() != memory_mode_name:
277 raise RuntimeError, \
278 "%s and %s require different memory modes." % (new_cpu,
279 new_cpus[0])
280 if old_cpu.switchedOut():
281 raise RuntimeError, \
282 "Old CPU (%s) is inactive." % (new_cpu,)
283 if not old_cpu.support_take_over():
284 raise RuntimeError, \
285 "Old CPU (%s) does not support CPU handover." % (old_cpu,)
286
287 try:
288 memory_mode = _memory_modes[memory_mode_name]
289 except KeyError:
290 raise RuntimeError, "Invalid memory mode (%s)" % memory_mode_name
291
292 if do_drain:
293 drain(system)
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
314 if do_drain:
315 resume(system)
316
317from internal.core import disableAllListeners
192 else:
193 all_drained = True
194 internal.drain.cleanupDrainManager(dm)
195 return all_drained
196
197 all_drained = _drain()
198 while (not all_drained):
199 all_drained = _drain()
200
201def memWriteback(root):
202 for obj in root.descendants():
203 obj.memWriteback()
204
205def memInvalidate(root):
206 for obj in root.descendants():
207 obj.memInvalidate()
208
209def resume(root):
210 for obj in root.descendants(): obj.drainResume()
211
212def checkpoint(dir):
213 root = objects.Root.getInstance()
214 if not isinstance(root, objects.Root):
215 raise TypeError, "Checkpoint must be called on a root object."
216 drain(root)
217 memWriteback(root)
218 print "Writing checkpoint"
219 internal.core.serializeAll(dir)
220 resume(root)
221
222def _changeMemoryMode(system, mode):
223 if not isinstance(system, (objects.Root, objects.System)):
224 raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
225 (type(system), objects.Root, objects.System)
226 if system.getMemoryMode() != mode:
227 drain(system)
228 system.setMemoryMode(mode)
229 else:
230 print "System already in target mode. Memory mode unchanged."
231
232def switchCpus(system, cpuList, do_drain=True, verbose=True):
233 """Switch CPUs in a system.
234
235 By default, this method drains and resumes the system. This
236 behavior can be disabled by setting the keyword argument
237 'do_drain' to false, which might be desirable if multiple
238 operations requiring a drained system are going to be performed in
239 sequence.
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 Keyword Arguments:
250 do_drain -- Perform a drain/resume of the system when switching.
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 if do_drain:
297 drain(system)
298
299 # Now all of the CPUs are ready to be switched out
300 for old_cpu, new_cpu in cpuList:
301 old_cpu.switchOut()
302
303 # Change the memory mode if required. We check if this is needed
304 # to avoid printing a warning if no switch was performed.
305 if system.getMemoryMode() != memory_mode:
306 # Flush the memory system if we are switching to a memory mode
307 # that disables caches. This typically happens when switching to a
308 # hardware virtualized CPU.
309 if memory_mode == objects.params.atomic_noncaching:
310 memWriteback(system)
311 memInvalidate(system)
312
313 _changeMemoryMode(system, memory_mode)
314
315 for old_cpu, new_cpu in cpuList:
316 new_cpu.takeOverFrom(old_cpu)
317
318 if do_drain:
319 resume(system)
320
321from internal.core import disableAllListeners