Simulation.py revision 8718
1# Copyright (c) 2006-2008 The Regents of The University of Michigan 2# Copyright (c) 2010 Advanced Micro Devices, Inc. 3# All rights reserved. 4# 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. 15# 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. 27# 28# Authors: Lisa Hsu 29 30from os import getcwd 31from os.path import join as joinpath 32 33import m5 34from m5.defines import buildEnv 35from m5.objects import * 36from m5.util import * 37 38addToPath('../common') 39 40def setCPUClass(options): 41 42 atomic = False 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" 48 sys.exit(1) 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" 53 sys.exit(1) 54 class TmpClass(InOrderCPU): pass 55 else: 56 class TmpClass(AtomicSimpleCPU): pass 57 atomic = True 58 59 CPUClass = None 60 test_mem_mode = 'atomic' 61 62 if not atomic: 63 if options.checkpoint_restore != None: 64 if options.restore_with_cpu != options.cpu_type: 65 CPUClass = TmpClass 66 class TmpClass(AtomicSimpleCPU): pass 67 else: 68 if options.restore_with_cpu != "atomic": 69 test_mem_mode = 'timing' 70 71 elif options.fast_forward: 72 CPUClass = TmpClass 73 class TmpClass(AtomicSimpleCPU): pass 74 else: 75 test_mem_mode = 'timing' 76 77 return (TmpClass, test_mem_mode, CPUClass) 78 79 80def run(options, root, testsys, cpu_class): 81 if options.maxtick: 82 maxtick = options.maxtick 83 elif options.maxtime: 84 simtime = m5.ticks.seconds(simtime) 85 print "simulating for: ", simtime 86 maxtick = simtime 87 else: 88 maxtick = m5.MaxTick 89 90 if options.checkpoint_dir: 91 cptdir = options.checkpoint_dir 92 elif m5.options.outdir: 93 cptdir = m5.options.outdir 94 else: 95 cptdir = getcwd() 96 97 if options.fast_forward and options.checkpoint_restore != None: 98 fatal("Can't specify both --fast-forward and --checkpoint-restore") 99 100 if options.standard_switch and not options.caches: 101 fatal("Must specify --caches when using --standard-switch") 102 103 np = options.num_cpus 104 max_checkpoints = options.max_checkpoints 105 switch_cpus = None 106 107 if options.prog_interval: 108 for i in xrange(np): 109 testsys.cpu[i].progress_interval = options.prog_interval 110 111 if options.maxinsts: 112 for i in xrange(np): 113 testsys.cpu[i].max_insts_any_thread = options.maxinsts 114 115 if cpu_class: 116 switch_cpus = [cpu_class(defer_registration=True, cpu_id=(np+i)) 117 for i in xrange(np)] 118 119 for i in xrange(np): 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 126 # simulation period 127 if options.maxinsts: 128 switch_cpus[i].max_insts_any_thread = options.maxinsts 129 130 testsys.switch_cpus = switch_cpus 131 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 132 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" 137 sys.exit(1) 138 139 switch_cpus = [TimingSimpleCPU(defer_registration=True, cpu_id=(np+i)) 140 for i in xrange(np)] 141 switch_cpus_1 = [DerivO3CPU(defer_registration=True, cpu_id=(2*np+i)) 142 for i in xrange(np)] 143 144 for i in xrange(np): 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 152 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 166 else: 167 testsys.cpu[i].max_insts_any_thread = 1 168 169 # warmup period 170 if options.warmup_insts: 171 switch_cpus[i].max_insts_any_thread = options.warmup_insts 172 173 # simulation period 174 if options.maxinsts: 175 switch_cpus_1[i].max_insts_any_thread = options.maxinsts 176 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)] 181 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 187 if options.simpoint: 188 for i in xrange(np): 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 195 else: 196 options.take_checkpoints = offset 197 # Set all test cpus with the right number of instructions 198 # for the upcoming simulation 199 for i in xrange(np): 200 testsys.cpu[i].max_insts_any_thread = offset 201 202 checkpoint_dir = None 203 if options.checkpoint_restore != None: 204 from os.path import isdir, exists 205 from os import listdir 206 import re 207 208 if not isdir(cptdir): 209 fatal("checkpoint dir %s does not exist!", cptdir) 210 211 if options.at_instruction or options.simpoint: 212 inst = options.checkpoint_restore 213 if options.simpoint: 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) 218 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) 223 else: 224 dirs = listdir(cptdir) 225 expr = re.compile('cpt\.([0-9]*)') 226 cpts = [] 227 for dir in dirs: 228 match = expr.match(dir) 229 if match: 230 cpts.append(match.group(1)) 231 232 cpts.sort(lambda a,b: cmp(long(a), long(b))) 233 234 cpt_num = options.checkpoint_restore 235 236 if cpt_num > len(cpts): 237 fatal('Checkpoint %d not found', cpt_num) 238 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]) 242 243 m5.instantiate(checkpoint_dir) 244 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() 254 else: 255 print "Switch at curTick count:%s" % str(10000) 256 exit_event = m5.simulate(10000) 257 print "Switched CPUS @ tick %s" % (m5.curTick()) 258 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. 264 265 m5.changeToTiming(testsys) 266 m5.switchCpus(switch_cpu_list) 267 m5.resume(testsys) 268 269 if options.standard_switch: 270 print "Switch at instruction count:%d" % \ 271 (testsys.switch_cpus[0].max_insts_any_thread) 272 273 #warmup instruction count may have already been set 274 if options.warmup_insts: 275 exit_event = m5.simulate() 276 else: 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) 281 m5.drain(testsys) 282 m5.switchCpus(switch_cpu_list1) 283 m5.resume(testsys) 284 285 num_checkpoints = 0 286 exit_cause = '' 287 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 295 else: 296 cptdir = getcwd() 297 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) 305 306 # maintain correct offset if we restored from some instruction 307 if options.checkpoint_restore != None: 308 checkpoint_inst += options.checkpoint_restore 309 310 print "Creating checkpoint at inst:%d" % (checkpoint_inst) 311 exit_event = m5.simulate() 312 print "exit cause = %s" % (exit_event.getCause()) 313 314 # skip checkpoint instructions should they exist 315 while exit_event.getCause() == "checkpoint": 316 exit_event = m5.simulate() 317 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." 323 num_checkpoints += 1 324 325 if exit_event.getCause() == "user interrupt received": 326 exit_cause = exit_event.getCause(); 327 else: 328 when, period = options.take_checkpoints.split(",", 1) 329 when = int(when) 330 period = int(period) 331 332 exit_event = m5.simulate(when) 333 while exit_event.getCause() == "checkpoint": 334 exit_event = m5.simulate(when - m5.curTick()) 335 336 if exit_event.getCause() == "simulate() limit reached": 337 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 338 num_checkpoints += 1 339 340 sim_ticks = when 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() 347 break 348 else: 349 exit_event = m5.simulate(period) 350 sim_ticks += 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")) 355 num_checkpoints += 1 356 357 if exit_event.getCause() != "simulate() limit reached": 358 exit_cause = exit_event.getCause(); 359 360 else: # no checkpoints being taken via this script 361 if options.fast_forward: 362 m5.stats.reset() 363 print "**** REAL SIMULATION ****" 364 exit_event = m5.simulate(maxtick) 365 366 while exit_event.getCause() == "checkpoint": 367 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 368 num_checkpoints += 1 369 if num_checkpoints == max_checkpoints: 370 exit_cause = "maximum %d checkpoints dropped" % max_checkpoints 371 break 372 373 exit_event = m5.simulate(maxtick - m5.curTick()) 374 exit_cause = exit_event.getCause() 375 376 if exit_cause == '': 377 exit_cause = exit_event.getCause() 378 print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause) 379 380 if options.checkpoint_at_end: 381 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 382 383