Simulation.py revision 9156:38dd0780322a
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 getCPUClass(cpu_type): 42 """Returns the required cpu class and the mode of operation. 43 """ 44 45 if cpu_type == "timing": 46 return TimingSimpleCPU, 'timing' 47 elif cpu_type == "detailed": 48 return DerivO3CPU, 'timing' 49 elif cpu_type == "arm_detailed": 50 return O3_ARM_v7a_3, 'timing' 51 elif cpu_type == "inorder": 52 return InOrderCPU, 'timing' 53 else: 54 return AtomicSimpleCPU, 'atomic' 55 56def setCPUClass(options): 57 """Returns two cpu classes and the initial mode of operation. 58 59 Restoring from a checkpoint or fast forwarding through a benchmark 60 can be done using one type of cpu, and then the actual 61 simulation can be carried out using another type. This function 62 returns these two types of cpus and the initial mode of operation 63 depending on the options provided. 64 """ 65 66 if options.cpu_type == "detailed" or \ 67 options.cpu_type == "arm_detailed" or \ 68 options.cpu_type == "inorder" : 69 if not options.caches and not options.ruby: 70 fatal("O3/Inorder CPU must be used with caches") 71 72 TmpClass, test_mem_mode = getCPUClass(options.cpu_type) 73 CPUClass = None 74 75 if options.checkpoint_restore != None: 76 if options.restore_with_cpu != options.cpu_type: 77 CPUClass = TmpClass 78 TmpClass, test_mem_mode = getCPUClass(options.restore_with_cpu) 79 elif options.fast_forward: 80 CPUClass = TmpClass 81 TmpClass = AtomicSimpleCPU 82 test_mem_mode = 'atomic' 83 84 return (TmpClass, test_mem_mode, CPUClass) 85 86def setWorkCountOptions(system, options): 87 if options.work_item_id != None: 88 system.work_item_id = options.work_item_id 89 if options.work_begin_cpu_id_exit != None: 90 system.work_begin_cpu_id_exit = options.work_begin_cpu_id_exit 91 if options.work_end_exit_count != None: 92 system.work_end_exit_count = options.work_end_exit_count 93 if options.work_end_checkpoint_count != None: 94 system.work_end_ckpt_count = options.work_end_checkpoint_count 95 if options.work_begin_exit_count != None: 96 system.work_begin_exit_count = options.work_begin_exit_count 97 if options.work_begin_checkpoint_count != None: 98 system.work_begin_ckpt_count = options.work_begin_checkpoint_count 99 if options.work_cpus_checkpoint_count != None: 100 system.work_cpus_ckpt_count = options.work_cpus_checkpoint_count 101 102def findCptDir(options, maxtick, cptdir, testsys): 103 """Figures out the directory from which the checkpointed state is read. 104 105 There are two different ways in which the directories holding checkpoints 106 can be named -- 107 1. cpt.<benchmark name>.<instruction count when the checkpoint was taken> 108 2. cpt.<some number, usually the tick value when the checkpoint was taken> 109 110 This function parses through the options to figure out which one of the 111 above should be used for selecting the checkpoint, and then figures out 112 the appropriate directory. 113 114 It also sets the value of the maximum tick value till which the simulation 115 will run. 116 """ 117 118 from os.path import isdir, exists 119 from os import listdir 120 import re 121 122 if not isdir(cptdir): 123 fatal("checkpoint dir %s does not exist!", cptdir) 124 125 if options.at_instruction or options.simpoint: 126 inst = options.checkpoint_restore 127 if options.simpoint: 128 # assume workload 0 has the simpoint 129 if testsys.cpu[0].workload[0].simpoint == 0: 130 fatal('Unable to find simpoint') 131 inst += int(testsys.cpu[0].workload[0].simpoint) 132 133 checkpoint_dir = joinpath(cptdir, "cpt.%s.%s" % (options.bench, inst)) 134 if not exists(checkpoint_dir): 135 fatal("Unable to find checkpoint directory %s", checkpoint_dir) 136 else: 137 dirs = listdir(cptdir) 138 expr = re.compile('cpt\.([0-9]*)') 139 cpts = [] 140 for dir in dirs: 141 match = expr.match(dir) 142 if match: 143 cpts.append(match.group(1)) 144 145 cpts.sort(lambda a,b: cmp(long(a), long(b))) 146 147 cpt_num = options.checkpoint_restore 148 if cpt_num > len(cpts): 149 fatal('Checkpoint %d not found', cpt_num) 150 151 maxtick = maxtick - int(cpts[cpt_num - 1]) 152 checkpoint_dir = joinpath(cptdir, "cpt.%s" % cpts[cpt_num - 1]) 153 154 return maxtick, checkpoint_dir 155 156def scriptCheckpoints(options, cptdir): 157 if options.at_instruction or options.simpoint: 158 checkpoint_inst = int(options.take_checkpoints) 159 160 # maintain correct offset if we restored from some instruction 161 if options.checkpoint_restore != None: 162 checkpoint_inst += options.checkpoint_restore 163 164 print "Creating checkpoint at inst:%d" % (checkpoint_inst) 165 exit_event = m5.simulate() 166 exit_cause = exit_event.getCause() 167 print "exit cause = %s" % exit_cause 168 169 # skip checkpoint instructions should they exist 170 while exit_cause == "checkpoint": 171 exit_event = m5.simulate() 172 exit_cause = exit_event.getCause() 173 174 if exit_cause == "a thread reached the max instruction count": 175 m5.checkpoint(joinpath(cptdir, "cpt.%s.%d" % \ 176 (options.bench, checkpoint_inst))) 177 print "Checkpoint written." 178 179 else: 180 when, period = options.take_checkpoints.split(",", 1) 181 when = int(when) 182 period = int(period) 183 num_checkpoints = 0 184 185 exit_event = m5.simulate(when) 186 exit_cause = exit_event.getCause() 187 while exit_cause == "checkpoint": 188 exit_event = m5.simulate(when - m5.curTick()) 189 exit_cause = exit_event.getCause() 190 191 if exit_cause == "simulate() limit reached": 192 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 193 num_checkpoints += 1 194 195 sim_ticks = when 196 max_checkpoints = options.max_checkpoints 197 198 while num_checkpoints < max_checkpoints and \ 199 exit_cause == "simulate() limit reached": 200 if (sim_ticks + period) > maxtick: 201 exit_event = m5.simulate(maxtick - sim_ticks) 202 exit_cause = exit_event.getCause() 203 break 204 else: 205 exit_event = m5.simulate(period) 206 exit_cause = exit_event.getCause() 207 sim_ticks += period 208 while exit_event.getCause() == "checkpoint": 209 exit_event = m5.simulate(sim_ticks - m5.curTick()) 210 if exit_event.getCause() == "simulate() limit reached": 211 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 212 num_checkpoints += 1 213 214 return exit_cause 215 216def benchCheckpoints(options, maxtick, cptdir): 217 exit_event = m5.simulate(maxtick) 218 exit_cause = exit_event.getCause() 219 220 num_checkpoints = 0 221 max_checkpoints = options.max_checkpoints 222 223 while exit_cause == "checkpoint": 224 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 225 num_checkpoints += 1 226 if num_checkpoints == max_checkpoints: 227 exit_cause = "maximum %d checkpoints dropped" % max_checkpoints 228 break 229 230 exit_event = m5.simulate(maxtick - m5.curTick()) 231 exit_cause = exit_event.getCause() 232 233 return exit_cause 234 235def repeatSwitch(testsys, repeat_switch_cpu_list, maxtick, switch_freq): 236 print "starting switch loop" 237 while True: 238 exit_event = m5.simulate(switch_freq) 239 exit_cause = exit_event.getCause() 240 241 if exit_cause != "simulate() limit reached": 242 return exit_cause 243 244 print "draining the system" 245 m5.doDrain(testsys) 246 m5.switchCpus(repeat_switch_cpu_list) 247 m5.resume(testsys) 248 249 tmp_cpu_list = [] 250 for old_cpu, new_cpu in repeat_switch_cpu_list: 251 tmp_cpu_list.append((new_cpu, old_cpu)) 252 repeat_switch_cpu_list = tmp_cpu_list 253 254 if (maxtick - m5.curTick()) <= switch_freq: 255 exit_event = m5.simulate(maxtick - m5.curTick()) 256 return exit_event.getCause() 257 258def run(options, root, testsys, cpu_class): 259 if options.maxtick: 260 maxtick = options.maxtick 261 elif options.maxtime: 262 simtime = m5.ticks.seconds(simtime) 263 print "simulating for: ", simtime 264 maxtick = simtime 265 else: 266 maxtick = m5.MaxTick 267 268 if options.checkpoint_dir: 269 cptdir = options.checkpoint_dir 270 elif m5.options.outdir: 271 cptdir = m5.options.outdir 272 else: 273 cptdir = getcwd() 274 275 if options.fast_forward and options.checkpoint_restore != None: 276 fatal("Can't specify both --fast-forward and --checkpoint-restore") 277 278 if options.standard_switch and not options.caches: 279 fatal("Must specify --caches when using --standard-switch") 280 281 if options.standard_switch and options.repeat_switch: 282 fatal("Can't specify both --standard-switch and --repeat-switch") 283 284 if options.repeat_switch and options.take_checkpoints: 285 fatal("Can't specify both --repeat-switch and --take-checkpoints") 286 287 np = options.num_cpus 288 switch_cpus = None 289 290 if options.prog_interval: 291 for i in xrange(np): 292 testsys.cpu[i].progress_interval = options.prog_interval 293 294 if options.maxinsts: 295 for i in xrange(np): 296 testsys.cpu[i].max_insts_any_thread = options.maxinsts 297 298 if cpu_class: 299 switch_cpus = [cpu_class(defer_registration=True, cpu_id=(i)) 300 for i in xrange(np)] 301 302 for i in xrange(np): 303 if options.fast_forward: 304 testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) 305 switch_cpus[i].system = testsys 306 switch_cpus[i].workload = testsys.cpu[i].workload 307 switch_cpus[i].clock = testsys.cpu[i].clock 308 # simulation period 309 if options.maxinsts: 310 switch_cpus[i].max_insts_any_thread = options.maxinsts 311 # Add checker cpu if selected 312 if options.checker: 313 switch_cpus[i].addCheckerCpu() 314 315 testsys.switch_cpus = switch_cpus 316 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 317 318 if options.repeat_switch: 319 if options.cpu_type == "arm_detailed": 320 if not options.caches: 321 print "O3 CPU must be used with caches" 322 sys.exit(1) 323 324 repeat_switch_cpus = [O3_ARM_v7a_3(defer_registration=True, \ 325 cpu_id=(i)) for i in xrange(np)] 326 elif options.cpu_type == "detailed": 327 if not options.caches: 328 print "O3 CPU must be used with caches" 329 sys.exit(1) 330 331 repeat_switch_cpus = [DerivO3CPU(defer_registration=True, \ 332 cpu_id=(i)) for i in xrange(np)] 333 elif options.cpu_type == "inorder": 334 print "inorder CPU switching not supported" 335 sys.exit(1) 336 elif options.cpu_type == "timing": 337 repeat_switch_cpus = [TimingSimpleCPU(defer_registration=True, \ 338 cpu_id=(i)) for i in xrange(np)] 339 else: 340 repeat_switch_cpus = [AtomicSimpleCPU(defer_registration=True, \ 341 cpu_id=(i)) for i in xrange(np)] 342 343 for i in xrange(np): 344 repeat_switch_cpus[i].system = testsys 345 repeat_switch_cpus[i].workload = testsys.cpu[i].workload 346 repeat_switch_cpus[i].clock = testsys.cpu[i].clock 347 348 if options.maxinsts: 349 repeat_switch_cpus[i].max_insts_any_thread = options.maxinsts 350 351 if options.checker: 352 repeat_switch_cpus[i].addCheckerCpu() 353 354 testsys.repeat_switch_cpus = repeat_switch_cpus 355 356 if cpu_class: 357 repeat_switch_cpu_list = [(switch_cpus[i], repeat_switch_cpus[i]) 358 for i in xrange(np)] 359 else: 360 repeat_switch_cpu_list = [(testsys.cpu[i], repeat_switch_cpus[i]) 361 for i in xrange(np)] 362 363 if options.standard_switch: 364 switch_cpus = [TimingSimpleCPU(defer_registration=True, cpu_id=(i)) 365 for i in xrange(np)] 366 switch_cpus_1 = [DerivO3CPU(defer_registration=True, cpu_id=(i)) 367 for i in xrange(np)] 368 369 for i in xrange(np): 370 switch_cpus[i].system = testsys 371 switch_cpus_1[i].system = testsys 372 switch_cpus[i].workload = testsys.cpu[i].workload 373 switch_cpus_1[i].workload = testsys.cpu[i].workload 374 switch_cpus[i].clock = testsys.cpu[i].clock 375 switch_cpus_1[i].clock = testsys.cpu[i].clock 376 377 # if restoring, make atomic cpu simulate only a few instructions 378 if options.checkpoint_restore != None: 379 testsys.cpu[i].max_insts_any_thread = 1 380 # Fast forward to specified location if we are not restoring 381 elif options.fast_forward: 382 testsys.cpu[i].max_insts_any_thread = int(options.fast_forward) 383 # Fast forward to a simpoint (warning: time consuming) 384 elif options.simpoint: 385 if testsys.cpu[i].workload[0].simpoint == 0: 386 fatal('simpoint not found') 387 testsys.cpu[i].max_insts_any_thread = \ 388 testsys.cpu[i].workload[0].simpoint 389 # No distance specified, just switch 390 else: 391 testsys.cpu[i].max_insts_any_thread = 1 392 393 # warmup period 394 if options.warmup_insts: 395 switch_cpus[i].max_insts_any_thread = options.warmup_insts 396 397 # simulation period 398 if options.maxinsts: 399 switch_cpus_1[i].max_insts_any_thread = options.maxinsts 400 401 # attach the checker cpu if selected 402 if options.checker: 403 switch_cpus[i].addCheckerCpu() 404 switch_cpus_1[i].addCheckerCpu() 405 406 testsys.switch_cpus = switch_cpus 407 testsys.switch_cpus_1 = switch_cpus_1 408 switch_cpu_list = [(testsys.cpu[i], switch_cpus[i]) for i in xrange(np)] 409 switch_cpu_list1 = [(switch_cpus[i], switch_cpus_1[i]) for i in xrange(np)] 410 411 # set the checkpoint in the cpu before m5.instantiate is called 412 if options.take_checkpoints != None and \ 413 (options.simpoint or options.at_instruction): 414 offset = int(options.take_checkpoints) 415 # Set an instruction break point 416 if options.simpoint: 417 for i in xrange(np): 418 if testsys.cpu[i].workload[0].simpoint == 0: 419 fatal('no simpoint for testsys.cpu[%d].workload[0]', i) 420 checkpoint_inst = int(testsys.cpu[i].workload[0].simpoint) + offset 421 testsys.cpu[i].max_insts_any_thread = checkpoint_inst 422 # used for output below 423 options.take_checkpoints = checkpoint_inst 424 else: 425 options.take_checkpoints = offset 426 # Set all test cpus with the right number of instructions 427 # for the upcoming simulation 428 for i in xrange(np): 429 testsys.cpu[i].max_insts_any_thread = offset 430 431 checkpoint_dir = None 432 if options.checkpoint_restore != None: 433 maxtick, checkpoint_dir = findCptDir(options, maxtick, cptdir, testsys) 434 m5.instantiate(checkpoint_dir) 435 436 if options.standard_switch or cpu_class: 437 if options.standard_switch: 438 print "Switch at instruction count:%s" % \ 439 str(testsys.cpu[0].max_insts_any_thread) 440 exit_event = m5.simulate() 441 elif cpu_class and options.fast_forward: 442 print "Switch at instruction count:%s" % \ 443 str(testsys.cpu[0].max_insts_any_thread) 444 exit_event = m5.simulate() 445 else: 446 print "Switch at curTick count:%s" % str(10000) 447 exit_event = m5.simulate(10000) 448 print "Switched CPUS @ tick %s" % (m5.curTick()) 449 450 # when you change to Timing (or Atomic), you halt the system 451 # given as argument. When you are finished with the system 452 # changes (including switchCpus), you must resume the system 453 # manually. You DON'T need to resume after just switching 454 # CPUs if you haven't changed anything on the system level. 455 456 m5.changeToTiming(testsys) 457 m5.switchCpus(switch_cpu_list) 458 m5.resume(testsys) 459 460 if options.standard_switch: 461 print "Switch at instruction count:%d" % \ 462 (testsys.switch_cpus[0].max_insts_any_thread) 463 464 #warmup instruction count may have already been set 465 if options.warmup_insts: 466 exit_event = m5.simulate() 467 else: 468 exit_event = m5.simulate(options.standard_switch) 469 print "Switching CPUS @ tick %s" % (m5.curTick()) 470 print "Simulation ends instruction count:%d" % \ 471 (testsys.switch_cpus_1[0].max_insts_any_thread) 472 m5.drain(testsys) 473 m5.switchCpus(switch_cpu_list1) 474 m5.resume(testsys) 475 476 # If we're taking and restoring checkpoints, use checkpoint_dir 477 # option only for finding the checkpoints to restore from. This 478 # lets us test checkpointing by restoring from one set of 479 # checkpoints, generating a second set, and then comparing them. 480 if options.take_checkpoints and options.checkpoint_restore: 481 if m5.options.outdir: 482 cptdir = m5.options.outdir 483 else: 484 cptdir = getcwd() 485 486 if options.take_checkpoints != None : 487 # Checkpoints being taken via the command line at <when> and at 488 # subsequent periods of <period>. Checkpoint instructions 489 # received from the benchmark running are ignored and skipped in 490 # favor of command line checkpoint instructions. 491 exit_cause = scriptCheckpoints(options, cptdir) 492 else: 493 if options.fast_forward: 494 m5.stats.reset() 495 print "**** REAL SIMULATION ****" 496 497 # If checkpoints are being taken, then the checkpoint instruction 498 # will occur in the benchmark code it self. 499 if options.repeat_switch and maxtick > options.repeat_switch: 500 exit_cause = repeatSwitch(testsys, repeat_switch_cpu_list, 501 maxtick, options.repeat_switch) 502 else: 503 exit_cause = benchCheckpoints(options, maxtick, cptdir) 504 505 print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause) 506 if options.checkpoint_at_end: 507 m5.checkpoint(joinpath(cptdir, "cpt.%d")) 508