Simulation.py revision 8724:7b4d80b26e35
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 if not buildEnv['FULL_SYSTEM']: 128 switch_cpus[i].workload = testsys.cpu[i].workload 129 switch_cpus[i].clock = testsys.cpu[0].clock 130 # simulation period 131 if options.maxinsts: 132 switch_cpus[i].max_insts_any_thread = options.maxinsts 133 134 testsys.switch_cpus = switch_cpus 135 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 136 137 if options.standard_switch: 138 if not options.caches: 139 # O3 CPU must have a cache to work. 140 print "O3 CPU must be used with caches" 141 sys.exit(1) 142 143 switch_cpus = [TimingSimpleCPU(defer_registration=True, cpu_id=(np+i)) 144 for i in xrange(np)] 145 switch_cpus_1 = [DerivO3CPU(defer_registration=True, cpu_id=(2*np+i)) 146 for i in xrange(np)] 147 148 for i in xrange(np): 149 switch_cpus[i].system = testsys 150 switch_cpus_1[i].system = testsys 151 if not buildEnv['FULL_SYSTEM']: 152 switch_cpus[i].workload = testsys.cpu[i].workload 153 switch_cpus_1[i].workload = testsys.cpu[i].workload 154 switch_cpus[i].clock = testsys.cpu[0].clock 155 switch_cpus_1[i].clock = testsys.cpu[0].clock 156 157 # if restoring, make atomic cpu simulate only a few instructions 158 if options.checkpoint_restore != None: 159 testsys.cpu[i].max_insts_any_thread = 1 160 # Fast forward to specified location if we are not restoring 161 elif options.fast_forward: 162 testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) 163 # Fast forward to a simpoint (warning: time consuming) 164 elif options.simpoint: 165 if testsys.cpu[i].workload[0].simpoint == 0: 166 fatal('simpoint not found') 167 testsys.cpu[i].max_insts_any_thread = \ 168 testsys.cpu[i].workload[0].simpoint 169 # No distance specified, just switch 170 else: 171 testsys.cpu[i].max_insts_any_thread = 1 172 173 # warmup period 174 if options.warmup_insts: 175 switch_cpus[i].max_insts_any_thread = options.warmup_insts 176 177 # simulation period 178 if options.maxinsts: 179 switch_cpus_1[i].max_insts_any_thread = options.maxinsts 180 181 testsys.switch_cpus = switch_cpus 182 testsys.switch_cpus_1 = switch_cpus_1 183 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 184 switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)] 185 186 # set the checkpoint in the cpu before m5.instantiate is called 187 if options.take_checkpoints != None and \ 188 (options.simpoint or options.at_instruction): 189 offset = int(options.take_checkpoints) 190 # Set an instruction break point 191 if options.simpoint: 192 for i in xrange(np): 193 if testsys.cpu[i].workload[0].simpoint == 0: 194 fatal('no simpoint for testsys.cpu[%d].workload[0]', i) 195 checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset 196 testsys.cpu[i].max_insts_any_thread = checkpoint_inst 197 # used for output below 198 options.take_checkpoints = checkpoint_inst 199 else: 200 options.take_checkpoints = offset 201 # Set all test cpus with the right number of instructions 202 # for the upcoming simulation 203 for i in xrange(np): 204 testsys.cpu[i].max_insts_any_thread = offset 205 206 checkpoint_dir = None 207 if options.checkpoint_restore != None: 208 from os.path import isdir, exists 209 from os import listdir 210 import re 211 212 if not isdir(cptdir): 213 fatal("checkpoint dir %s does not exist!", cptdir) 214 215 if options.at_instruction or options.simpoint: 216 inst = options.checkpoint_restore 217 if options.simpoint: 218 # assume workload 0 has the simpoint 219 if testsys.cpu[0].workload[0].simpoint == 0: 220 fatal('Unable to find simpoint') 221 inst += int(testsys.cpu[0].workload[0].simpoint) 222 223 checkpoint_dir = joinpath(cptdir, 224 "cpt.%s.%s" % (options.bench, inst)) 225 if not exists(checkpoint_dir): 226 fatal("Unable to find checkpoint directory %s", checkpoint_dir) 227 else: 228 dirs = listdir(cptdir) 229 expr = re.compile('cpt\.([0-9]*)') 230 cpts = [] 231 for dir in dirs: 232 match = expr.match(dir) 233 if match: 234 cpts.append(match.group(1)) 235 236 cpts.sort(lambda a,b: cmp(long(a), long(b))) 237 238 cpt_num = options.checkpoint_restore 239 240 if cpt_num > len(cpts): 241 fatal('Checkpoint %d not found', cpt_num) 242 243 ## Adjust max tick based on our starting tick 244 maxtick = maxtick - int(cpts[cpt_num - 1]) 245 checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1]) 246 247 m5.instantiate(checkpoint_dir) 248 249 if options.standard_switch or cpu_class: 250 if options.standard_switch: 251 print "Switch at instruction count:%s" % \ 252 str(testsys.cpu[0].max_insts_any_thread) 253 exit_event = m5.simulate() 254 elif cpu_class and options.fast_forward: 255 print "Switch at instruction count:%s" % \ 256 str(testsys.cpu[0].max_insts_any_thread) 257 exit_event = m5.simulate() 258 else: 259 print "Switch at curTick count:%s" % str(10000) 260 exit_event = m5.simulate(10000) 261 print "Switched CPUS @ tick %s" % (m5.curTick()) 262 263 # when you change to Timing (or Atomic), you halt the system 264 # given as argument. When you are finished with the system 265 # changes (including switchCpus), you must resume the system 266 # manually. You DON'T need to resume after just switching 267 # CPUs if you haven't changed anything on the system level. 268 269 m5.changeToTiming(testsys) 270 m5.switchCpus(switch_cpu_list) 271 m5.resume(testsys) 272 273 if options.standard_switch: 274 print "Switch at instruction count:%d" % \ 275 (testsys.switch_cpus[0].max_insts_any_thread) 276 277 #warmup instruction count may have already been set 278 if options.warmup_insts: 279 exit_event = m5.simulate() 280 else: 281 exit_event = m5.simulate(options.warmup) 282 print "Switching CPUS @ tick %s" % (m5.curTick()) 283 print "Simulation ends instruction count:%d" % \ 284 (testsys.switch_cpus_1[0].max_insts_any_thread) 285 m5.drain(testsys) 286 m5.switchCpus(switch_cpu_list1) 287 m5.resume(testsys) 288 289 num_checkpoints = 0 290 exit_cause = '' 291 292 # If we're taking and restoring checkpoints, use checkpoint_dir 293 # option only for finding the checkpoints to restore from. This 294 # lets us test checkpointing by restoring from one set of 295 # checkpoints, generating a second set, and then comparing them. 296 if options.take_checkpoints and options.checkpoint_restore: 297 if m5.options.outdir: 298 cptdir = m5.options.outdir 299 else: 300 cptdir = getcwd() 301 302 # Checkpoints being taken via the command line at <when> and at 303 # subsequent periods of <period>. Checkpoint instructions 304 # received from the benchmark running are ignored and skipped in 305 # favor of command line checkpoint instructions. 306 if options.take_checkpoints != None : 307 if options.at_instruction or options.simpoint: 308 checkpoint_inst = int(options.take_checkpoints) 309 310 # maintain correct offset if we restored from some instruction 311 if options.checkpoint_restore != None: 312 checkpoint_inst += options.checkpoint_restore 313 314 print "Creating checkpoint at inst:%d" % (checkpoint_inst) 315 exit_event = m5.simulate() 316 print "exit cause = %s" % (exit_event.getCause()) 317 318 # skip checkpoint instructions should they exist 319 while exit_event.getCause() == "checkpoint": 320 exit_event = m5.simulate() 321 322 if exit_event.getCause() == \ 323 "a thread reached the max instruction count": 324 m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \ 325 (options.bench, checkpoint_inst))) 326 print "Checkpoint written." 327 num_checkpoints += 1 328 329 if exit_event.getCause() == "user interrupt received": 330 exit_cause = exit_event.getCause(); 331 else: 332 when, period = options.take_checkpoints.split(",", 1) 333 when = int(when) 334 period = int(period) 335 336 exit_event = m5.simulate(when) 337 while exit_event.getCause() == "checkpoint": 338 exit_event = m5.simulate(when - m5.curTick()) 339 340 if exit_event.getCause() == "simulate() limit reached": 341 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 342 num_checkpoints += 1 343 344 sim_ticks = when 345 exit_cause = "maximum %d checkpoints dropped" % max_checkpoints 346 while num_checkpoints < max_checkpoints and \ 347 exit_event.getCause() == "simulate() limit reached": 348 if (sim_ticks + period) > maxtick: 349 exit_event = m5.simulate(maxtick - sim_ticks) 350 exit_cause = exit_event.getCause() 351 break 352 else: 353 exit_event = m5.simulate(period) 354 sim_ticks += period 355 while exit_event.getCause() == "checkpoint": 356 exit_event = m5.simulate(sim_ticks - m5.curTick()) 357 if exit_event.getCause() == "simulate() limit reached": 358 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 359 num_checkpoints += 1 360 361 if exit_event.getCause() != "simulate() limit reached": 362 exit_cause = exit_event.getCause(); 363 364 else: # no checkpoints being taken via this script 365 if options.fast_forward: 366 m5.stats.reset() 367 print "**** REAL SIMULATION ****" 368 exit_event = m5.simulate(maxtick) 369 370 while exit_event.getCause() == "checkpoint": 371 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 372 num_checkpoints += 1 373 if num_checkpoints == max_checkpoints: 374 exit_cause = "maximum %d checkpoints dropped" % max_checkpoints 375 break 376 377 exit_event = m5.simulate(maxtick - m5.curTick()) 378 exit_cause = exit_event.getCause() 379 380 if exit_cause == '': 381 exit_cause = exit_event.getCause() 382 print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause) 383 384 if options.checkpoint_at_end: 385 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 386 387