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