Simulation.py revision 8887:20ea02da9c53
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 * 37from O3_ARM_v7a import * 38 39addToPath('../common') 40 41def setCPUClass(options): 42 43 atomic = False 44 if options.cpu_type == "timing": 45 class TmpClass(TimingSimpleCPU): pass 46 elif options.cpu_type == "detailed" or options.cpu_type == "arm_detailed": 47 if not options.caches and not options.ruby: 48 print "O3 CPU must be used with caches" 49 sys.exit(1) 50 if options.cpu_type == "arm_detailed": 51 class TmpClass(O3_ARM_v7a_3): pass 52 else: 53 class TmpClass(DerivO3CPU): pass 54 elif options.cpu_type == "inorder": 55 if not options.caches: 56 print "InOrder CPU must be used with caches" 57 sys.exit(1) 58 class TmpClass(InOrderCPU): pass 59 else: 60 class TmpClass(AtomicSimpleCPU): pass 61 atomic = True 62 63 CPUClass = None 64 test_mem_mode = 'atomic' 65 66 if not atomic: 67 if options.checkpoint_restore != None: 68 if options.restore_with_cpu != options.cpu_type: 69 CPUClass = TmpClass 70 class TmpClass(AtomicSimpleCPU): pass 71 else: 72 if options.restore_with_cpu != "atomic": 73 test_mem_mode = 'timing' 74 75 elif options.fast_forward: 76 CPUClass = TmpClass 77 class TmpClass(AtomicSimpleCPU): pass 78 else: 79 test_mem_mode = 'timing' 80 81 return (TmpClass, test_mem_mode, CPUClass) 82 83 84def run(options, root, testsys, cpu_class): 85 if options.maxtick: 86 maxtick = options.maxtick 87 elif options.maxtime: 88 simtime = m5.ticks.seconds(simtime) 89 print "simulating for: ", simtime 90 maxtick = simtime 91 else: 92 maxtick = m5.MaxTick 93 94 if options.checkpoint_dir: 95 cptdir = options.checkpoint_dir 96 elif m5.options.outdir: 97 cptdir = m5.options.outdir 98 else: 99 cptdir = getcwd() 100 101 if options.fast_forward and options.checkpoint_restore != None: 102 fatal("Can't specify both --fast-forward and --checkpoint-restore") 103 104 if options.standard_switch and not options.caches: 105 fatal("Must specify --caches when using --standard-switch") 106 107 np = options.num_cpus 108 max_checkpoints = options.max_checkpoints 109 switch_cpus = None 110 111 if options.prog_interval: 112 for i in xrange(np): 113 testsys.cpu[i].progress_interval = options.prog_interval 114 115 if options.maxinsts: 116 for i in xrange(np): 117 testsys.cpu[i].max_insts_any_thread = options.maxinsts 118 119 if cpu_class: 120 switch_cpus = [cpu_class(defer_registration=True, cpu_id=(np+i)) 121 for i in xrange(np)] 122 123 for i in xrange(np): 124 if options.fast_forward: 125 testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) 126 switch_cpus[i].system = testsys 127 switch_cpus[i].workload = testsys.cpu[i].workload 128 switch_cpus[i].clock = testsys.cpu[0].clock 129 # simulation period 130 if options.maxinsts: 131 switch_cpus[i].max_insts_any_thread = options.maxinsts 132 # Add checker cpu if selected 133 if options.checker: 134 switch_cpus[i].addCheckerCpu() 135 136 testsys.switch_cpus = switch_cpus 137 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 138 139 if options.standard_switch: 140 if not options.caches: 141 # O3 CPU must have a cache to work. 142 print "O3 CPU must be used with caches" 143 sys.exit(1) 144 145 switch_cpus = [TimingSimpleCPU(defer_registration=True, cpu_id=(np+i)) 146 for i in xrange(np)] 147 switch_cpus_1 = [DerivO3CPU(defer_registration=True, cpu_id=(2*np+i)) 148 for i in xrange(np)] 149 150 for i in xrange(np): 151 switch_cpus[i].system = testsys 152 switch_cpus_1[i].system = testsys 153 switch_cpus[i].workload = testsys.cpu[i].workload 154 switch_cpus_1[i].workload = testsys.cpu[i].workload 155 switch_cpus[i].clock = testsys.cpu[0].clock 156 switch_cpus_1[i].clock = testsys.cpu[0].clock 157 158 # if restoring, make atomic cpu simulate only a few instructions 159 if options.checkpoint_restore != None: 160 testsys.cpu[i].max_insts_any_thread = 1 161 # Fast forward to specified location if we are not restoring 162 elif options.fast_forward: 163 testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) 164 # Fast forward to a simpoint (warning: time consuming) 165 elif options.simpoint: 166 if testsys.cpu[i].workload[0].simpoint == 0: 167 fatal('simpoint not found') 168 testsys.cpu[i].max_insts_any_thread = \ 169 testsys.cpu[i].workload[0].simpoint 170 # No distance specified, just switch 171 else: 172 testsys.cpu[i].max_insts_any_thread = 1 173 174 # warmup period 175 if options.warmup_insts: 176 switch_cpus[i].max_insts_any_thread = options.warmup_insts 177 178 # simulation period 179 if options.maxinsts: 180 switch_cpus_1[i].max_insts_any_thread = options.maxinsts 181 182 # attach the checker cpu if selected 183 if options.checker: 184 switch_cpus[i].addCheckerCpu() 185 switch_cpus_1[i].addCheckerCpu() 186 187 testsys.switch_cpus = switch_cpus 188 testsys.switch_cpus_1 = switch_cpus_1 189 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 190 switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)] 191 192 # set the checkpoint in the cpu before m5.instantiate is called 193 if options.take_checkpoints != None and \ 194 (options.simpoint or options.at_instruction): 195 offset = int(options.take_checkpoints) 196 # Set an instruction break point 197 if options.simpoint: 198 for i in xrange(np): 199 if testsys.cpu[i].workload[0].simpoint == 0: 200 fatal('no simpoint for testsys.cpu[%d].workload[0]', i) 201 checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset 202 testsys.cpu[i].max_insts_any_thread = checkpoint_inst 203 # used for output below 204 options.take_checkpoints = checkpoint_inst 205 else: 206 options.take_checkpoints = offset 207 # Set all test cpus with the right number of instructions 208 # for the upcoming simulation 209 for i in xrange(np): 210 testsys.cpu[i].max_insts_any_thread = offset 211 212 checkpoint_dir = None 213 if options.checkpoint_restore != None: 214 from os.path import isdir, exists 215 from os import listdir 216 import re 217 218 if not isdir(cptdir): 219 fatal("checkpoint dir %s does not exist!", cptdir) 220 221 if options.at_instruction or options.simpoint: 222 inst = options.checkpoint_restore 223 if options.simpoint: 224 # assume workload 0 has the simpoint 225 if testsys.cpu[0].workload[0].simpoint == 0: 226 fatal('Unable to find simpoint') 227 inst += int(testsys.cpu[0].workload[0].simpoint) 228 229 checkpoint_dir = joinpath(cptdir, 230 "cpt.%s.%s" % (options.bench, inst)) 231 if not exists(checkpoint_dir): 232 fatal("Unable to find checkpoint directory %s", checkpoint_dir) 233 else: 234 dirs = listdir(cptdir) 235 expr = re.compile('cpt\.([0-9]*)') 236 cpts = [] 237 for dir in dirs: 238 match = expr.match(dir) 239 if match: 240 cpts.append(match.group(1)) 241 242 cpts.sort(lambda a,b: cmp(long(a), long(b))) 243 244 cpt_num = options.checkpoint_restore 245 246 if cpt_num > len(cpts): 247 fatal('Checkpoint %d not found', cpt_num) 248 249 ## Adjust max tick based on our starting tick 250 maxtick = maxtick - int(cpts[cpt_num - 1]) 251 checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1]) 252 253 m5.instantiate(checkpoint_dir) 254 255 if options.standard_switch or cpu_class: 256 if options.standard_switch: 257 print "Switch at instruction count:%s" % \ 258 str(testsys.cpu[0].max_insts_any_thread) 259 exit_event = m5.simulate() 260 elif cpu_class and options.fast_forward: 261 print "Switch at instruction count:%s" % \ 262 str(testsys.cpu[0].max_insts_any_thread) 263 exit_event = m5.simulate() 264 else: 265 print "Switch at curTick count:%s" % str(10000) 266 exit_event = m5.simulate(10000) 267 print "Switched CPUS @ tick %s" % (m5.curTick()) 268 269 # when you change to Timing (or Atomic), you halt the system 270 # given as argument. When you are finished with the system 271 # changes (including switchCpus), you must resume the system 272 # manually. You DON'T need to resume after just switching 273 # CPUs if you haven't changed anything on the system level. 274 275 m5.changeToTiming(testsys) 276 m5.switchCpus(switch_cpu_list) 277 m5.resume(testsys) 278 279 if options.standard_switch: 280 print "Switch at instruction count:%d" % \ 281 (testsys.switch_cpus[0].max_insts_any_thread) 282 283 #warmup instruction count may have already been set 284 if options.warmup_insts: 285 exit_event = m5.simulate() 286 else: 287 exit_event = m5.simulate(options.warmup) 288 print "Switching CPUS @ tick %s" % (m5.curTick()) 289 print "Simulation ends instruction count:%d" % \ 290 (testsys.switch_cpus_1[0].max_insts_any_thread) 291 m5.drain(testsys) 292 m5.switchCpus(switch_cpu_list1) 293 m5.resume(testsys) 294 295 num_checkpoints = 0 296 exit_cause = '' 297 298 # If we're taking and restoring checkpoints, use checkpoint_dir 299 # option only for finding the checkpoints to restore from. This 300 # lets us test checkpointing by restoring from one set of 301 # checkpoints, generating a second set, and then comparing them. 302 if options.take_checkpoints and options.checkpoint_restore: 303 if m5.options.outdir: 304 cptdir = m5.options.outdir 305 else: 306 cptdir = getcwd() 307 308 # Checkpoints being taken via the command line at <when> and at 309 # subsequent periods of <period>. Checkpoint instructions 310 # received from the benchmark running are ignored and skipped in 311 # favor of command line checkpoint instructions. 312 if options.take_checkpoints != None : 313 if options.at_instruction or options.simpoint: 314 checkpoint_inst = int(options.take_checkpoints) 315 316 # maintain correct offset if we restored from some instruction 317 if options.checkpoint_restore != None: 318 checkpoint_inst += options.checkpoint_restore 319 320 print "Creating checkpoint at inst:%d" % (checkpoint_inst) 321 exit_event = m5.simulate() 322 print "exit cause = %s" % (exit_event.getCause()) 323 324 # skip checkpoint instructions should they exist 325 while exit_event.getCause() == "checkpoint": 326 exit_event = m5.simulate() 327 328 if exit_event.getCause() == \ 329 "a thread reached the max instruction count": 330 m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \ 331 (options.bench, checkpoint_inst))) 332 print "Checkpoint written." 333 num_checkpoints += 1 334 335 if exit_event.getCause() == "user interrupt received": 336 exit_cause = exit_event.getCause(); 337 else: 338 when, period = options.take_checkpoints.split(",", 1) 339 when = int(when) 340 period = int(period) 341 342 exit_event = m5.simulate(when) 343 while exit_event.getCause() == "checkpoint": 344 exit_event = m5.simulate(when - m5.curTick()) 345 346 if exit_event.getCause() == "simulate() limit reached": 347 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 348 num_checkpoints += 1 349 350 sim_ticks = when 351 exit_cause = "maximum %d checkpoints dropped" % max_checkpoints 352 while num_checkpoints < max_checkpoints and \ 353 exit_event.getCause() == "simulate() limit reached": 354 if (sim_ticks + period) > maxtick: 355 exit_event = m5.simulate(maxtick - sim_ticks) 356 exit_cause = exit_event.getCause() 357 break 358 else: 359 exit_event = m5.simulate(period) 360 sim_ticks += period 361 while exit_event.getCause() == "checkpoint": 362 exit_event = m5.simulate(sim_ticks - m5.curTick()) 363 if exit_event.getCause() == "simulate() limit reached": 364 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 365 num_checkpoints += 1 366 367 if exit_event.getCause() != "simulate() limit reached": 368 exit_cause = exit_event.getCause(); 369 370 else: # no checkpoints being taken via this script 371 if options.fast_forward: 372 m5.stats.reset() 373 print "**** REAL SIMULATION ****" 374 exit_event = m5.simulate(maxtick) 375 376 while exit_event.getCause() == "checkpoint": 377 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 378 num_checkpoints += 1 379 if num_checkpoints == max_checkpoints: 380 exit_cause = "maximum %d checkpoints dropped" % max_checkpoints 381 break 382 383 exit_event = m5.simulate(maxtick - m5.curTick()) 384 exit_cause = exit_event.getCause() 385 386 if exit_cause == '': 387 exit_cause = exit_event.getCause() 388 print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause) 389 390 if options.checkpoint_at_end: 391 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 392 393