1 # Copyright (c) 2006-2008 The Regents of The University of Michigan
2 # Copyright (c) 2010 Advanced Micro Devices, Inc.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met: redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer;
9 # redistributions in binary form must reproduce the above copyright
10 # notice, this list of conditions and the following disclaimer in the
11 # documentation and/or other materials provided with the distribution;
12 # neither the name of the copyright holders nor the names of its
13 # contributors may be used to endorse or promote products derived from
14 # this software without specific prior written permission.
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 from os
.path
import join
as joinpath
34 from m5
.defines
import buildEnv
35 from m5
.objects
import *
38 addToPath('../common')
40 def setCPUClass(options
):
43 if options
.cpu_type
== "timing":
44 class TmpClass(TimingSimpleCPU
): pass
45 elif options
.cpu_type
== "detailed":
46 if not options
.caches
and not options
.ruby
:
47 print "O3 CPU must be used with caches"
49 class TmpClass(DerivO3CPU
): pass
50 elif options
.cpu_type
== "inorder":
51 if not options
.caches
:
52 print "InOrder CPU must be used with caches"
54 class TmpClass(InOrderCPU
): pass
56 class TmpClass(AtomicSimpleCPU
): pass
60 test_mem_mode
= 'atomic'
63 if options
.checkpoint_restore
!= None:
64 if options
.restore_with_cpu
!= options
.cpu_type
:
66 class TmpClass(AtomicSimpleCPU
): pass
68 if options
.restore_with_cpu
!= "atomic":
69 test_mem_mode
= 'timing'
71 elif options
.fast_forward
:
73 class TmpClass(AtomicSimpleCPU
): pass
75 test_mem_mode
= 'timing'
77 return (TmpClass
, test_mem_mode
, CPUClass
)
80 def run(options
, root
, testsys
, cpu_class
):
82 maxtick
= options
.maxtick
84 simtime
= m5
.ticks
.seconds(simtime
)
85 print "simulating for: ", simtime
90 if options
.checkpoint_dir
:
91 cptdir
= options
.checkpoint_dir
92 elif m5
.options
.outdir
:
93 cptdir
= m5
.options
.outdir
97 if options
.fast_forward
and options
.checkpoint_restore
!= None:
98 fatal("Can't specify both --fast-forward and --checkpoint-restore")
100 if options
.standard_switch
and not options
.caches
:
101 fatal("Must specify --caches when using --standard-switch")
103 np
= options
.num_cpus
104 max_checkpoints
= options
.max_checkpoints
107 if options
.prog_interval
:
109 testsys
.cpu
[i
].progress_interval
= options
.prog_interval
113 testsys
.cpu
[i
].max_insts_any_thread
= options
.maxinsts
116 switch_cpus
= [cpu_class(defer_registration
=True, cpu_id
=(np
+i
))
120 if options
.fast_forward
:
121 testsys
.cpu
[i
].max_insts_any_thread
= int(options
.fast_forward
)
122 switch_cpus
[i
].system
= testsys
123 if not buildEnv
['FULL_SYSTEM']:
124 switch_cpus
[i
].workload
= testsys
.cpu
[i
].workload
125 switch_cpus
[i
].clock
= testsys
.cpu
[0].clock
128 switch_cpus
[i
].max_insts_any_thread
= options
.maxinsts
130 testsys
.switch_cpus
= switch_cpus
131 switch_cpu_list
= [(testsys
.cpu
[i
], switch_cpus
[i
]) for i
in xrange(np
)]
133 if options
.standard_switch
:
134 if not options
.caches
:
135 # O3 CPU must have a cache to work.
136 print "O3 CPU must be used with caches"
139 switch_cpus
= [TimingSimpleCPU(defer_registration
=True, cpu_id
=(np
+i
))
141 switch_cpus_1
= [DerivO3CPU(defer_registration
=True, cpu_id
=(2*np
+i
))
145 switch_cpus
[i
].system
= testsys
146 switch_cpus_1
[i
].system
= testsys
147 if not buildEnv
['FULL_SYSTEM']:
148 switch_cpus
[i
].workload
= testsys
.cpu
[i
].workload
149 switch_cpus_1
[i
].workload
= testsys
.cpu
[i
].workload
150 switch_cpus
[i
].clock
= testsys
.cpu
[0].clock
151 switch_cpus_1
[i
].clock
= testsys
.cpu
[0].clock
153 # if restoring, make atomic cpu simulate only a few instructions
154 if options
.checkpoint_restore
!= None:
155 testsys
.cpu
[i
].max_insts_any_thread
= 1
156 # Fast forward to specified location if we are not restoring
157 elif options
.fast_forward
:
158 testsys
.cpu
[i
].max_insts_any_thread
= int(options
.fast_forward
)
159 # Fast forward to a simpoint (warning: time consuming)
160 elif options
.simpoint
:
161 if testsys
.cpu
[i
].workload
[0].simpoint
== 0:
162 fatal('simpoint not found')
163 testsys
.cpu
[i
].max_insts_any_thread
= \
164 testsys
.cpu
[i
].workload
[0].simpoint
165 # No distance specified, just switch
167 testsys
.cpu
[i
].max_insts_any_thread
= 1
170 if options
.warmup_insts
:
171 switch_cpus
[i
].max_insts_any_thread
= options
.warmup_insts
175 switch_cpus_1
[i
].max_insts_any_thread
= options
.maxinsts
177 testsys
.switch_cpus
= switch_cpus
178 testsys
.switch_cpus_1
= switch_cpus_1
179 switch_cpu_list
= [(testsys
.cpu
[i
], switch_cpus
[i
]) for i
in xrange(np
)]
180 switch_cpu_list1
= [(switch_cpus
[i
], switch_cpus_1
[i
]) for i
in xrange(np
)]
182 # set the checkpoint in the cpu before m5.instantiate is called
183 if options
.take_checkpoints
!= None and \
184 (options
.simpoint
or options
.at_instruction
):
185 offset
= int(options
.take_checkpoints
)
186 # Set an instruction break point
189 if testsys
.cpu
[i
].workload
[0].simpoint
== 0:
190 fatal('no simpoint for testsys.cpu[%d].workload[0]', i
)
191 checkpoint_inst
= int(testsys
.cpu
[i
].workload
[0].simpoint
) + offset
192 testsys
.cpu
[i
].max_insts_any_thread
= checkpoint_inst
193 # used for output below
194 options
.take_checkpoints
= checkpoint_inst
196 options
.take_checkpoints
= offset
197 # Set all test cpus with the right number of instructions
198 # for the upcoming simulation
200 testsys
.cpu
[i
].max_insts_any_thread
= offset
202 checkpoint_dir
= None
203 if options
.checkpoint_restore
!= None:
204 from os
.path
import isdir
, exists
205 from os
import listdir
208 if not isdir(cptdir
):
209 fatal("checkpoint dir %s does not exist!", cptdir
)
211 if options
.at_instruction
or options
.simpoint
:
212 inst
= options
.checkpoint_restore
214 # assume workload 0 has the simpoint
215 if testsys
.cpu
[0].workload
[0].simpoint
== 0:
216 fatal('Unable to find simpoint')
217 inst
+= int(testsys
.cpu
[0].workload
[0].simpoint
)
219 checkpoint_dir
= joinpath(cptdir
,
220 "cpt.%s.%s" % (options
.bench
, inst
))
221 if not exists(checkpoint_dir
):
222 fatal("Unable to find checkpoint directory %s", checkpoint_dir
)
224 dirs
= listdir(cptdir
)
225 expr
= re
.compile('cpt\.([0-9]*)')
228 match
= expr
.match(dir)
230 cpts
.append(match
.group(1))
232 cpts
.sort(lambda a
,b
: cmp(long(a
), long(b
)))
234 cpt_num
= options
.checkpoint_restore
236 if cpt_num
> len(cpts
):
237 fatal('Checkpoint %d not found', cpt_num
)
239 ## Adjust max tick based on our starting tick
240 maxtick
= maxtick
- int(cpts
[cpt_num
- 1])
241 checkpoint_dir
= joinpath(cptdir
, "cpt.%s" % cpts
[cpt_num
- 1])
243 m5
.instantiate(checkpoint_dir
)
245 if options
.standard_switch
or cpu_class
:
246 if options
.standard_switch
:
247 print "Switch at instruction count:%s" % \
248 str(testsys
.cpu
[0].max_insts_any_thread
)
249 exit_event
= m5
.simulate()
250 elif cpu_class
and options
.fast_forward
:
251 print "Switch at instruction count:%s" % \
252 str(testsys
.cpu
[0].max_insts_any_thread
)
253 exit_event
= m5
.simulate()
255 print "Switch at curTick count:%s" % str(10000)
256 exit_event
= m5
.simulate(10000)
257 print "Switched CPUS @ tick %s" % (m5
.curTick())
259 # when you change to Timing (or Atomic), you halt the system
260 # given as argument. When you are finished with the system
261 # changes (including switchCpus), you must resume the system
262 # manually. You DON'T need to resume after just switching
263 # CPUs if you haven't changed anything on the system level.
265 m5
.changeToTiming(testsys
)
266 m5
.switchCpus(switch_cpu_list
)
269 if options
.standard_switch
:
270 print "Switch at instruction count:%d" % \
271 (testsys
.switch_cpus
[0].max_insts_any_thread
)
273 #warmup instruction count may have already been set
274 if options
.warmup_insts
:
275 exit_event
= m5
.simulate()
277 exit_event
= m5
.simulate(options
.warmup
)
278 print "Switching CPUS @ tick %s" % (m5
.curTick())
279 print "Simulation ends instruction count:%d" % \
280 (testsys
.switch_cpus_1
[0].max_insts_any_thread
)
282 m5
.switchCpus(switch_cpu_list1
)
288 # If we're taking and restoring checkpoints, use checkpoint_dir
289 # option only for finding the checkpoints to restore from. This
290 # lets us test checkpointing by restoring from one set of
291 # checkpoints, generating a second set, and then comparing them.
292 if options
.take_checkpoints
and options
.checkpoint_restore
:
293 if m5
.options
.outdir
:
294 cptdir
= m5
.options
.outdir
298 # Checkpoints being taken via the command line at <when> and at
299 # subsequent periods of <period>. Checkpoint instructions
300 # received from the benchmark running are ignored and skipped in
301 # favor of command line checkpoint instructions.
302 if options
.take_checkpoints
!= None :
303 if options
.at_instruction
or options
.simpoint
:
304 checkpoint_inst
= int(options
.take_checkpoints
)
306 # maintain correct offset if we restored from some instruction
307 if options
.checkpoint_restore
!= None:
308 checkpoint_inst
+= options
.checkpoint_restore
310 print "Creating checkpoint at inst:%d" % (checkpoint_inst
)
311 exit_event
= m5
.simulate()
312 print "exit cause = %s" % (exit_event
.getCause())
314 # skip checkpoint instructions should they exist
315 while exit_event
.getCause() == "checkpoint":
316 exit_event
= m5
.simulate()
318 if exit_event
.getCause() == \
319 "a thread reached the max instruction count":
320 m5
.checkpoint(joinpath(cptdir
, "cpt.%s.%d" % \
321 (options
.bench
, checkpoint_inst
)))
322 print "Checkpoint written."
325 if exit_event
.getCause() == "user interrupt received":
326 exit_cause
= exit_event
.getCause();
328 when
, period
= options
.take_checkpoints
.split(",", 1)
332 exit_event
= m5
.simulate(when
)
333 while exit_event
.getCause() == "checkpoint":
334 exit_event
= m5
.simulate(when
- m5
.curTick())
336 if exit_event
.getCause() == "simulate() limit reached":
337 m5
.checkpoint(joinpath(cptdir
, "cpt.%d"))
341 exit_cause
= "maximum %d checkpoints dropped" % max_checkpoints
342 while num_checkpoints
< max_checkpoints
and \
343 exit_event
.getCause() == "simulate() limit reached":
344 if (sim_ticks
+ period
) > maxtick
:
345 exit_event
= m5
.simulate(maxtick
- sim_ticks
)
346 exit_cause
= exit_event
.getCause()
349 exit_event
= m5
.simulate(period
)
351 while exit_event
.getCause() == "checkpoint":
352 exit_event
= m5
.simulate(sim_ticks
- m5
.curTick())
353 if exit_event
.getCause() == "simulate() limit reached":
354 m5
.checkpoint(joinpath(cptdir
, "cpt.%d"))
357 if exit_event
.getCause() != "simulate() limit reached":
358 exit_cause
= exit_event
.getCause();
360 else: # no checkpoints being taken via this script
361 if options
.fast_forward
:
363 print "**** REAL SIMULATION ****"
364 exit_event
= m5
.simulate(maxtick
)
366 while exit_event
.getCause() == "checkpoint":
367 m5
.checkpoint(joinpath(cptdir
, "cpt.%d"))
369 if num_checkpoints
== max_checkpoints
:
370 exit_cause
= "maximum %d checkpoints dropped" % max_checkpoints
373 exit_event
= m5
.simulate(maxtick
- m5
.curTick())
374 exit_cause
= exit_event
.getCause()
377 exit_cause
= exit_event
.getCause()
378 print 'Exiting @ tick %i because %s' % (m5
.curTick(), exit_cause
)
380 if options
.checkpoint_at_end
:
381 m5
.checkpoint(joinpath(cptdir
, "cpt.%d"))