simulate.py (9983:2cce74fe359e) simulate.py (9993:bdd606534bdc)
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 # We're done registering statistics. Enable the stats package now.
122 stats.enable()
123
124 # Restore checkpoint (if any)
125 if ckpt_dir:
126 ckpt = internal.core.getCheckpoint(ckpt_dir)
127 internal.core.unserializeGlobals(ckpt);
128 for obj in root.descendants(): obj.loadState(ckpt)
129 need_resume.append(root)
130 else:
131 for obj in root.descendants(): obj.initState()
132
133 # Check to see if any of the stat events are in the past after resuming from
134 # a checkpoint, If so, this call will shift them to be at a valid time.
135 updateStatEvents()
136
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 # We're done registering statistics. Enable the stats package now.
122 stats.enable()
123
124 # Restore checkpoint (if any)
125 if ckpt_dir:
126 ckpt = internal.core.getCheckpoint(ckpt_dir)
127 internal.core.unserializeGlobals(ckpt);
128 for obj in root.descendants(): obj.loadState(ckpt)
129 need_resume.append(root)
130 else:
131 for obj in root.descendants(): obj.initState()
132
133 # Check to see if any of the stat events are in the past after resuming from
134 # a checkpoint, If so, this call will shift them to be at a valid time.
135 updateStatEvents()
136
137 # Reset to put the stats in a consistent state.
138 stats.reset()
139
140need_resume = []
141need_startup = True
142def simulate(*args, **kwargs):
143 global need_resume, need_startup
144
145 if need_startup:
146 root = objects.Root.getInstance()
147 for obj in root.descendants(): obj.startup()
148 need_startup = False
149
150 # Python exit handlers happen in reverse order.
151 # We want to dump stats last.
152 atexit.register(stats.dump)
153
154 # register our C++ exit callback function with Python
155 atexit.register(internal.core.doExitCleanup)
156
137need_resume = []
138need_startup = True
139def simulate(*args, **kwargs):
140 global need_resume, need_startup
141
142 if need_startup:
143 root = objects.Root.getInstance()
144 for obj in root.descendants(): obj.startup()
145 need_startup = False
146
147 # Python exit handlers happen in reverse order.
148 # We want to dump stats last.
149 atexit.register(stats.dump)
150
151 # register our C++ exit callback function with Python
152 atexit.register(internal.core.doExitCleanup)
153
154 # Reset to put the stats in a consistent state.
155 stats.reset()
156
157 for root in need_resume:
158 resume(root)
159 need_resume = []
160
161 return internal.event.simulate(*args, **kwargs)
162
163# Export curTick to user script.
164def curTick():
165 return internal.core.curTick()
166
167# Drain the system in preparation of a checkpoint or memory mode
168# switch.
169def drain(root):
170 # Try to drain all objects. Draining might not be completed unless
171 # all objects return that they are drained on the first call. This
172 # is because as objects drain they may cause other objects to no
173 # longer be drained.
174 def _drain():
175 all_drained = False
176 dm = internal.drain.createDrainManager()
177 unready_objs = sum(obj.drain(dm) for obj in root.descendants())
178 # If we've got some objects that can't drain immediately, then simulate
179 if unready_objs > 0:
180 dm.setCount(unready_objs)
181 simulate()
182 else:
183 all_drained = True
184 internal.drain.cleanupDrainManager(dm)
185 return all_drained
186
187 all_drained = _drain()
188 while (not all_drained):
189 all_drained = _drain()
190
191def memWriteback(root):
192 for obj in root.descendants():
193 obj.memWriteback()
194
195def memInvalidate(root):
196 for obj in root.descendants():
197 obj.memInvalidate()
198
199def resume(root):
200 for obj in root.descendants(): obj.drainResume()
201
202def checkpoint(dir):
203 root = objects.Root.getInstance()
204 if not isinstance(root, objects.Root):
205 raise TypeError, "Checkpoint must be called on a root object."
206 drain(root)
207 memWriteback(root)
208 print "Writing checkpoint"
209 internal.core.serializeAll(dir)
210 resume(root)
211
212def _changeMemoryMode(system, mode):
213 if not isinstance(system, (objects.Root, objects.System)):
214 raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
215 (type(system), objects.Root, objects.System)
216 if system.getMemoryMode() != mode:
217 drain(system)
218 system.setMemoryMode(mode)
219 else:
220 print "System already in target mode. Memory mode unchanged."
221
222def switchCpus(system, cpuList, do_drain=True, verbose=True):
223 """Switch CPUs in a system.
224
225 By default, this method drains and resumes the system. This
226 behavior can be disabled by setting the keyword argument
227 'do_drain' to false, which might be desirable if multiple
228 operations requiring a drained system are going to be performed in
229 sequence.
230
231 Note: This method may switch the memory mode of the system if that
232 is required by the CPUs. It may also flush all caches in the
233 system.
234
235 Arguments:
236 system -- Simulated system.
237 cpuList -- (old_cpu, new_cpu) tuples
238
239 Keyword Arguments:
240 do_drain -- Perform a drain/resume of the system when switching.
241 """
242
243 if verbose:
244 print "switching cpus"
245
246 if not isinstance(cpuList, list):
247 raise RuntimeError, "Must pass a list to this function"
248 for item in cpuList:
249 if not isinstance(item, tuple) or len(item) != 2:
250 raise RuntimeError, "List must have tuples of (oldCPU,newCPU)"
251
252 old_cpus = [old_cpu for old_cpu, new_cpu in cpuList]
253 new_cpus = [new_cpu for old_cpu, new_cpu in cpuList]
254 old_cpu_set = set(old_cpus)
255 memory_mode_name = new_cpus[0].memory_mode()
256 for old_cpu, new_cpu in cpuList:
257 if not isinstance(old_cpu, objects.BaseCPU):
258 raise TypeError, "%s is not of type BaseCPU" % old_cpu
259 if not isinstance(new_cpu, objects.BaseCPU):
260 raise TypeError, "%s is not of type BaseCPU" % new_cpu
261 if new_cpu in old_cpu_set:
262 raise RuntimeError, \
263 "New CPU (%s) is in the list of old CPUs." % (old_cpu,)
264 if not new_cpu.switchedOut():
265 raise RuntimeError, \
266 "New CPU (%s) is already active." % (new_cpu,)
267 if not new_cpu.support_take_over():
268 raise RuntimeError, \
269 "New CPU (%s) does not support CPU handover." % (old_cpu,)
270 if new_cpu.memory_mode() != memory_mode_name:
271 raise RuntimeError, \
272 "%s and %s require different memory modes." % (new_cpu,
273 new_cpus[0])
274 if old_cpu.switchedOut():
275 raise RuntimeError, \
276 "Old CPU (%s) is inactive." % (new_cpu,)
277 if not old_cpu.support_take_over():
278 raise RuntimeError, \
279 "Old CPU (%s) does not support CPU handover." % (old_cpu,)
280
281 try:
282 memory_mode = _memory_modes[memory_mode_name]
283 except KeyError:
284 raise RuntimeError, "Invalid memory mode (%s)" % memory_mode_name
285
286 if do_drain:
287 drain(system)
288
289 # Now all of the CPUs are ready to be switched out
290 for old_cpu, new_cpu in cpuList:
291 old_cpu.switchOut()
292
293 # Change the memory mode if required. We check if this is needed
294 # to avoid printing a warning if no switch was performed.
295 if system.getMemoryMode() != memory_mode:
296 # Flush the memory system if we are switching to a memory mode
297 # that disables caches. This typically happens when switching to a
298 # hardware virtualized CPU.
299 if memory_mode == objects.params.atomic_noncaching:
300 memWriteback(system)
301 memInvalidate(system)
302
303 _changeMemoryMode(system, memory_mode)
304
305 for old_cpu, new_cpu in cpuList:
306 new_cpu.takeOverFrom(old_cpu)
307
308 if do_drain:
309 resume(system)
310
311from internal.core import disableAllListeners
157 for root in need_resume:
158 resume(root)
159 need_resume = []
160
161 return internal.event.simulate(*args, **kwargs)
162
163# Export curTick to user script.
164def curTick():
165 return internal.core.curTick()
166
167# Drain the system in preparation of a checkpoint or memory mode
168# switch.
169def drain(root):
170 # Try to drain all objects. Draining might not be completed unless
171 # all objects return that they are drained on the first call. This
172 # is because as objects drain they may cause other objects to no
173 # longer be drained.
174 def _drain():
175 all_drained = False
176 dm = internal.drain.createDrainManager()
177 unready_objs = sum(obj.drain(dm) for obj in root.descendants())
178 # If we've got some objects that can't drain immediately, then simulate
179 if unready_objs > 0:
180 dm.setCount(unready_objs)
181 simulate()
182 else:
183 all_drained = True
184 internal.drain.cleanupDrainManager(dm)
185 return all_drained
186
187 all_drained = _drain()
188 while (not all_drained):
189 all_drained = _drain()
190
191def memWriteback(root):
192 for obj in root.descendants():
193 obj.memWriteback()
194
195def memInvalidate(root):
196 for obj in root.descendants():
197 obj.memInvalidate()
198
199def resume(root):
200 for obj in root.descendants(): obj.drainResume()
201
202def checkpoint(dir):
203 root = objects.Root.getInstance()
204 if not isinstance(root, objects.Root):
205 raise TypeError, "Checkpoint must be called on a root object."
206 drain(root)
207 memWriteback(root)
208 print "Writing checkpoint"
209 internal.core.serializeAll(dir)
210 resume(root)
211
212def _changeMemoryMode(system, mode):
213 if not isinstance(system, (objects.Root, objects.System)):
214 raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
215 (type(system), objects.Root, objects.System)
216 if system.getMemoryMode() != mode:
217 drain(system)
218 system.setMemoryMode(mode)
219 else:
220 print "System already in target mode. Memory mode unchanged."
221
222def switchCpus(system, cpuList, do_drain=True, verbose=True):
223 """Switch CPUs in a system.
224
225 By default, this method drains and resumes the system. This
226 behavior can be disabled by setting the keyword argument
227 'do_drain' to false, which might be desirable if multiple
228 operations requiring a drained system are going to be performed in
229 sequence.
230
231 Note: This method may switch the memory mode of the system if that
232 is required by the CPUs. It may also flush all caches in the
233 system.
234
235 Arguments:
236 system -- Simulated system.
237 cpuList -- (old_cpu, new_cpu) tuples
238
239 Keyword Arguments:
240 do_drain -- Perform a drain/resume of the system when switching.
241 """
242
243 if verbose:
244 print "switching cpus"
245
246 if not isinstance(cpuList, list):
247 raise RuntimeError, "Must pass a list to this function"
248 for item in cpuList:
249 if not isinstance(item, tuple) or len(item) != 2:
250 raise RuntimeError, "List must have tuples of (oldCPU,newCPU)"
251
252 old_cpus = [old_cpu for old_cpu, new_cpu in cpuList]
253 new_cpus = [new_cpu for old_cpu, new_cpu in cpuList]
254 old_cpu_set = set(old_cpus)
255 memory_mode_name = new_cpus[0].memory_mode()
256 for old_cpu, new_cpu in cpuList:
257 if not isinstance(old_cpu, objects.BaseCPU):
258 raise TypeError, "%s is not of type BaseCPU" % old_cpu
259 if not isinstance(new_cpu, objects.BaseCPU):
260 raise TypeError, "%s is not of type BaseCPU" % new_cpu
261 if new_cpu in old_cpu_set:
262 raise RuntimeError, \
263 "New CPU (%s) is in the list of old CPUs." % (old_cpu,)
264 if not new_cpu.switchedOut():
265 raise RuntimeError, \
266 "New CPU (%s) is already active." % (new_cpu,)
267 if not new_cpu.support_take_over():
268 raise RuntimeError, \
269 "New CPU (%s) does not support CPU handover." % (old_cpu,)
270 if new_cpu.memory_mode() != memory_mode_name:
271 raise RuntimeError, \
272 "%s and %s require different memory modes." % (new_cpu,
273 new_cpus[0])
274 if old_cpu.switchedOut():
275 raise RuntimeError, \
276 "Old CPU (%s) is inactive." % (new_cpu,)
277 if not old_cpu.support_take_over():
278 raise RuntimeError, \
279 "Old CPU (%s) does not support CPU handover." % (old_cpu,)
280
281 try:
282 memory_mode = _memory_modes[memory_mode_name]
283 except KeyError:
284 raise RuntimeError, "Invalid memory mode (%s)" % memory_mode_name
285
286 if do_drain:
287 drain(system)
288
289 # Now all of the CPUs are ready to be switched out
290 for old_cpu, new_cpu in cpuList:
291 old_cpu.switchOut()
292
293 # Change the memory mode if required. We check if this is needed
294 # to avoid printing a warning if no switch was performed.
295 if system.getMemoryMode() != memory_mode:
296 # Flush the memory system if we are switching to a memory mode
297 # that disables caches. This typically happens when switching to a
298 # hardware virtualized CPU.
299 if memory_mode == objects.params.atomic_noncaching:
300 memWriteback(system)
301 memInvalidate(system)
302
303 _changeMemoryMode(system, memory_mode)
304
305 for old_cpu, new_cpu in cpuList:
306 new_cpu.takeOverFrom(old_cpu)
307
308 if do_drain:
309 resume(system)
310
311from internal.core import disableAllListeners