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