1 # Copyright (c) 2006-2008 The Regents of The University of Michigan
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met: redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer;
8 # redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution;
11 # neither the name of the copyright holders nor the names of its
12 # contributors may be used to endorse or promote products derived from
13 # this software without specific prior written permission.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 from os
.path
import join
as joinpath
33 from m5
.defines
import buildEnv
34 from m5
.objects
import *
37 addToPath('../common')
39 def setCPUClass(options
):
43 class TmpClass(TimingSimpleCPU
): pass
44 elif options
.detailed
:
45 if not options
.caches
:
46 print "O3 CPU must be used with caches"
48 class TmpClass(DerivO3CPU
): pass
50 if not options
.caches
:
51 print "InOrder CPU must be used with caches"
53 class TmpClass(InOrderCPU
): pass
55 class TmpClass(AtomicSimpleCPU
): pass
59 test_mem_mode
= 'atomic'
62 if options
.checkpoint_restore
!= None or options
.fast_forward
:
64 class TmpClass(AtomicSimpleCPU
): pass
66 test_mem_mode
= 'timing'
68 return (TmpClass
, test_mem_mode
, CPUClass
)
71 def run(options
, root
, testsys
, cpu_class
):
73 maxtick
= options
.maxtick
75 simtime
= m5
.ticks
.seconds(simtime
)
76 print "simulating for: ", simtime
81 if options
.checkpoint_dir
:
82 cptdir
= options
.checkpoint_dir
83 elif m5
.options
.outdir
:
84 cptdir
= m5
.options
.outdir
88 if options
.fast_forward
and options
.checkpoint_restore
!= None:
89 fatal("Can't specify both --fast-forward and --checkpoint-restore")
91 if options
.standard_switch
and not options
.caches
:
92 fatal("Must specify --caches when using --standard-switch")
95 max_checkpoints
= options
.max_checkpoints
98 if options
.prog_intvl
:
100 testsys
.cpu
[i
].progress_interval
= options
.prog_intvl
104 testsys
.cpu
[i
].max_insts_any_thread
= options
.maxinsts
107 switch_cpus
= [cpu_class(defer_registration
=True, cpu_id
=(np
+i
))
111 if options
.fast_forward
:
112 testsys
.cpu
[i
].max_insts_any_thread
= int(options
.fast_forward
)
113 switch_cpus
[i
].system
= testsys
114 if not buildEnv
['FULL_SYSTEM']:
115 switch_cpus
[i
].workload
= testsys
.cpu
[i
].workload
116 switch_cpus
[i
].clock
= testsys
.cpu
[0].clock
119 switch_cpus
[i
].max_insts_any_thread
= options
.max_inst
121 testsys
.switch_cpus
= switch_cpus
122 switch_cpu_list
= [(testsys
.cpu
[i
], switch_cpus
[i
]) for i
in xrange(np
)]
124 if options
.standard_switch
:
125 switch_cpus
= [TimingSimpleCPU(defer_registration
=True, cpu_id
=(np
+i
))
127 switch_cpus_1
= [DerivO3CPU(defer_registration
=True, cpu_id
=(2*np
+i
))
131 switch_cpus
[i
].system
= testsys
132 switch_cpus_1
[i
].system
= testsys
133 if not buildEnv
['FULL_SYSTEM']:
134 switch_cpus
[i
].workload
= testsys
.cpu
[i
].workload
135 switch_cpus_1
[i
].workload
= testsys
.cpu
[i
].workload
136 switch_cpus
[i
].clock
= testsys
.cpu
[0].clock
137 switch_cpus_1
[i
].clock
= testsys
.cpu
[0].clock
139 # if restoring, make atomic cpu simulate only a few instructions
140 if options
.checkpoint_restore
!= None:
141 testsys
.cpu
[i
].max_insts_any_thread
= 1
142 # Fast forward to specified location if we are not restoring
143 elif options
.fast_forward
:
144 testsys
.cpu
[i
].max_insts_any_thread
= int(options
.fast_forward
)
145 # Fast forward to a simpoint (warning: time consuming)
146 elif options
.simpoint
:
147 if testsys
.cpu
[i
].workload
[0].simpoint
== 0:
148 fatal('simpoint not found')
149 testsys
.cpu
[i
].max_insts_any_thread
= \
150 testsys
.cpu
[i
].workload
[0].simpoint
151 # No distance specified, just switch
153 testsys
.cpu
[i
].max_insts_any_thread
= 1
156 if options
.warmup_insts
:
157 switch_cpus
[i
].max_insts_any_thread
= options
.warmup_insts
161 switch_cpus_1
[i
].max_insts_any_thread
= options
.max_inst
163 if not options
.caches
:
164 # O3 CPU must have a cache to work.
165 print "O3 CPU must be used with caches"
168 testsys
.switch_cpus
= switch_cpus
169 testsys
.switch_cpus_1
= switch_cpus_1
170 switch_cpu_list
= [(testsys
.cpu
[i
], switch_cpus
[i
]) for i
in xrange(np
)]
171 switch_cpu_list1
= [(switch_cpus
[i
], switch_cpus_1
[i
]) for i
in xrange(np
)]
173 # set the checkpoint in the cpu before m5.instantiate is called
174 if options
.take_checkpoints
!= None and \
175 (options
.simpoint
or options
.at_instruction
):
176 offset
= int(options
.take_checkpoints
)
177 # Set an instruction break point
180 if testsys
.cpu
[i
].workload
[0].simpoint
== 0:
181 fatal('no simpoint for testsys.cpu[%d].workload[0]', i
)
182 checkpoint_inst
= int(testsys
.cpu
[i
].workload
[0].simpoint
) + offset
183 testsys
.cpu
[i
].max_insts_any_thread
= checkpoint_inst
184 # used for output below
185 options
.take_checkpoints
= checkpoint_inst
187 options
.take_checkpoints
= offset
188 # Set all test cpus with the right number of instructions
189 # for the upcoming simulation
191 testsys
.cpu
[i
].max_insts_any_thread
= offset
195 if options
.checkpoint_restore
!= None:
196 from os
.path
import isdir
, exists
197 from os
import listdir
200 if not isdir(cptdir
):
201 fatal("checkpoint dir %s does not exist!", cptdir
)
203 if options
.at_instruction
:
204 checkpoint_dir
= joinpath(cptdir
, "cpt.%s.%s" % \
205 (options
.bench
, options
.checkpoint_restore
))
206 if not exists(checkpoint_dir
):
207 fatal("Unable to find checkpoint directory %s", checkpoint_dir
)
209 print "Restoring checkpoint ..."
210 m5
.restoreCheckpoint(root
, checkpoint_dir
)
212 elif options
.simpoint
:
213 # assume workload 0 has the simpoint
214 if testsys
.cpu
[0].workload
[0].simpoint
== 0:
215 fatal('Unable to find simpoint')
217 options
.checkpoint_restore
+= \
218 int(testsys
.cpu
[0].workload
[0].simpoint
)
220 checkpoint_dir
= joinpath(cptdir
, "cpt.%s.%d" % \
221 (options
.bench
, options
.checkpoint_restore
))
222 if not exists(checkpoint_dir
):
223 fatal("Unable to find checkpoint directory %s.%s",
224 options
.bench
, options
.checkpoint_restore
)
226 print "Restoring checkpoint ..."
227 m5
.restoreCheckpoint(root
,checkpoint_dir
)
230 dirs
= listdir(cptdir
)
231 expr
= re
.compile('cpt\.([0-9]*)')
234 match
= expr
.match(dir)
236 cpts
.append(match
.group(1))
238 cpts
.sort(lambda a
,b
: cmp(long(a
), long(b
)))
240 cpt_num
= options
.checkpoint_restore
242 if cpt_num
> len(cpts
):
243 fatal('Checkpoint %d not found', cpt_num
)
245 ## Adjust max tick based on our starting tick
246 maxtick
= maxtick
- int(cpts
[cpt_num
- 1])
248 ## Restore the checkpoint
249 m5
.restoreCheckpoint(root
,
250 joinpath(cptdir
, "cpt.%s" % cpts
[cpt_num
- 1]))
252 if options
.standard_switch
or cpu_class
:
253 if options
.standard_switch
:
254 print "Switch at instruction count:%s" % \
255 str(testsys
.cpu
[0].max_insts_any_thread
)
256 exit_event
= m5
.simulate()
257 elif cpu_class
and options
.fast_forward
:
258 print "Switch at instruction count:%s" % \
259 str(testsys
.cpu
[0].max_insts_any_thread
)
260 exit_event
= m5
.simulate()
262 print "Switch at curTick count:%s" % str(10000)
263 exit_event
= m5
.simulate(10000)
264 print "Switched CPUS @ cycle = %s" % (m5
.curTick())
266 # when you change to Timing (or Atomic), you halt the system
267 # given as argument. When you are finished with the system
268 # changes (including switchCpus), you must resume the system
269 # manually. You DON'T need to resume after just switching
270 # CPUs if you haven't changed anything on the system level.
272 m5
.changeToTiming(testsys
)
273 m5
.switchCpus(switch_cpu_list
)
276 if options
.standard_switch
:
277 print "Switch at instruction count:%d" % \
278 (testsys
.switch_cpus
[0].max_insts_any_thread
)
280 #warmup instruction count may have already been set
281 if options
.warmup_insts
:
282 exit_event
= m5
.simulate()
284 exit_event
= m5
.simulate(options
.warmup
)
285 print "Switching CPUS @ cycle = %s" % (m5
.curTick())
286 print "Simulation ends instruction count:%d" % \
287 (testsys
.switch_cpus_1
[0].max_insts_any_thread
)
289 m5
.switchCpus(switch_cpu_list1
)
295 # Checkpoints being taken via the command line at <when> and at
296 # subsequent periods of <period>. Checkpoint instructions
297 # received from the benchmark running are ignored and skipped in
298 # favor of command line checkpoint instructions.
299 if options
.take_checkpoints
!= None :
300 if options
.at_instruction
or options
.simpoint
:
301 checkpoint_inst
= int(options
.take_checkpoints
)
303 # maintain correct offset if we restored from some instruction
304 if options
.checkpoint_restore
!= None:
305 checkpoint_inst
+= options
.checkpoint_restore
307 print "Creating checkpoint at inst:%d" % (checkpoint_inst
)
308 exit_event
= m5
.simulate()
309 print "exit cause = %s" % (exit_event
.getCause())
311 # skip checkpoint instructions should they exist
312 while exit_event
.getCause() == "checkpoint":
313 exit_event
= m5
.simulate()
315 if exit_event
.getCause() == \
316 "a thread reached the max instruction count":
317 m5
.checkpoint(root
, joinpath(cptdir
, "cpt.%s.%d" % \
318 (options
.bench
, checkpoint_inst
)))
319 print "Checkpoint written."
322 if exit_event
.getCause() == "user interrupt received":
323 exit_cause
= exit_event
.getCause();
325 when
, period
= options
.take_checkpoints
.split(",", 1)
329 exit_event
= m5
.simulate(when
)
330 while exit_event
.getCause() == "checkpoint":
331 exit_event
= m5
.simulate(when
- m5
.curTick())
333 if exit_event
.getCause() == "simulate() limit reached":
334 m5
.checkpoint(root
, joinpath(cptdir
, "cpt.%d"))
338 exit_cause
= "maximum %d checkpoints dropped" % max_checkpoints
339 while num_checkpoints
< max_checkpoints
and \
340 exit_event
.getCause() == "simulate() limit reached":
341 if (sim_ticks
+ period
) > maxtick
:
342 exit_event
= m5
.simulate(maxtick
- sim_ticks
)
343 exit_cause
= exit_event
.getCause()
346 exit_event
= m5
.simulate(period
)
348 while exit_event
.getCause() == "checkpoint":
349 exit_event
= m5
.simulate(sim_ticks
- m5
.curTick())
350 if exit_event
.getCause() == "simulate() limit reached":
351 m5
.checkpoint(root
, joinpath(cptdir
, "cpt.%d"))
354 if exit_event
.getCause() != "simulate() limit reached":
355 exit_cause
= exit_event
.getCause();
357 else: # no checkpoints being taken via this script
358 if options
.fast_forward
:
360 print "**** REAL SIMULATION ****"
361 exit_event
= m5
.simulate(maxtick
)
363 while exit_event
.getCause() == "checkpoint":
364 m5
.checkpoint(root
, joinpath(cptdir
, "cpt.%d"))
366 if num_checkpoints
== max_checkpoints
:
367 exit_cause
= "maximum %d checkpoints dropped" % max_checkpoints
370 exit_event
= m5
.simulate(maxtick
- m5
.curTick())
371 exit_cause
= exit_event
.getCause()
374 exit_cause
= exit_event
.getCause()
375 print 'Exiting @ cycle %i because %s' % (m5
.curTick(), exit_cause
)